<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>IaC on 엔지니어 생존기록</title><link>https://netscout.github.io/tags/IaC/</link><description>Recent content in IaC on 엔지니어 생존기록</description><generator>Hugo -- gohugo.io</generator><language>ko</language><lastBuildDate>Sat, 16 Dec 2023 14:09:14 +0900</lastBuildDate><atom:link href="https://netscout.github.io/tags/IaC/index.xml" rel="self" type="application/rss+xml"/><item><title>How to Terraform(7) - 코드 중복 최소화하기</title><link>https://netscout.github.io/posts/how-to-terraform-7-%EC%BD%94%EB%93%9C-%EC%A4%91%EB%B3%B5-%EC%B5%9C%EC%86%8C%ED%99%94%ED%95%98%EA%B8%B0/</link><pubDate>Sat, 16 Dec 2023 14:09:14 +0900</pubDate><guid>https://netscout.github.io/posts/how-to-terraform-7-%EC%BD%94%EB%93%9C-%EC%A4%91%EB%B3%B5-%EC%B5%9C%EC%86%8C%ED%99%94%ED%95%98%EA%B8%B0/</guid><description>이전 글에서 우리는 모듈을 활용하여 코드를 재사용하는 방법을 알아봤습니다. 그 결과 동일한 리소스에 대해서 코드 중복을 많이 줄일 수 있었죠. 그런데 여전히 중복되는 코드가 있었습니다. 각 리소스마다 프로바이더와 백엔드는 어쩔 수 없이 매번 작성해야 했습니다. 이번 …</description><content>&lt;h2 id="시리즈-목차">시리즈 목차&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="../How%20to%20Terraform%281%29%20-%20%ED%99%98%EA%B2%BD%20%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0%2FHow%20to%20Terraform%281%29%20-%20%ED%85%8C%EB%9D%BC%ED%8F%BC%EA%B3%BC%EC%9D%98%20%EA%B0%80%EB%B2%BC%EC%9A%B4%28%3F%29%20%EC%B2%AB%20%EB%A7%8C%EB%82%A8.md">How to Terraform(1) - 테라폼과의 가벼운(?) 첫 만남&lt;/a>&lt;/li>
&lt;li>&lt;a href="../How%20to%20Terraform%282%29%20-%20%EB%B3%80%EC%88%98%EC%99%80%20%EC%B6%9C%EB%A0%A5%2FHow%20to%20Terraform%282%29%20-%20%EB%B3%80%EC%88%98%EC%99%80%20%EC%B6%9C%EB%A0%A5.md">How to Terraform(2) - 변수와 출력&lt;/a>&lt;/li>
&lt;li>&lt;a href="../How%20to%20Terraform%283%29%20-%20%EC%83%81%ED%83%9C%20%EA%B4%80%EB%A6%AC%2FHow%20to%20Terraform%283%29%20-%20%EC%83%81%ED%83%9C%20%EA%B4%80%EB%A6%AC.md">How to Terraform(3) - 상태 관리&lt;/a>&lt;/li>
&lt;li>&lt;a href="../How%20to%20Terraform%284%29%20-%20%EC%83%81%ED%83%9C%EA%B4%80%EB%A6%AC%20%EA%B0%9C%EC%84%A0%ED%95%98%EA%B8%B0%2FHow%20to%20Terraform%284%29%20-%20%EC%83%81%ED%83%9C%EA%B4%80%EB%A6%AC%20%EA%B0%9C%EC%84%A0%ED%95%98%EA%B8%B0.md">How to Terraform(4) - 상태관리 개선하기&lt;/a>&lt;/li>
&lt;li>&lt;a href="../How%20to%20Terraform%285%29%20-%20%EB%AA%A8%EB%93%88%2FHow%20to%20Terraform%285%29%20-%20%EB%AA%A8%EB%93%88.md">How to Terraform(5) - 모듈&lt;/a>&lt;/li>
&lt;li>&lt;a href="../How%20to%20Terraform%286%29%20-%20%EB%AA%A8%EB%93%88%20%EB%B2%84%EC%A0%84%EA%B4%80%EB%A6%AC%2FHow%20to%20Terraform%286%29%20-%20%EB%AA%A8%EB%93%88%20%EB%B2%84%EC%A0%84%EA%B4%80%EB%A6%AC.md">How to Terraform(6) - 모듈 버전관리&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>이전 글에서 우리는 모듈을 활용하여 코드를 재사용하는 방법을 알아봤습니다. 그 결과 동일한 리소스에 대해서 코드 중복을 많이 줄일 수 있었죠. 그런데 여전히 중복되는 코드가 있었습니다. 각 리소스마다 프로바이더와 백엔드는 어쩔 수 없이 매번 작성해야 했습니다. 이번 글에서는 이런 중복을 최소화하는 방법을 알아보겠습니다.&lt;/p>
&lt;h2 id="terragrunt-설치하기">Terragrunt 설치하기&lt;/h2>
&lt;p>Terragrunt는 Terraform의 래퍼(wrapper)로 동작하며, Terraform 코드에서 중복되는 부분을 많이 줄일 수 있도록 도와줍니다. 래퍼로 동작하기 때문에 Terraform으로 실행가능한 init, plan, apply, destroy등의 명령은 그대로 사용할 수 있습니다. 우선 Terragrunt를 설치해볼까요?&lt;/p>
&lt;h3 id="homebrew로-설치하기">Homebrew로 설치하기&lt;/h3>
&lt;p>리눅스와 맥에서는 Homebrew를 사용해서 Terragrunt를 설치할 수 있습니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; brew install terragrunt
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt; terragrunt --version
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">terragrunt version 0.54.5
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>Terraform과 Terragrunt는 다음과 같이 alias로 등록하여 각각 tf, tg로 사용할 수 있습니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">alias&lt;/span> &lt;span class="nv">tf&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;terraform&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">alias&lt;/span> &lt;span class="nv">tg&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;terragrunt&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/blockquote>
&lt;h3 id="terragrunt-설정하기">Terragrunt 설정하기&lt;/h3>
&lt;p>먼저 이전 글에서 작업하던 폴더 구조를 다시 확인해볼까요?&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">terraform-live
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└── dev
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> └── ec2
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── service1
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> | ├── main.tf
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> | └── outputs.tf
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> └── service2
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── main.tf
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> └── outputs.tf
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>terraform-modules 리포지토리에 정의되어 있는 모듈을 참조하여 service1, service2를 정의했었습니다. 각 서비스의 main.tf 파일에는 다음과 같은 내용이 공통으로 존재했습니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-terraform" data-lang="terraform">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// AWS 프로바이더 설정
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">provider&lt;/span> &lt;span class="s2">&amp;#34;aws&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // 아시아 태평양(서울) 리전
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">region&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ap-northeast-2&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">...&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Terragrunt로 이 중복을 제거해보겠습니다.&lt;/p>
&lt;p>terraform-live/terragrunt.hcl 파일을 생성하고 다음과 같이 작성합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-hcl" data-lang="hcl">&lt;span class="line">&lt;span class="cl">&lt;span class="k">generate&lt;/span> &lt;span class="s2">&amp;#34;providers&amp;#34;&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;providers.tf&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> if_exists&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;overwrite_terragrunt&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> contents&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="err">&amp;lt;&amp;lt;&lt;/span>&lt;span class="k">EOF&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">provider&lt;/span> &lt;span class="s2">&amp;#34;aws&amp;#34;&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="err">//&lt;/span> &lt;span class="k">아시아&lt;/span> &lt;span class="k">태평양&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">서울&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">리전&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> region&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ap-northeast-2&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">EOF&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>그리고 service1의 모든 파일을 삭제하고 terragrunt.hcl 파일을 생성하고 다음과 같이 작성합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-hcl" data-lang="hcl">&lt;span class="line">&lt;span class="cl">&lt;span class="k">terraform&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> source&lt;/span> &lt;span class="o">=&lt;/span>&lt;span class="n"> &amp;#34;github.com/netscout/terraform-modules//modules/ec2?ref&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="k">v0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="m">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="m">1&lt;/span>&lt;span class="err">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">include&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">find_in_parent_folders&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">inputs&lt;/span> &lt;span class="o">=&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> env&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;dev&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> port&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">8080&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>현재까지의 내용을 정리해보자면, 폴더 구조는 다음과 같습니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">terraform-live
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── terragrunt.hcl
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└── dev
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> └── ec2
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── service1
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> | └── terragrunt.hcl
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> └── service2
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── main.tf
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> └── outputs.tf
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>그리고 Terragrunt의 plan 명령을 실행합니다. 참고로, Terragrunt는 plan 명령을 실행 할 때, init 명령을 자동으로 실행합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; &lt;span class="nb">cd&lt;/span> dev/ec2/service1
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt; tg plan
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Plan: &lt;span class="m">2&lt;/span> to add, &lt;span class="m">0&lt;/span> to change, &lt;span class="m">0&lt;/span> to destroy.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Changes to Outputs:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">public_ip&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>provider 설정이 없는데도 정상적으로 동작합니다. 그리고 outputs.tf가 없어졌는데도 출력값을 확인할 수 있습니다. 어떻게 가능한지 확인해볼까요? service1 폴더를 다시 확인해보면, &lt;code>.terragrunt-cache&lt;/code> 폴더가 생성되어 있습니다. 이 폴더에는 Terragrunt가 실행될 때 자동으로 생성된 Terraform 코드가 저장되어 있습니다. 폴더 구조를 볼까요?&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-gdscript3" data-lang="gdscript3">&lt;span class="line">&lt;span class="cl">&lt;span class="n">service1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">├──&lt;/span> &lt;span class="o">.&lt;/span>&lt;span class="n">terragrunt&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">cache&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">└──&lt;/span> &lt;span class="n">lIQuDV1aWBSG5nm4zKCulAdnsus&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">└──&lt;/span> &lt;span class="n">modules&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">└──&lt;/span> &lt;span class="n">ec2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">├──&lt;/span> &lt;span class="n">main&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">tf&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">├──&lt;/span> &lt;span class="n">outputs&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">tf&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">├──&lt;/span> &lt;span class="n">providers&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">tf&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">└──&lt;/span> &lt;span class="n">variables&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">tf&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">└──&lt;/span> &lt;span class="n">terragrunt&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">hcl&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>다른 파일들이 있긴 하지만, 핵심만 추리면 이렇습니다. 그러니까 모듈로 선언된 Terraform 코드가 그대로 다운로드 되어 있고, &lt;code>providers.tf&lt;/code> 파일이 새로 생성되어 있습니다. 이 파일의 내용을 보면 다음과 같습니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-terraform" data-lang="terraform">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Generated by Terragrunt. Sig: nIlQXj57tbuaRZEa
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">provider&lt;/span> &lt;span class="s2">&amp;#34;aws&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // 아시아 태평양(서울) 리전
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">region&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ap-northeast-2&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>provider 설정 없이도 plan 명령이 정상적으로 동작한 이유가 뭔지 이제 알 수 있죠? Terragrunt가 자동으로 생성해준 코드를 통해 provider 설정이 추가되었기 때문입니다. 다시 terraform-live/terragrunt.hcl 파일의 내용을 확인해볼까요?&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-hcl" data-lang="hcl">&lt;span class="line">&lt;span class="cl">&lt;span class="k">generate&lt;/span> &lt;span class="s2">&amp;#34;providers&amp;#34;&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;providers.tf&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> if_exists&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;overwrite_terragrunt&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> contents&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="err">&amp;lt;&amp;lt;&lt;/span>&lt;span class="k">EOF&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">provider&lt;/span> &lt;span class="s2">&amp;#34;aws&amp;#34;&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="err">//&lt;/span> &lt;span class="k">아시아&lt;/span> &lt;span class="k">태평양&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">서울&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">리전&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> region&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ap-northeast-2&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">EOF&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>providers.tf 파일을 생성하도록 설정하였고, 파일이 존재한다면 덮어쓰도록 했습니다. 그리고 파일의 내용은 provider 블록을 통해 aws 프로바이더를 정의해두었습니다. 그래서 &lt;code>tg plan&lt;/code>명령이 실행 될 때 Terragrunt가 providers.tf 파일을 생성하고, 이 파일을 통해 provider 설정이 추가되었던 것입니다.&lt;/p>
&lt;h3 id="좀-더-복잡한-경우">좀 더 복잡한 경우&lt;/h3>
&lt;p>겨우 이 몇 줄의 코드 때문에 Terragrunt를 써야 하는 거냐고 생각하실 수도 있지만 이 코드는 좀 더 길어질 수도 있습니다. 예를 들어 프로바이더 설정과 백엔드 설정을 추가한다면 어떻게 될까요?&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-hcl" data-lang="hcl">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># terragrunt가 각 모듈에 대해서 backend.tf를 생성한다.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">remote_state&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> backend&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;s3&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> generate&lt;/span> &lt;span class="o">=&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;backend.tf&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> if_exists&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;overwrite&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> }
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> config&lt;/span> &lt;span class="o">=&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> bucket&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;terraform-state-example-20231216&amp;#34;&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> # 상태 파일이 저장될 경로
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n"> key&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;${path_relative_to_include()}/terraform.tfstate&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> region&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ap-northeast-2&amp;#34;&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> # 상태 파일을 락으로 사용할 DynamoDB 테이블
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n"> dynamodb_table&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;terraform_locks&amp;#34;&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> # 상태 파일을 암호화
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n"> encrypt&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kt">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> }
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">generate&lt;/span> &lt;span class="s2">&amp;#34;providers&amp;#34;&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;providers.tf&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> if_exists&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;overwrite_terragrunt&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> contents&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="err">&amp;lt;&amp;lt;&lt;/span>&lt;span class="k">EOF&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">terraform&lt;/span> {&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> # 필요한 프로바이더 목록과 버전 정보
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">required_providers&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> aws&lt;/span> &lt;span class="o">=&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> source&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;hashicorp/aws&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> version&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;~&amp;gt; 5.0&amp;#34;&lt;/span>&lt;span class="c1"> # 5.0 이상 버전 사용
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> }
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> }
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">//&lt;/span> &lt;span class="k">AWS&lt;/span> &lt;span class="k">프로바이더&lt;/span> &lt;span class="k">설정&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">provider&lt;/span> &lt;span class="s2">&amp;#34;aws&amp;#34;&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="err">//&lt;/span> &lt;span class="k">아시아&lt;/span> &lt;span class="k">태평양&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">서울&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">리전&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> region&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ap-northeast-2&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">EOF&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>remote_state 블록에는 모든 Terraform 리소스에 적용될 backend 설정을 정의했습니다. config 속성의 내용은 기존의 backend 속성의 내용을 그대로 옮긴 것이며, generate 속성에는 backend.tf 파일을 생성하고 기존에 존재하는 경우 덮어쓰도록 설정했습니다. 자세히 보시면 config.key 속성이 기존과 다릅니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-hcl" data-lang="hcl">&lt;span class="line">&lt;span class="cl">&lt;span class="n">key&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;${path_relative_to_include()}/terraform.tfstate&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>즉, 현재 이 파일의 위치를 기준으로 해서 Terragrunt 명령이 실행되는 폴더의 경로를 가져오도록 했습니다. 만약 &lt;code>dev/ec2/service1&lt;/code> 폴더에서 &lt;code>tg plan&lt;/code> 명령을 실행한다면, key 값은 &lt;code>dev/ec2/service1/terraform.tfstate&lt;/code>가 됩니다. 매번 리소스를 정의할 때 마다 폴더 경로를 key 값으로 수정하지 않아도 알아서 해준다는 거죠!&lt;/p>
&lt;p>그리고 generate 블록에는 프로바이더 버전 정보를 추가했습니다. 이렇게 하면 모든 리소스에 대해서 프로바이더 버전을 일괄적으로 관리할 수 있습니다.&lt;/p>
&lt;h2 id="정리">정리&lt;/h2>
&lt;p>이제 Terraform을 통해 IaC를 구현하는 방법의 기초적인 내용은 모두 알아보았습니다. 익숙해지기 전에는 예전에 하던 것 처럼 수작업으로 일일이 리소스를 생성하는 게 훨씬 빠르다는 생각도 들게 됩니다. 하지만, 한 번 잘 설정해두면 속도가 빨라지는 것 뿐만 아니라 리소스의 변경을 추적할 수 있고, 리소스를 정리할 때도 커맨드 한 번으로 정리할 수 있게 됩니다. 지금까지 읽어주셔서 감사드리며, 도움이 되셨기를 바랍니다.&lt;/p>
&lt;h1 id="참고자료">참고자료&lt;/h1>
&lt;ul>
&lt;li>&lt;a href="https://www.terraformupandrunning.com/">Terraform Up and Running, 3rd Edition&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://terragrunt.gruntwork.io/">Terragrunt&lt;/a>&lt;/li>
&lt;/ul>
&lt;h1 id="license">License&lt;/h1>
&lt;p>&lt;a href="https://creativecommons.org/licenses/by-nc-nd/2.0/kr/">저작자표시-비영리-변경금지 2.0 대한민국 (CC BY-NC-ND 2.0 KR)&lt;/a>&lt;/p></content></item><item><title>How to Terraform(6) - 모듈 버전관리</title><link>https://netscout.github.io/posts/how-to-terraform-6-%EB%AA%A8%EB%93%88-%EB%B2%84%EC%A0%84%EA%B4%80%EB%A6%AC/</link><pubDate>Sat, 09 Dec 2023 14:04:13 +0900</pubDate><guid>https://netscout.github.io/posts/how-to-terraform-6-%EB%AA%A8%EB%93%88-%EB%B2%84%EC%A0%84%EA%B4%80%EB%A6%AC/</guid><description>이전 글에서는 모듈을 활용해서 반복되는 리소스를 재사용 가능한 형태로 정의하는 방법을 알아봤습니다. 그런데 모듈로 재사용성을 높이는 건 좋지만, 문제가 있긴 했습니다. 모듈을 업데이트해야 하는 경우, 이미 모듈을 사용해서 생성된 리소스 역시 업데이트되는 모듈의 영향을 …</description><content>&lt;h2 id="시리즈-목차">시리즈 목차&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="../How%20to%20Terraform%281%29%20-%20%ED%99%98%EA%B2%BD%20%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0%2FHow%20to%20Terraform%281%29%20-%20%ED%85%8C%EB%9D%BC%ED%8F%BC%EA%B3%BC%EC%9D%98%20%EA%B0%80%EB%B2%BC%EC%9A%B4%28%3F%29%20%EC%B2%AB%20%EB%A7%8C%EB%82%A8.md">How to Terraform(1) - 테라폼과의 가벼운(?) 첫 만남&lt;/a>&lt;/li>
&lt;li>&lt;a href="../How%20to%20Terraform%282%29%20-%20%EB%B3%80%EC%88%98%EC%99%80%20%EC%B6%9C%EB%A0%A5%2FHow%20to%20Terraform%282%29%20-%20%EB%B3%80%EC%88%98%EC%99%80%20%EC%B6%9C%EB%A0%A5.md">How to Terraform(2) - 변수와 출력&lt;/a>&lt;/li>
&lt;li>&lt;a href="../How%20to%20Terraform%283%29%20-%20%EC%83%81%ED%83%9C%20%EA%B4%80%EB%A6%AC%2FHow%20to%20Terraform%283%29%20-%20%EC%83%81%ED%83%9C%20%EA%B4%80%EB%A6%AC.md">How to Terraform(3) - 상태 관리&lt;/a>&lt;/li>
&lt;li>&lt;a href="../How%20to%20Terraform%284%29%20-%20%EC%83%81%ED%83%9C%EA%B4%80%EB%A6%AC%20%EA%B0%9C%EC%84%A0%ED%95%98%EA%B8%B0%2FHow%20to%20Terraform%284%29%20-%20%EC%83%81%ED%83%9C%EA%B4%80%EB%A6%AC%20%EA%B0%9C%EC%84%A0%ED%95%98%EA%B8%B0.md">How to Terraform(4) - 상태관리 개선하기&lt;/a>&lt;/li>
&lt;li>&lt;a href="../How%20to%20Terraform%285%29%20-%20%EB%AA%A8%EB%93%88%2FHow%20to%20Terraform%285%29%20-%20%EB%AA%A8%EB%93%88.md">How to Terraform(5) - 모듈&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>&lt;a href="../How%20to%20Terraform%285%29%20-%20%EB%AA%A8%EB%93%88%2FHow%20to%20Terraform%285%29%20-%20%EB%AA%A8%EB%93%88.md">이전 글&lt;/a>에서는 모듈을 활용해서 반복되는 리소스를 재사용 가능한 형태로 정의하는 방법을 알아봤습니다. 그런데 모듈로 재사용성을 높이는 건 좋지만, 문제가 있긴 했습니다. 모듈을 업데이트해야 하는 경우, 이미 모듈을 사용해서 생성된 리소스 역시 업데이트되는 모듈의 영향을 받게 된다는 점입니다. 모듈을 업데이트 하되 기존 리소스는 기존 모듈을 그대로 사용할 수 있도록 하위호환성을 도입하려면 어떻게 해야 할까요?&lt;/p>
&lt;h2 id="git-으로-모듈-버전-관리하기">Git 으로 모듈 버전 관리하기&lt;/h2>
&lt;p>여기서는 Git을 이용해서 모듈의 버전을 관리하고, 리소스도 각 모듈의 버전을 지정해서 참조하도록 해서 모듈과 리소스 간의 의존성을 관리하는 방법을 알아보겠습니다. 이렇게 하면 모듈을 업데이트할 때 기존 리소스에 영향을 주지 않으면서도 모듈을 업데이트할 수 있습니다. Git으로 모듈 버전을 관리하려면 2개의 Git 리포지토리가 필요합니다. 하나는 모듈을 관리하는 리포지토리, 또 하나는 모듈을 사용하여 리소스를 정의하는 리포지토리입니다. 우선 모듈을 관리하는 리포지토리를 만들어 보겠습니다.&lt;/p>
&lt;h2 id="모듈-리포지토리-만들기">모듈 리포지토리 만들기&lt;/h2>
&lt;p>모듈을 관리하는 리포지토리를 terraform-modules, 모듈을 사용해서 리소스를 관리하는 리포지토리를 terraform-live라고 가정하고 진행하겠습니다. 먼저 terraform-modules 리포지토리를 생성하고, &lt;a href="../How%20to%20Terraform%285%29%20-%20%EB%AA%A8%EB%93%88%2FHow%20to%20Terraform%285%29%20-%20%EB%AA%A8%EB%93%88.md">이전 글&lt;/a>에서 작성했던 EC2 인스턴스 모듈을 이 리포지토리에 옮깁니다. 폴더 구조는 다음과 같습니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-gdscript3" data-lang="gdscript3">&lt;span class="line">&lt;span class="cl">&lt;span class="n">terraform&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">modules&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">└──&lt;/span> &lt;span class="n">modules&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="err">└──&lt;/span> &lt;span class="n">ec2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="err">├──&lt;/span> &lt;span class="n">main&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">tf&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="err">├──&lt;/span> &lt;span class="n">outputs&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">tf&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="err">└──&lt;/span> &lt;span class="n">variables&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">tf&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>그리고 이 리포지토리를 GitHub에 푸시합니다. 그리고 다음 명령을 통해 모듈의 버전을 태그합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; git tag -a v0.0.1 -m &lt;span class="s2">&amp;#34;EC2 모듈 추가&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">~/src/terraform-modules main
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt; git push --follow-tags
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Enumerating objects: 1, &lt;span class="k">done&lt;/span>.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Counting objects: 100% &lt;span class="o">(&lt;/span>1/1&lt;span class="o">)&lt;/span>, &lt;span class="k">done&lt;/span>.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Writing objects: 100% &lt;span class="o">(&lt;/span>1/1&lt;span class="o">)&lt;/span>, &lt;span class="m">185&lt;/span> bytes &lt;span class="p">|&lt;/span> 185.00 KiB/s, &lt;span class="k">done&lt;/span>.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Total &lt;span class="m">1&lt;/span> &lt;span class="o">(&lt;/span>delta 0&lt;span class="o">)&lt;/span>, reused &lt;span class="m">0&lt;/span> &lt;span class="o">(&lt;/span>delta 0&lt;span class="o">)&lt;/span>, pack-reused &lt;span class="m">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">To https://github.com/netscout/terraform-modules.git
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> * &lt;span class="o">[&lt;/span>new tag&lt;span class="o">]&lt;/span> v0.0.1 -&amp;gt; v0.0.1
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>만약 이전 커밋에 지정된 태그를 삭제하고 싶다면 &lt;code>git tag -d v0.0.1&lt;/code>의 형태로 명령을 사용하고 새로운 커밋에 다시 태그를 붙이면 됩니다. 이미 태그를 푸시한 상태라면 &lt;code>git push --delete origin v0.0.1&lt;/code> 명령을 사용하면 됩니다.&lt;/p>&lt;/blockquote>
&lt;h2 id="모듈-리포지토리-참조하기">모듈 리포지토리 참조하기&lt;/h2>
&lt;p>EC2 모듈의 첫 버전을 v0.0.1로 태그 했습니다. 이제 리소스 리포지토리를 만들어서 이 모듈을 참조해보겠습니다. 우선 terraform-live라는 리포지토리를 생성하고, &lt;a href="../How%20to%20Terraform%285%29%20-%20%EB%AA%A8%EB%93%88%2FHow%20to%20Terraform%285%29%20-%20%EB%AA%A8%EB%93%88.md">이전 글&lt;/a>에서 작성했던 EC2 인스턴스 리소스를 이 리포지토리로 옮겨줍니다. 폴더 구조는 다음과 같습니다.&lt;/p>
&lt;p>terraform-live 폴더 안에 dev 폴더를 만들고, 그 안에 ec2 폴더를 만들고, service1 폴더를 만들어서 EC2 인스턴스 리소스를 옮겨줍니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">terraform-live
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└── dev
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> └── ec2
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> └── service1
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── main.tf
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> └── outputs.tf
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>이전 글에서 작성한 &lt;code>main.tf&lt;/code>는 로컬에 있는 모듈을 참조하도록 설정되어 있습니다. 로컬 대신에 Git의 모듈 리포지토리를 참조하도록 변경하겠습니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-terraform" data-lang="terraform">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// AWS 프로바이더 설정
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">provider&lt;/span> &lt;span class="s2">&amp;#34;aws&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // 아시아 태평양(서울) 리전
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">region&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ap-northeast-2&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 모듈 사용
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">module&lt;/span> &lt;span class="s2">&amp;#34;ec2&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> //source = &amp;#34;../../modules/ec2&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">source&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;github.com/netscout/terraform-modules//modules/ec2?ref=v0.0.1&amp;#34;&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // 모듈에 전달할 인자
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">env&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;dev&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">port&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">8080&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>source 속성을 자세히 보시면 중간에 &lt;code>//&lt;/code>가 들어가 있습니다. &lt;code>//&lt;/code>의 앞쪽에는 모듈이 저장된 git 리포지토리의 주소를, 그리고 뒤 쪽에는 모듈의 경로와 태그로 지정된 버전을 명시합니다. 모듈을 참조하기 위한 Terraform 코드 작성은 완료됐지만 아직 한 가지 더 검토해야 할 게 남아있습니다.&lt;/p>
&lt;h2 id="terraform-에게-git-리포지토리-접근-허용해주기">Terraform 에게 Git 리포지토리 접근 허용해주기&lt;/h2>
&lt;p>아마도 모듈 리포지토리는 private 리포지토리로 생성되었을 겁니다. 회사에서 작업하는 모듈에 대한 정의를 public 하게 공개할 수는 없기 때문이죠. 그렇다면 Terraform이 private 리포지토리에 접근할 수 있는 방법을 알려줘야 합니다.&lt;/p>
&lt;h3 id="ssh-키-생성-및-등록하기">SSH 키 생성 및 등록하기&lt;/h3>
&lt;p>Terraform이 모듈 리포지토리를 참조하기 위해서 SSH 키를 생성해서 github에 등록해야 합니다. 여기서는 ed25519 알고리즘을 사용해서 키를 생성하겠습니다. ed25519는 rsa보다 보안이 더 강화된 알고리즘으로, 최근에는 ed25519를 사용하는 것을 권장하고 있습니다. 다음 명령을 실행하여 키를 생성합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># &amp;#34;your_email@example.com&amp;#34; 대신에 github 이메일 주소를 입력하세요.&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt; ssh-keygen -t ed25519 -C &lt;span class="s2">&amp;#34;your_email@example.com&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># ssh-agent를 실행하여, 키를 등록한다.&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt; &lt;span class="nb">eval&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="k">$(&lt;/span>ssh-agent -s&lt;span class="k">)&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt; ssh-add ~/.ssh/id_ed25519
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>그리고 생성된 키의 내용을 클립보드에 복사한 후, 그 내용을 github에 등록합니다. 키의 내용을 클립보드에 복사하려면 ubuntu에서는 xclip을 사용하고,&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; cat ~/.ssh/id_ed25519.pub &lt;span class="p">|&lt;/span> xclip -selection clipboard
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>mac에서는 pbcopy를 사용하면 됩니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; cat ~/.ssh/id_ed25519.pub &lt;span class="p">|&lt;/span> pbcopy
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>이제 클립보드에 복사된 키를 github에 등록할 차례입니다. github에 접속하고 우측 상단의 아바타 버튼을 누르고 &lt;code>Settings&lt;/code> &amp;gt; &lt;code>SSH and GPG keys&lt;/code> &amp;gt; &lt;code>New SSH key&lt;/code>를 클릭합니다.&lt;/p>
&lt;p>&lt;code>Title&lt;/code>에는 키를 등록하는 컴퓨터의 이름을 적고, &lt;code>Key&lt;/code>에는 위에서 복사한 키를 붙여넣으면 완료입니다. 그러면 모듈을 잘 참조하는지 확인해볼까요?&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; &lt;span class="nb">cd&lt;/span> dev/ec2/service1
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt; tf init
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Initializing the backend...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Initializing modules...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Downloading git::https://github.com/netscout/terraform-modules.git?ref&lt;span class="o">=&lt;/span>v0.0.1 &lt;span class="k">for&lt;/span> ec2...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">- ec2 in .terraform/modules/ec2/modules/ec2
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Terraform has been successfully initialized!
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>정상적으로 잘 참조하고 있습니다! 이제 모듈을 업데이트 해볼까요?&lt;/p>
&lt;h3 id="모듈-업데이트하기">모듈 업데이트하기&lt;/h3>
&lt;p>모듈 리포지토리의 EC2 모듈을 업데이트 해보겠습니다. &lt;code>modules/ec2/main.tf&lt;/code> 파일을 열고, locals의 변수 정의를 수정하고 aws_security_group.sg 리소스에 ssh 접속을 위한 인바운트 규칙을 추가합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-terraform" data-lang="terraform">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 로컬 변수 정의
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="nx">locals&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // EC2 인스턴스에 할당할 태그
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">security_group_name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">${&lt;/span>&lt;span class="nb">var&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">name&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">-&lt;/span>&lt;span class="si">${&lt;/span>&lt;span class="nb">var&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">env&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_instance&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;ec2&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // ap-northeast-2 리전의 Ubuntu 20.04 AMI
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">ami&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">var&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">ami_id&lt;/span>&lt;span class="c1"> # 변수 ami_id 참조
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">instance_type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">var&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">instance_type&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">vpc_security_group_ids&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="nx">aws_security_group&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">sg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">id&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // 최초 인스턴스 생성 시에만 실행
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">user_data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;-EOF&lt;/span>&lt;span class="s">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> #!/bin/bash
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> echo &amp;#34;Hello, World&amp;#34; &amp;gt; index.html
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> nohup busybox httpd -f -p ${var.port} &amp;amp;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> &lt;/span>&lt;span class="o">EOF&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">tags&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">Name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;terraform-example&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_security_group&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;sg&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">local&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">security_group_name&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // 인바운드 규칙
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">ingress&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">from_port&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">var&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">port&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">to_port&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">var&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">port&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">protocol&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;tcp&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">cidr_blocks&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">var&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">cidr_blocks&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // ssh 접속을 위한 인바운드 규칙(새로 추가)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">ingress&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">from_port&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">22&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">to_port&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">22&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">protocol&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;tcp&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">cidr_blocks&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">var&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">cidr_blocks&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>다음으로 variables.tf 파일을 열고, name 변수를 추가합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-terraform" data-lang="terraform">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// name 변수 추가
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">variable&lt;/span> &lt;span class="s2">&amp;#34;name&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">string&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">variable&lt;/span> &lt;span class="s2">&amp;#34;env&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">string&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // 변수 값이 &amp;#34;dev&amp;#34;, &amp;#34;stg&amp;#34;, &amp;#34;prod&amp;#34; 중에 하나로 설정되야함
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">validation&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">condition&lt;/span> &lt;span class="o">=&lt;/span>&lt;span class="nb"> contains&lt;/span>&lt;span class="p">([&lt;/span>&lt;span class="s2">&amp;#34;dev&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;stg&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;prod&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="nb">var&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">env&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">error_message&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;env must be one of dev, stg, prod&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">variable&lt;/span> &lt;span class="s2">&amp;#34;ami_id&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">string&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">default&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ami-0c6e5afdd23291f73&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">variable&lt;/span> &lt;span class="s2">&amp;#34;instance_type&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">string&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">default&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;t2.micro&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">variable&lt;/span> &lt;span class="s2">&amp;#34;port&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">number&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">variable&lt;/span> &lt;span class="s2">&amp;#34;cidr_blocks&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">type&lt;/span> &lt;span class="o">=&lt;/span>&lt;span class="nb"> list&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">string&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">default&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;0.0.0.0/0&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>그리고 변경 내용을 커밋하고, 모듈 리포지토리를 푸시, 그리고 태그를 추가합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; git tag -a v0.0.2 -m &lt;span class="s2">&amp;#34;EC2에 SSH 인바운드 규칙 추가&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt; git push --follow-tags
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Enumerating objects: 1, &lt;span class="k">done&lt;/span>.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Counting objects: 100% &lt;span class="o">(&lt;/span>1/1&lt;span class="o">)&lt;/span>, &lt;span class="k">done&lt;/span>.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Writing objects: 100% &lt;span class="o">(&lt;/span>1/1&lt;span class="o">)&lt;/span>, &lt;span class="m">207&lt;/span> bytes &lt;span class="p">|&lt;/span> 207.00 KiB/s, &lt;span class="k">done&lt;/span>.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Total &lt;span class="m">1&lt;/span> &lt;span class="o">(&lt;/span>delta 0&lt;span class="o">)&lt;/span>, reused &lt;span class="m">0&lt;/span> &lt;span class="o">(&lt;/span>delta 0&lt;span class="o">)&lt;/span>, pack-reused &lt;span class="m">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">To https://github.com/netscout/terraform-modules.git
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> * &lt;span class="o">[&lt;/span>new tag&lt;span class="o">]&lt;/span> v0.0.2 -&amp;gt; v0.0.2
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="업데이트된-모듈-참조하기">업데이트된 모듈 참조하기&lt;/h3>
&lt;p>이제 업데이트된 모듈을 참조해보겠습니다. terraform-live/dev/ec2/service2 폴더를 추가하고, terraform-live/dev/ec2/service1 폴더에 작성된 main.tf, outputs.tf 파일을 복사해서 붙여넣습니다. 그리고 service2 폴더에 있는 main.tf 파일을 열고, 다음과 같이 모듈의 버전을 v0.0.2로 변경하고 name 변수에 인자를 할당합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-terraform" data-lang="terraform">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// AWS 프로바이더 설정
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">provider&lt;/span> &lt;span class="s2">&amp;#34;aws&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // 아시아 태평양(서울) 리전
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">region&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ap-northeast-2&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 모듈 사용
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">module&lt;/span> &lt;span class="s2">&amp;#34;ec2&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> //source = &amp;#34;../../modules/ec2&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">source&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;github.com/netscout/terraform-modules//modules/ec2?ref=v0.0.2&amp;#34;&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // 모듈에 전달할 인자
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;service2&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">env&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;dev&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">port&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">8080&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>init 명령을 실행해서 모듈 참조를 확인합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; &lt;span class="nb">cd&lt;/span> dev/ec2/service2
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt; tf init
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Initializing the backend...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Initializing modules...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Downloading git::https://github.com/netscout/terraform-modules.git?ref&lt;span class="o">=&lt;/span>v0.0.2 &lt;span class="k">for&lt;/span> ec2...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">- ec2 in .terraform/modules/ec2/modules/ec2
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>v0.0.2 버전의 모듈의 정상적으로 참조하고 있죠? v0.0.1을 참조하는 service1을 다시 확인해볼까요?&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 모듈 다시 업데이트 하기&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt; tf get -update
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt; tf plan
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>service1의 리소스 정의에는 모듈 v0.0.2에서 새로 추가된 name 변수가 지정되어 있지 않지만, name 변수가 아직 추가되지 않는 v0.0.1을 참조하고 있기 때문에 모듈의 버전 변경과 관계없이 잘 동작하는 걸 확인할 수 있습니다.&lt;/p>
&lt;h2 id="정리">정리&lt;/h2>
&lt;p>Git으로 모듈의 버전을 관리하면 모듈이 변경되더라도 이전에 생성된 리소스에는 영향을 주지 않고 안전하게 모듈을 업데이트할 수 있습니다. 점점 좋아지고 있죠? 그런데 여전히 중복은 남아있습니다. service1과 service2 에는 각각 provider에 대한 정의가 있습니다. 그리고 여기서는 backend를 사용하지 않았지만, S3같은 backend를 사용하면 그 설정 역시 각 리소스에 중복해서 들어가게 될 겁니다. 다음에는 이런 중복을 제거할 수 있는 방법을 알아보겠습니다.&lt;/p>
&lt;h1 id="참고자료">참고자료&lt;/h1>
&lt;ul>
&lt;li>&lt;a href="https://www.terraformupandrunning.com/">Terraform Up and Running, 3rd Edition&lt;/a>&lt;/li>
&lt;/ul>
&lt;h1 id="license">License&lt;/h1>
&lt;p>&lt;a href="https://creativecommons.org/licenses/by-nc-nd/2.0/kr/">저작자표시-비영리-변경금지 2.0 대한민국 (CC BY-NC-ND 2.0 KR)&lt;/a>&lt;/p></content></item><item><title>How to Terraform(5) - 모듈</title><link>https://netscout.github.io/posts/how-to-terraform-5-%EB%AA%A8%EB%93%88/</link><pubDate>Sat, 02 Dec 2023 13:47:25 +0900</pubDate><guid>https://netscout.github.io/posts/how-to-terraform-5-%EB%AA%A8%EB%93%88/</guid><description>Terraform을 사용하다보면 동일한 유형의 리소스를 여러번 생성해야 할 때가 있습니다. 예를 들면 개발, 스테이징, 운영 환경을 각각 분리된 EC2 인스턴스로 생성한다고 했을 때, 거의 동일한 EC2 인스턴스를 리소스로 정의하게 되겠죠. 지금까지는 동일한 코드를 …</description><content>&lt;h2 id="시리즈-목차">시리즈 목차&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="../How%20to%20Terraform%281%29%20-%20%ED%99%98%EA%B2%BD%20%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0%2FHow%20to%20Terraform%281%29%20-%20%ED%85%8C%EB%9D%BC%ED%8F%BC%EA%B3%BC%EC%9D%98%20%EA%B0%80%EB%B2%BC%EC%9A%B4%28%3F%29%20%EC%B2%AB%20%EB%A7%8C%EB%82%A8.md">How to Terraform(1) - 테라폼과의 가벼운(?) 첫 만남&lt;/a>&lt;/li>
&lt;li>&lt;a href="../How%20to%20Terraform%282%29%20-%20%EB%B3%80%EC%88%98%EC%99%80%20%EC%B6%9C%EB%A0%A5%2FHow%20to%20Terraform%282%29%20-%20%EB%B3%80%EC%88%98%EC%99%80%20%EC%B6%9C%EB%A0%A5.md">How to Terraform(2) - 변수와 출력&lt;/a>&lt;/li>
&lt;li>&lt;a href="../How%20to%20Terraform%283%29%20-%20%EC%83%81%ED%83%9C%20%EA%B4%80%EB%A6%AC%2FHow%20to%20Terraform%283%29%20-%20%EC%83%81%ED%83%9C%20%EA%B4%80%EB%A6%AC.md">How to Terraform(3) - 상태 관리&lt;/a>&lt;/li>
&lt;li>&lt;a href="../How%20to%20Terraform%284%29%20-%20%EC%83%81%ED%83%9C%EA%B4%80%EB%A6%AC%20%EA%B0%9C%EC%84%A0%ED%95%98%EA%B8%B0%2FHow%20to%20Terraform%284%29%20-%20%EC%83%81%ED%83%9C%EA%B4%80%EB%A6%AC%20%EA%B0%9C%EC%84%A0%ED%95%98%EA%B8%B0.md">How to Terraform(4) - 상태관리 개선하기&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>Terraform을 사용하다보면 동일한 유형의 리소스를 여러번 생성해야 할 때가 있습니다. 예를 들면 개발, 스테이징, 운영 환경을 각각 분리된 EC2 인스턴스로 생성한다고 했을 때, 거의 동일한 EC2 인스턴스를 리소스로 정의하게 되겠죠. 지금까지는 동일한 코드를 복사해서 붙여넣는 방식으로 각 리소스를 정의했습니다. 그런데 이렇게 하면 EC2 인스턴스의 설정이 복잡해지고, 개수가 많아질 수록 중복되는 코드의 양이 늘어나겠죠? 만약 기존에 정의된 EC2 인스턴스의 AMI를 변경해야 한다면, 모든 코드를 찾아서 일일이 변경해야만 할 겁니다. 그리고 이렇게 하다 보면 실수할 확률이 높아지겠죠?&lt;/p>
&lt;p>이렇게 동일한 리소스를 반복해서 사용해야 하는 경우, 리소스의 공통적인 내용을 재사용 가능한 형태로 정의해놓고 필요할 때마다 참조해서 사용하되, 바뀌는 부분만 따로 명시해줄 수 있으면 좋을 겁니다. 이런 재사용 가능한 형태로 정의된 리소스를 모듈이라고 합니다.&lt;/p>
&lt;h2 id="모듈이란">모듈이란?&lt;/h2>
&lt;p>Terraform 모듈은 동일한 유형의 리소스를 여러 번 생성할 때, 코드를 중복해서 작성하지 않도록 재사용 가능한 형태로 정의할 수 있습니다. 프로그래밍 언어에서는 함수나 클래스를 떠올려보시면 비슷합니다. 자 그럼 우선 모듈을 사용하기 전에 중복해서 리소스를 정의하는 코드를 먼저 확인해볼까요?&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-terraform" data-lang="terraform">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// AWS 프로바이더 설정
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">provider&lt;/span> &lt;span class="s2">&amp;#34;aws&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // 아시아 태평양(서울) 리전
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">region&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ap-northeast-2&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 개발 환경 EC2 인스턴스
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_instance&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;example_dev&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // ap-northeast-2 리전의 Ubuntu 20.04 AMI
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">ami&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ami-0c6e5afdd23291f73&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">instance_type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;t2.micro&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">vpc_security_group_ids&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="nx">aws_security_group&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">example_dev&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">id&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // 최초 인스턴스 생성 시에만 실행
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">user_data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;-EOF&lt;/span>&lt;span class="s">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> #!/bin/bash
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> echo &amp;#34;Hello, World&amp;#34; &amp;gt; index.html
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> nohup busybox httpd -f -p 8080 &amp;amp;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> &lt;/span>&lt;span class="o">EOF&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">tags&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">Name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;terraform-example&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_security_group&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;example_dev&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;terraform-example&amp;#34;&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // 인바운드 규칙
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">ingress&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">from_port&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">8080&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">to_port&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">8080&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">protocol&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;tcp&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">cidr_blocks&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;0.0.0.0/0&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 스테이징 환경 EC2 인스턴스
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_instance&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;example2_stg&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // ap-northeast-2 리전의 Ubuntu 20.04 AMI
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">ami&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ami-0c6e5afdd23291f73&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">instance_type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;t2.micro&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">vpc_security_group_ids&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="nx">aws_security_group&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">example_stg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">id&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // 최초 인스턴스 생성 시에만 실행
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">user_data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;-EOF&lt;/span>&lt;span class="s">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> #!/bin/bash
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> echo &amp;#34;Hello, World&amp;#34; &amp;gt; index.html
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> nohup busybox httpd -f -p 8080 &amp;amp;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> &lt;/span>&lt;span class="o">EOF&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">tags&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">Name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;terraform-example&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_security_group&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;example_stg&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;terraform-example-stg&amp;#34;&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // 인바운드 규칙
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">ingress&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">from_port&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">8080&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">to_port&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">8080&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">protocol&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;tcp&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">cidr_blocks&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;0.0.0.0/0&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>개발 환경과 스테이징 환경에서 동작할 EC2 인스턴스를 2개 정의해놓았습니다. 대부분의 코드가 중복되어 있죠? 간단한 코드지만 계속해서 늘어난다고 생각하면 좀 별로이긴합니다. 그러면 일단 중복을 제거할 수 있도록 모듈을 작성해보겠습니다. &lt;code>modules/ec2&lt;/code> 폴더를 만들고, 그 안에 &lt;code>ec2&lt;/code> 폴더를 만들어서 &lt;code>main.tf&lt;/code> 파일을 생성합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-terraform" data-lang="terraform">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 로컬 변수 정의
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="nx">locals&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // EC2 인스턴스에 할당할 태그
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">security_group_name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;terraform-example-&lt;/span>&lt;span class="si">${&lt;/span>&lt;span class="nb">var&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">env&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_instance&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;ec2&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // ap-northeast-2 리전의 Ubuntu 20.04 AMI
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">ami&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">var&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">ami_id&lt;/span>&lt;span class="c1"> # 변수 ami_id 참조
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">instance_type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">var&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">instance_type&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">vpc_security_group_ids&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="nx">aws_security_group&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">sg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">id&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // 최초 인스턴스 생성 시에만 실행
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">user_data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;-EOF&lt;/span>&lt;span class="s">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> #!/bin/bash
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> echo &amp;#34;Hello, World&amp;#34; &amp;gt; index.html
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> nohup busybox httpd -f -p ${var.port} &amp;amp;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> &lt;/span>&lt;span class="o">EOF&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">tags&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">Name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;terraform-example&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_security_group&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;sg&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">local&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">security_group_name&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // 인바운드 규칙
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">ingress&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">from_port&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">var&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">port&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">to_port&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">var&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">port&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">protocol&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;tcp&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">cidr_blocks&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">var&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">cidr_blocks&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>그리고 &lt;code>variables.tf&lt;/code> 파일을 생성해서 변수를 정의합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-terraform" data-lang="terraform">&lt;span class="line">&lt;span class="cl">&lt;span class="kr">variable&lt;/span> &lt;span class="s2">&amp;#34;env&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">string&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // 변수 값이 &amp;#34;dev&amp;#34;, &amp;#34;stg&amp;#34;, &amp;#34;prod&amp;#34; 중에 하나로 설정되야함
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">validation&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">condition&lt;/span> &lt;span class="o">=&lt;/span>&lt;span class="nb"> contains&lt;/span>&lt;span class="p">([&lt;/span>&lt;span class="s2">&amp;#34;dev&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;stg&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;prod&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="nb">var&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">env&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">error_message&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;env must be one of dev, stg, prod&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">variable&lt;/span> &lt;span class="s2">&amp;#34;ami_id&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">string&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">default&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ami-0c6e5afdd23291f73&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">variable&lt;/span> &lt;span class="s2">&amp;#34;instance_type&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">string&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">default&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;t2.micro&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">variable&lt;/span> &lt;span class="s2">&amp;#34;port&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">number&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">variable&lt;/span> &lt;span class="s2">&amp;#34;cidr_blocks&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">type&lt;/span> &lt;span class="o">=&lt;/span>&lt;span class="nb"> list&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">string&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">default&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;0.0.0.0/0&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>마지막으로 &lt;code>outputs.tf&lt;/code> 파일을 생성해서 EC2 인스턴스의 public IP 주소를 출력하도록 설정합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-terraform" data-lang="terraform">&lt;span class="line">&lt;span class="cl">&lt;span class="kr">output&lt;/span> &lt;span class="s2">&amp;#34;public_ip&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">value&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">aws_instance&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">ec2&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">public_ip&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>이제 모듈을 사용하는 코드를 작성해보겠습니다. &lt;code>dev/ec2&lt;/code> 폴더에 &lt;code>main.tf&lt;/code> 파일을 생성하고, 다음과 같이 작성합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-terraform" data-lang="terraform">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// AWS 프로바이더 설정
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">provider&lt;/span> &lt;span class="s2">&amp;#34;aws&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // 아시아 태평양(서울) 리전
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">region&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ap-northeast-2&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 모듈 사용
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">module&lt;/span> &lt;span class="s2">&amp;#34;ec2&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // 모듈의 소스 경로 지정
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">source&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;../../modules/ec2&amp;#34;&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // 모듈에 전달할 인자
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">env&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;dev&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">port&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">8080&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>모듈의 소스 경로를 상대 경로로 지정해주고, 모듈에 전달하고 싶은 변수를 지정해줍니다. 그리고 &lt;code>stg/ec2&lt;/code> 폴더에도 &lt;code>main.tf&lt;/code> 파일을 생성하고, 다음과 같이 작성합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-terraform" data-lang="terraform">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// AWS 프로바이더 설정
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">provider&lt;/span> &lt;span class="s2">&amp;#34;aws&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // 아시아 태평양(서울) 리전
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">region&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ap-northeast-2&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 모듈 사용
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">module&lt;/span> &lt;span class="s2">&amp;#34;ec2&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">source&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;../../modules/ec2&amp;#34;&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // 모듈에 전달할 인자
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">env&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;stg&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">port&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">8080&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>그리고 모듈의 output을 이용해서 EC2 인스턴스의 public IP 주소를 출력하도록 &lt;code>outputs.tf&lt;/code> 파일을 생성합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-terraform" data-lang="terraform">&lt;span class="line">&lt;span class="cl">&lt;span class="kr">output&lt;/span> &lt;span class="s2">&amp;#34;public_ip&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">value&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">module&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">ec2&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">public_ip&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>참고로 폴더 구조는 다음과 같습니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-gdscript3" data-lang="gdscript3">&lt;span class="line">&lt;span class="cl">&lt;span class="o">.&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">├──&lt;/span> &lt;span class="n">modules&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">└──&lt;/span> &lt;span class="n">ec2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">├──&lt;/span> &lt;span class="n">main&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">tf&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">└──&lt;/span> &lt;span class="n">variables&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">tf&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">|&lt;/span> &lt;span class="err">└──&lt;/span> &lt;span class="n">outputs&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">tf&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">├──&lt;/span> &lt;span class="n">dev&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">└──&lt;/span> &lt;span class="n">ec2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">└──&lt;/span> &lt;span class="n">main&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">tf&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">└──&lt;/span> &lt;span class="n">outputs&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">tf&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">└──&lt;/span> &lt;span class="n">stg&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="err">└──&lt;/span> &lt;span class="n">ec2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="err">└──&lt;/span> &lt;span class="n">main&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">tf&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="err">└──&lt;/span> &lt;span class="n">outputs&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">tf&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>우선 &lt;code>dev/ec2&lt;/code> 폴더에서 &lt;code>tf init&lt;/code> 명령을 실행합니다.&lt;/p>
&lt;blockquote>
&lt;p>&lt;code>terraform&lt;/code>이라고 매번 입력하는게 어려우니 .zshrc나 .bashrc에 다음과 같이 alias 설정을 해서 &lt;code>tf&lt;/code>로 사용하는 것도 방법입니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">alias tf=terraform
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/blockquote>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; &lt;span class="nb">cd&lt;/span> dev/ec2
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt; tf init
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Initializing the backend...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Initializing modules...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">- ec2 in ../../modules/ec2
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Initializing provider plugins...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>가장 먼저 지정된 모듈의 소스 경로에서 모듈을 가져와서 초기화 하는 걸 확인할 수 있죠? 그리고 &lt;code>tf plan&lt;/code> 명령을 실행해볼까요?&lt;/p>
&lt;blockquote>
&lt;p>참고로 모듈을 수정한 다음에 수정된 모듈을 반영하려면 &lt;code>tf get -update&lt;/code>명령을 실행해야 합니다.&lt;/p>&lt;/blockquote>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; tf plan
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Plan: &lt;span class="m">2&lt;/span> to add, &lt;span class="m">0&lt;/span> to change, &lt;span class="m">0&lt;/span> to destroy.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Changes to Outputs:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">public_ip&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt; tf apply
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Apply complete! Resources: &lt;span class="m">2&lt;/span> added, &lt;span class="m">0&lt;/span> changed, &lt;span class="m">0&lt;/span> destroyed.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Outputs:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">public_ip&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;...&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>모듈에 설정된 내용대로 인스턴스가 생성되었고, 모듈의 출력으로 설정된 public_ip도 출력을 확인할 수 있습니다. 이제 &lt;code>stg/ec2&lt;/code> 폴더에서도 동일한 명령을 실행해서 인스턴스를 추가로 생성할 수 있습니다.&lt;/p>
&lt;h2 id="정리">정리&lt;/h2>
&lt;p>모듈을 활용하면 코드의 중복을 줄일 수 있으며, 수작업으로 인해 실수를 방지할 수 있습니다. 하지만 모듈은 또 다른 단점을 가지고 있습니다. 모듈을 수정하게 되면 모듈을 참조하는 모든 리소스의 상태 관리에 영향을 미친다는 점입니다. 어떻게 하면 모듈을 업데이트하면서도 특정 리소스는 이전 모듈을 참조하고, 특정 리로스는 새로 업데이트된 모듈을 참조하도록 할 수 있을까요? 다음 시간에는 그 방법을 알아보겠습니다!&lt;/p>
&lt;h1 id="참고자료">참고자료&lt;/h1>
&lt;ul>
&lt;li>&lt;a href="https://www.terraformupandrunning.com/">Terraform Up and Running, 3rd Edition&lt;/a>&lt;/li>
&lt;/ul>
&lt;h1 id="license">License&lt;/h1>
&lt;p>&lt;a href="https://creativecommons.org/licenses/by-nc-nd/2.0/kr/">저작자표시-비영리-변경금지 2.0 대한민국 (CC BY-NC-ND 2.0 KR)&lt;/a>&lt;/p></content></item><item><title>How to Terraform(4) - 상태관리 개선하기</title><link>https://netscout.github.io/posts/how-to-terraform-4-%EC%83%81%ED%83%9C%EA%B4%80%EB%A6%AC-%EA%B0%9C%EC%84%A0%ED%95%98%EA%B8%B0/</link><pubDate>Sat, 25 Nov 2023 14:14:54 +0900</pubDate><guid>https://netscout.github.io/posts/how-to-terraform-4-%EC%83%81%ED%83%9C%EA%B4%80%EB%A6%AC-%EA%B0%9C%EC%84%A0%ED%95%98%EA%B8%B0/</guid><description>이전 글에서는 Terraform의 상태에 대해 알아보았고, 로컬 파일로 관리할 때의 단점을 해결하기 위해서 상태를 S3에 저장하는 방법을 알아보았습니다. 하지만 여전히 문제가 남아있었습니다. 그 문제가 뭐였는지 알아볼까요?</description><content>&lt;h2 id="시리즈-목차">시리즈 목차&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="../How%20to%20Terraform%281%29%20-%20%ED%99%98%EA%B2%BD%20%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0%2FHow%20to%20Terraform%281%29%20-%20%ED%85%8C%EB%9D%BC%ED%8F%BC%EA%B3%BC%EC%9D%98%20%EA%B0%80%EB%B2%BC%EC%9A%B4%28%3F%29%20%EC%B2%AB%20%EB%A7%8C%EB%82%A8.md">How to Terraform(1) - 테라폼과의 가벼운(?) 첫 만남&lt;/a>&lt;/li>
&lt;li>&lt;a href="../How%20to%20Terraform%282%29%20-%20%EB%B3%80%EC%88%98%EC%99%80%20%EC%B6%9C%EB%A0%A5%2FHow%20to%20Terraform%282%29%20-%20%EB%B3%80%EC%88%98%EC%99%80%20%EC%B6%9C%EB%A0%A5.md">How to Terraform(2) - 변수와 출력&lt;/a>&lt;/li>
&lt;li>&lt;a href="../How%20to%20Terraform%283%29%20-%20%EC%83%81%ED%83%9C%20%EA%B4%80%EB%A6%AC%2FHow%20to%20Terraform%283%29%20-%20%EC%83%81%ED%83%9C%20%EA%B4%80%EB%A6%AC.md">How to Terraform(3) - 상태 관리&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>&lt;a href="../How%20to%20Terraform%283%29%20-%20%EC%83%81%ED%83%9C%20%EA%B4%80%EB%A6%AC%2FHow%20to%20Terraform%283%29%20-%20%EC%83%81%ED%83%9C%20%EA%B4%80%EB%A6%AC.md">이전 글&lt;/a>에서는 Terraform의 상태에 대해 알아보았고, 로컬 파일로 관리할 때의 단점을 해결하기 위해서 상태를 S3에 저장하는 방법을 알아보았습니다. 하지만 여전히 문제가 남아있었습니다. 그 문제가 뭐였는지 알아볼까요?&lt;/p>
&lt;h2 id="현재-상태관리의-문제점">현재 상태관리의 문제점&lt;/h2>
&lt;p>이전 글에서는 모든 테라폼 리소스가 한 개의 상태 파일로 관리되고 있었습니다. 예시를 위해서 새로 폴더를 만들고 다음 코드를 &lt;code>main.tf&lt;/code>에 작성합니다.&lt;/p>
&lt;blockquote>
&lt;p>일단 예시를 위해서 S3를 사용하지 않고 로컬 파일을 사용합니다.&lt;/p>&lt;/blockquote>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-terraform" data-lang="terraform">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// AWS 프로바이더 설정
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">provider&lt;/span> &lt;span class="s2">&amp;#34;aws&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // 아시아 태평양(서울) 리전
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">region&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ap-northeast-2&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_instance&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;example&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // ap-northeast-2 리전의 Ubuntu 20.04 AMI
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">ami&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ami-0c6e5afdd23291f73&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">instance_type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;t2.micro&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>그리고 init, plan, apply 명령을 실행합니다.&lt;/p>
&lt;blockquote>
&lt;p>&lt;code>terraform&lt;/code>이라고 매번 입력하는게 어려우니 .zshrc나 .bashrc에 다음과 같이 alias 설정을 해서 &lt;code>tf&lt;/code>로 사용하는 것도 방법입니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">alias tf=terraform
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/blockquote>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; tf init
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Terraform has been successfully initialized!
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt; tf plan
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Plan: &lt;span class="m">1&lt;/span> to add, &lt;span class="m">0&lt;/span> to change, &lt;span class="m">0&lt;/span> to destroy.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt; tf apply
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Apply complete! Resources: &lt;span class="m">1&lt;/span> added, &lt;span class="m">0&lt;/span> changed, &lt;span class="m">0&lt;/span> destroyed.
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>자 여기까지는 뭐 기존과 다를 게 하나도 없습니다. 여기에 두번째 EC2 인스턴스를 추가해볼까요?&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-terraform" data-lang="terraform">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">//main.tf 기존 코드...
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_instance&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;example2&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // ap-northeast-2 리전의 Ubuntu 20.04 AMI
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">ami&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ami-0c6e5afdd23291f73&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">instance_type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;t2.micro&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>그리고 다시 plan을 실행해봅니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; tf plan
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">aws_instance.example: Refreshing state... &lt;span class="o">[&lt;/span>&lt;span class="nv">id&lt;/span>&lt;span class="o">=&lt;/span>i-00c12ab694ff80dfa&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Plan: &lt;span class="m">1&lt;/span> to add, &lt;span class="m">0&lt;/span> to change, &lt;span class="m">0&lt;/span> to destroy.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>두번째 EC2 인스턴스를 추가할 때 우리의 관심사는 &lt;code>aws_instance.example2&lt;/code> 리소스 입니다. 하지만 plan 명령을 실행하자 이미 추가된 리소스인 &lt;code>aws_instance.example&lt;/code>에 대한 검사가 먼저 진행되었죠? &lt;code>aws_instance.example&lt;/code> 리소스가 &lt;code>aws_instance.example2&lt;/code> 리소스와 하나의 상태 파일로 관리되고 있기 때문에 Terraform으로서는 어쩔 수 없이 상태 파일의 내용과 테라폼 코드의 리소스를 모두 비교할 수 밖에 없는 거죠. EC2 인스턴스 몇 개는 금방 끝나니까 별 문제가 아닐 수 있지만, 이런 식으로 리소스가 계속 늘어나다 보면 어느새 plan 한번 실행하는데 몇 분이 걸리는 일도 발생할 수 있습니다.&lt;/p>
&lt;p>그리고 좀 더 복잡한 문제가 생기는 경우도 있습니다. 만약 반드시 변수로 입력받아야 하는 값이 있다고 생각해볼까요? 테라폼 코드에 작성된 상당수의 리소스가 환경변수 등을 통해서 변수를 입력받아야 한다면 어떨까요? 내가 관심 있는 리소스 하나 작업하기 위해서 모든 변수 값을 제대로 설정해야만 하는 문제가 발생합니다. 정리해보자면,&lt;/p>
&lt;ul>
&lt;li>여러 리소스가 하나의 상태 파일로 관리되기 때문에, 리소스가 추가됨에 따라 상태 파일이 점점 거대해진다.&lt;/li>
&lt;li>따라서 새로 추가하는 리소스에 대한 plan, apply 명령에도 기존에 관리되고 있는 모든 리소스에 대한 검사가 진행되므로 시간이 점점 더 오래걸린다.&lt;/li>
&lt;li>모든 리소스가 하나의 상태 파일로 관리되면 다른 사람이 일부 리소스를 변경했을 때 변경된 상태 값 역시 공유된다. 만약 다른 사람이 변경한 테라폼 코드를 업데이트 받지 않은 상태에서 내 작업을 진행하면 리소스의 상태를 다시 변경 이전 상태로 되돌리는 등의 예상치 못한 오류가 발생할 수 있다.&lt;/li>
&lt;/ul>
&lt;p>이러한 문제를 해결하기 위해서는 각 리소스에 대한 상태를 최대한 작게 나눠서 관리하는 게 좋을 것 같습니다. 나눠서 관리한다는 게 생각보다 별 거 없습니다. 그냥 폴더를 쪼개면 됩니다.&lt;/p>
&lt;h2 id="폴더로-나눠서-관리하기">폴더로 나눠서 관리하기&lt;/h2>
&lt;p>S3 백엔드와 EC2 인스턴스 2개를 만드는 상황을 가정하면 폴더는 대강 이렇게 나눌 수 있습니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── global
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── s3
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── main.tf
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── dev
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── ec2
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── example
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── main.tf
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── example2
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── main.tf
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>우선 &lt;code>global&lt;/code> 폴더에는 S3 백엔드를 생성하는 코드를 작성합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-terraform" data-lang="terraform">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// AWS 프로바이더 설정
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">provider&lt;/span> &lt;span class="s2">&amp;#34;aws&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // 아시아 태평양(서울) 리전
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">region&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ap-northeast-2&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># S3 버킷 생성
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_s3_bucket&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;terraform_state&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">bucket&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;terraform-state-example-20231125&amp;#34;&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> # 실수로 버킷이 삭제되지 않도록 하려면 아래 주석을 해제하세요.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> # lifecycle {
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> # prevent_destroy = true
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> # }
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 버킷 버전 관리 활성화(상태 파일의 히스토리를 관리하기 위함)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_s3_bucket_versioning&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;enabled&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">bucket&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">aws_s3_bucket&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">terraform_state&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">id&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">versioning_configuration&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">status&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;Enabled&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># S3에 저장될 때 암호화 하도록 설정
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_s3_bucket_server_side_encryption_configuration&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;default&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">bucket&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">aws_s3_bucket&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">terraform_state&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">id&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">rule&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">apply_server_side_encryption_by_default&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">sse_algorithm&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;AES256&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 모든 public access를 차단(실수로 버킷이 공개되지 않도록 하기 위함)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_s3_bucket_public_access_block&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;public_access&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">bucket&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">aws_s3_bucket&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">terraform_state&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">id&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">block_public_acls&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">block_public_policy&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">ignore_public_acls&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">restrict_public_buckets&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 여러 사람이 동시에 상태 파일을 수정하지 못하도록 DynamoDB를 사용한 락 설정
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_dynamodb_table&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;terraform_locks&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;terraform_locks&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">billing_mode&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;PAY_PER_REQUEST&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">hash_key&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;LockID&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">attribute&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;LockID&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;S&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>그리고 우선 init, plan, apply 를 실행해서 백엔드 설정을 위한 S3 버킷을 생성합니다.&lt;/p>
&lt;blockquote>
&lt;p>참고로, VS Code에서는 cd 명령 대신에 폴더에 우클릭하고 &lt;code>통합 터미널에서 열기&lt;/code>를 선택하면 해당 폴더로 터미널이 이동합니다.&lt;/p>
&lt;p align="center">&lt;img src="./01.png">&lt;/p>&lt;/blockquote>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; &lt;span class="nb">cd&lt;/span> global/s3
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt; tf init
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Terraform has been successfully initialized!
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt; tf plan
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Plan: &lt;span class="m">5&lt;/span> to add, &lt;span class="m">0&lt;/span> to change, &lt;span class="m">0&lt;/span> to destroy.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt; tf apply
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Apply complete! Resources: &lt;span class="m">5&lt;/span> added, &lt;span class="m">0&lt;/span> changed, &lt;span class="m">0&lt;/span> destroyed.
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>그리고 생성된 S3에 현재 생성된 리소스의 상태를 저장하기 위해서 &lt;code>main.tf&lt;/code>상단에 다음 코드를 추가합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-terraform" data-lang="terraform">&lt;span class="line">&lt;span class="cl">&lt;span class="nx">terraform&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> # 필요한 프로바이더 목록과 버전 정보
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">required_providers&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">aws&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">source&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;hashicorp/aws&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">version&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;~&amp;gt; 5.0&amp;#34;&lt;/span>&lt;span class="c1"> # 5.0 이상 버전 사용
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> # 상태 파일을 S3에 저장하도록 설정
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">backend&lt;/span> &lt;span class="s2">&amp;#34;s3&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">bucket&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;terraform-state-example-20231125&amp;#34;&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> # 상태 파일이 저장될 경로
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">key&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;global/s3/terraform.tfstate&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">region&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ap-northeast-2&amp;#34;&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> # 상태 파일을 락으로 사용할 DynamoDB 테이블
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">dynamodb_table&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;terraform_locks&amp;#34;&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> # 상태 파일을 암호화
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">encrypt&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// main.tf 기존 코드...
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>여기서 주목해야 할 점은 상태 파일이 저장될 경로를 리소스 파일이 정의된 폴더 경로와 일치하도록 설정했다는 점입니다. 이렇게 하면 리로스와 상태 파일의 경로가 일치하므로 상태 파일을 덮어쓴다던지 하는 오류를 피할 수 있습니다. 이제 init 명령을 통해 벡엔드를 설정하겠습니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; tf init
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Initializing the backend...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Do you want to copy existing state to the new backend?
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> Pre-existing state was found &lt;span class="k">while&lt;/span> migrating the previous &lt;span class="s2">&amp;#34;local&amp;#34;&lt;/span> backend to the
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> newly configured &lt;span class="s2">&amp;#34;s3&amp;#34;&lt;/span> backend. No existing state was found in the newly
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> configured &lt;span class="s2">&amp;#34;s3&amp;#34;&lt;/span> backend. Do you want to copy this state to the new &lt;span class="s2">&amp;#34;s3&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> backend? Enter &lt;span class="s2">&amp;#34;yes&amp;#34;&lt;/span> to copy and &lt;span class="s2">&amp;#34;no&amp;#34;&lt;/span> to start with an empty state.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> Enter a value: yes
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Successfully configured the backend &lt;span class="s2">&amp;#34;s3&amp;#34;&lt;/span>! Terraform will automatically
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">use this backend unless the backend configuration changes.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>콘솔에서 S3를 확인해보면,&lt;/p>
&lt;p align="center">&lt;img src="./02.png">&lt;/p>
&lt;p>지정된 경로에 상태 파일이 생성된 것을 확인할 수 있습니다.&lt;/p>
&lt;blockquote>
&lt;p>이렇게 리소스 별로 상태를 관리할 때 아무래도 자주 관리하지 않는 리소스가 생기기 마련입니다. 시간이 한참 지나서 다시 관리를 해야 할 때, 이전에 사용하던 프로바이더의 버전과 현재 버전이 차이가 많이 날 수도 있겠죠. 그럴 때 기존에 작성한 코드가 제대로 동작하지 않는 문제가 생길 수도 있으므로 프로바이더의 버전을 명시하는 것도 좋은 방법입니다!&lt;/p>&lt;/blockquote>
&lt;p>이제 &lt;code>dev/ec2/example/main.tf&lt;/code> 파일을 생성하고 다음 코드를 작성합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-terraform" data-lang="terraform">&lt;span class="line">&lt;span class="cl">&lt;span class="nx">terraform&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> # 필요한 프로바이더 목록과 버전 정보
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">required_providers&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">aws&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">source&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;hashicorp/aws&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">version&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;~&amp;gt; 5.0&amp;#34;&lt;/span>&lt;span class="c1"> # 5.0 이상 버전 사용
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> # 상태 파일을 S3에 저장하도록 설정
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">backend&lt;/span> &lt;span class="s2">&amp;#34;s3&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">bucket&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;terraform-state-example-20231125&amp;#34;&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> # 상태 파일이 저장될 경로
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">key&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;dev/ec2/example/terraform.tfstate&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">region&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ap-northeast-2&amp;#34;&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> # 상태 파일을 락으로 사용할 DynamoDB 테이블
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">dynamodb_table&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;terraform_locks&amp;#34;&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> # 상태 파일을 암호화
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">encrypt&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// AWS 프로바이더 설정
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">provider&lt;/span> &lt;span class="s2">&amp;#34;aws&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // 아시아 태평양(서울) 리전
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">region&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ap-northeast-2&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_instance&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;example&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // ap-northeast-2 리전의 Ubuntu 20.04 AMI
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">ami&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ami-0c6e5afdd23291f73&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">instance_type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;t2.micro&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>그리고 역시 &lt;code>dev/ec2/example&lt;/code> 폴더에서 init, plan, apply 명령을 실행합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; &lt;span class="nb">cd&lt;/span> dev/ec2/example
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt; tf init
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Terraform has been successfully initialized!
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt; tf plan
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Plan: &lt;span class="m">1&lt;/span> to add, &lt;span class="m">0&lt;/span> to change, &lt;span class="m">0&lt;/span> to destroy.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt; tf apply
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Apply complete! Resources: &lt;span class="m">1&lt;/span> added, &lt;span class="m">0&lt;/span> changed, &lt;span class="m">0&lt;/span> destroyed.
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>그리고 &lt;code>dev/ec2/example2/main.tf&lt;/code> 파일을 생성하고 동일한 과정으로 EC2 인스턴스를 추가할 수 있습니다.&lt;/p>
&lt;h2 id="정리">정리&lt;/h2>
&lt;p>이제 우리는 각 리소스에 대해 개별적으로 상태 관리를 진행할 수 있습니다. 리소스는 각각의 상태를 가지므로 다른 리소스에 대해 신경쓰지 않고 관리할 수 있고, 특히 새로운 리소스를 추가할 때 역시 기존 리소스의 상태에 대해서 전혀 신경쓰지 않아도 됩니다. 다만 역시나 한 가지 마음에 걸리는 게 있습니다. EC2 인스턴스를 작성 할 때 저희는 동일한 코드를 복붙해서 새로운 인스턴스를 생성했었죠. 사실 지금은 EC2에 별다른 설정을 하지 않아서 뭐 복잡할 건 없습니다만, VPC등의 설정에 따라서는 EC2도 매우 복잡해질 수 있고 저희가 Terraform으로 EC2만 관리할 것도 아니기 때문에 이 부분은 더 나은 방법이 필요해보입니다. 다음 글에서는 모듈을 통해 중복을 줄이는 방법을 알아보겠습니다.&lt;/p>
&lt;h1 id="참고자료">참고자료&lt;/h1>
&lt;ul>
&lt;li>&lt;a href="https://www.terraformupandrunning.com/">Terraform Up and Running, 3rd Edition&lt;/a>&lt;/li>
&lt;/ul>
&lt;h1 id="license">License&lt;/h1>
&lt;p>&lt;a href="https://creativecommons.org/licenses/by-nc-nd/2.0/kr/">저작자표시-비영리-변경금지 2.0 대한민국 (CC BY-NC-ND 2.0 KR)&lt;/a>&lt;/p></content></item><item><title>How to Terraform(3) - 상태 관리</title><link>https://netscout.github.io/posts/how-to-terraform-3-%EC%83%81%ED%83%9C-%EA%B4%80%EB%A6%AC/</link><pubDate>Sat, 18 Nov 2023 15:28:03 +0900</pubDate><guid>https://netscout.github.io/posts/how-to-terraform-3-%EC%83%81%ED%83%9C-%EA%B4%80%EB%A6%AC/</guid><description>상태가 뭔지 설명하기 전에 간단한 실험을 해보죠! 새로운 폴더를 생성하고 아래 코드를 main.tf에 추가하겠습니다.</description><content>&lt;h2 id="시리즈-목차">시리즈 목차&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="../How%20to%20Terraform%281%29%20-%20%ED%99%98%EA%B2%BD%20%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0%2FHow%20to%20Terraform%281%29%20-%20%ED%85%8C%EB%9D%BC%ED%8F%BC%EA%B3%BC%EC%9D%98%20%EA%B0%80%EB%B2%BC%EC%9A%B4%28%3F%29%20%EC%B2%AB%20%EB%A7%8C%EB%82%A8.md">How to Terraform(1) - 테라폼과의 가벼운(?) 첫 만남&lt;/a>&lt;/li>
&lt;li>&lt;a href="../How%20to%20Terraform%282%29%20-%20%EB%B3%80%EC%88%98%EC%99%80%20%EC%B6%9C%EB%A0%A5%2FHow%20to%20Terraform%282%29%20-%20%EB%B3%80%EC%88%98%EC%99%80%20%EC%B6%9C%EB%A0%A5.md">How to Terraform(2) - 변수와 출력&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="상태라니-무슨-상태">상태라니 무슨 상태?&lt;/h2>
&lt;p>상태가 뭔지 설명하기 전에 간단한 실험을 해보죠! 새로운 폴더를 생성하고 아래 코드를 &lt;code>main.tf&lt;/code>에 추가하겠습니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-terraform" data-lang="terraform">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// AWS 프로바이더 설정
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">provider&lt;/span> &lt;span class="s2">&amp;#34;aws&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // 아시아 태평양(서울) 리전
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">region&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ap-northeast-2&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>그리고 &lt;code>tf init&lt;/code>을 실행해봅시다.&lt;/p>
&lt;blockquote>
&lt;p>&lt;code>terraform&lt;/code>이라고 매번 입력하는게 어려우니 .zshrc나 .bashrc에 다음과 같이 alias 설정을 해서 &lt;code>tf&lt;/code>로 사용하는 것도 방법입니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">alias tf=terraform
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/blockquote>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; tf init
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Initializing the backend...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Initializing provider plugins...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Terraform has been successfully initialized!
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>맨 처음에 &lt;code>backend&lt;/code>라는 표현이 등장합니다. 이게 웹 어플리케이션도 아닌데 backend는 뭘 말하는 걸까요~? 일단은 궁금증을 뒤로 하고 &lt;code>tf plan&lt;/code>을 실행해봅시다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; tf plan
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">No changes. Your infrastructure matches the configuration.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Terraform has compared your real infrastructure against your configuration and found no differences, so no changes
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">are needed.
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>아무 것도 바꿀 게 없다고 합니다. 리소스를 하나도 선언하지 않았으니 당연하겠죠. 그런데 여기서 &lt;code>tf apply&lt;/code>를 실행해볼까요?&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; tf apply
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">No changes. Your infrastructure matches the configuration.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Terraform has compared your real infrastructure against your configuration and found no differences, so no changes
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">are needed.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Apply complete! Resources: &lt;span class="m">0&lt;/span> added, &lt;span class="m">0&lt;/span> changed, &lt;span class="m">0&lt;/span> destroyed.
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>바꿀건 하나도 없지만 apply 명령이 완료되었습니다. 그런데 apply 명령을 실행한 폴더를 확인해보시면, &lt;code>terraform.tfstate&lt;/code>라는 파일이 생겼습니다! 파일을 확인 해보면 이런 내용이 있습니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;version&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">4&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;terraform_version&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;1.6.2&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;serial&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;lineage&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;2e6b0c74-0e92-bfe8-1197-36e5547d9375&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;outputs&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;resources&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;check_results&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">null&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>이 파일에는 현재 Terraform 코드를 apply해서 구성된 리소스의 상태가 기록되고 있습니다. 즉, 가장 최근에 실행한 apply 명령을 통해 구성된 리소스의 상태(여기서는 aws 클라우드에 생성된 리소스의 상태)가 기록됩니다. 여러분이 plan 명령을 실행 할 때 뭐가 추가되고, 뭐가 수정되며 뭐가 삭제되는지를 이 파일에 기록된 현재 상태를 기준으로 판단하는 거죠. 이 파일에 포함된 속성은 다음과 같습니다.&lt;/p>
&lt;ul>
&lt;li>&lt;code>version&lt;/code>: Terraform의 상태 파일 형식 버전입니다. 현재는 4입니다.&lt;/li>
&lt;li>&lt;code>terraform_version&lt;/code>: Terraform의 버전입니다.&lt;/li>
&lt;li>&lt;code>serial&lt;/code>: 상태 파일이 변경될 때마다 증가하는 숫자입니다. 이 숫자는 상태 파일이 변경될 때마다 증가하며, 이 숫자를 통해 상태 파일이 변경되었는지를 판단합니다.&lt;/li>
&lt;li>&lt;code>lineage&lt;/code>: 상태 파일의 고유 식별자입니다. 처음 생성될 때 부여되고, 그 이후로는 변경되지 않습니다.&lt;/li>
&lt;li>&lt;code>outputs&lt;/code>: Terraform 코드에서 &lt;code>output&lt;/code>으로 정의한 출력 값들이 기록됩니다.&lt;/li>
&lt;li>&lt;code>resources&lt;/code>: Terraform 코드에서 &lt;code>resource&lt;/code>로 정의한 리소스들의 상태가 기록됩니다.&lt;/li>
&lt;li>&lt;code>check_results&lt;/code>: Terraform 코드에서 &lt;code>data&lt;/code>로 정의한 데이터 소스들의 상태가 기록됩니다.&lt;/li>
&lt;/ul>
&lt;p>그렇다면 EC2 인스턴스를 하나 추가해서 상태 파일이 어떻게 바뀌는지 확인해봅시다! &lt;code>main.tf&lt;/code>에 아래 코드를 추가합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-terraform" data-lang="terraform">&lt;span class="line">&lt;span class="cl">&lt;span class="kr">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_instance&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;example&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // ap-northeast-2 리전의 Ubuntu 20.04 AMI
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">ami&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ami-0c6e5afdd23291f73&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">instance_type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;t2.micro&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>그리고 &lt;code>tf plan&lt;/code>을 실행합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; tf plan
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Terraform used the selected providers to generate the following execution plan. Resource actions are indicated
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">with the following symbols:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + create
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Terraform will perform the following actions:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># aws_instance.example will be created&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + resource &lt;span class="s2">&amp;#34;aws_instance&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;example&amp;#34;&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">ami&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ami-0c6e5afdd23291f73&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">arn&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">associate_public_ip_address&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">availability_zone&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">cpu_core_count&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">cpu_threads_per_core&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">disable_api_stop&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">disable_api_termination&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">ebs_optimized&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">get_password_data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">false&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">host_id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">host_resource_group_arn&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">iam_instance_profile&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">instance_initiated_shutdown_behavior&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">instance_lifecycle&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">instance_state&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">instance_type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;t2.micro&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">ipv6_address_count&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">ipv6_addresses&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">key_name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">monitoring&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">outpost_arn&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">password_data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">placement_group&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">placement_partition_number&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">primary_network_interface_id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">private_dns&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">private_ip&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">public_dns&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">public_ip&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">secondary_private_ips&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">security_groups&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">source_dest_check&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">spot_instance_request_id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">subnet_id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">tags_all&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">tenancy&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">user_data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">user_data_base64&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">user_data_replace_on_change&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">false&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">vpc_security_group_ids&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Plan: &lt;span class="m">1&lt;/span> to add, &lt;span class="m">0&lt;/span> to change, &lt;span class="m">0&lt;/span> to destroy.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">──────────────────────────────────────────────────────────────────────────────────────────────────────────────────
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Note: You didn&lt;span class="s1">&amp;#39;t use the -out option to save this plan, so Terraform can&amp;#39;&lt;/span>t guarantee to take exactly these actions
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> you run &lt;span class="s2">&amp;#34;terraform apply&amp;#34;&lt;/span> now.
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>현재는 생성된 리소스가 하나도 없기 때문에, 상태 값은 비어있는 상태죠. 그래서 Terraform 코드에 정의된 리소스는 모두 새로 추가됩니다. 이제 &lt;code>tf apply&lt;/code>를 실행합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; tf apply
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Apply complete! Resources: &lt;span class="m">1&lt;/span> added, &lt;span class="m">0&lt;/span> changed, &lt;span class="m">0&lt;/span> destroyed.
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>이제 다시 &lt;code>terraform.tfstate&lt;/code> 파일의 내용을 확인합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;version&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">4&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;terraform_version&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;1.6.2&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;serial&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;lineage&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;2e6b0c74-0e92-bfe8-1197-36e5547d9375&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;outputs&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;resources&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;mode&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;managed&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;aws_instance&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;example&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;provider&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;provider[\&amp;#34;registry.terraform.io/hashicorp/aws\&amp;#34;]&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;instances&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;schema_version&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;attributes&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;ami&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;ami-0c6e5afdd23291f73&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="err">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;sensitive_attributes&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;private&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;...&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;check_results&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">null&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>방금 전 apply 명령으로 추가된 리소스를 확인할 수 있습니다.&lt;/p>
&lt;p>상태는 Terraform이 리소스를 관리할 때 어떻게 변경해야 할지 판단하는 기준이 됩니다. 그렇기 때문에 상태는 Terraform에서 가장 중요합니다. 상태가 제대로 관리되지 않으면 어떤 리소스를 어떻게 변경해야 할지 Terraform이 제대로 판단할 수 없겠죠.&lt;/p>
&lt;blockquote>
&lt;p>그렇기 때문에 Terraform으로 생성된 리소스를 관리 콘솔에서 직접 변경하면 안됩니다! 상태 파일에 기록된 내용과 실제 리소스의 상태가 달라지기 때문에 Terraform이 제대로 동작하지 않을 수 있습니다.&lt;/p>&lt;/blockquote>
&lt;p>확인이 끝났으므로 destroy 명령으로 생성된 리소스를 모두 제거합니다. 참고로 제거 작업이 끝난 후 상태 파일은 이렇습니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;version&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">4&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;terraform_version&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;1.6.2&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;serial&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;lineage&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;2e6b0c74-0e92-bfe8-1197-36e5547d9375&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;outputs&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;resources&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;check_results&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">null&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>serial&lt;/code>을 제외하고는 모두 원래대로 돌아왔죠?&lt;/p>
&lt;h2 id="상태-파일-관리">상태 파일 관리&lt;/h2>
&lt;p>보시다시피 별다른 설정이 없다면, 상태 파일은 현재 Terraform 명령을 실행하는 폴더에 생성됩니다. 실습을 위해 간단하게 테스트를 하는 경우라면 문제가 없겠지만, 계속 상태 파일을 이렇게 사용하는 건 매우 위험합니다. 그 이유는!&lt;/p>
&lt;ul>
&lt;li>output등의 민감한 정보가 상태 파일에 기록되기 때문에 파일에 접근할 수 있다면, 민감한 정보를 보호할 수 없습니다.&lt;/li>
&lt;li>동일한 리소스에 대해, 여러 장소(컴퓨터)에서 Terraform을 실행해야 하는 경우 각 장소마다 동일한 상태 파일을 가지고 있어야 합니다. 그래서 git등의 버전 관리 시스템으로 상태 파일을 관리할 수도 있지만, &lt;code>commit이나 pull을 까먹는다면 무슨 일이 벌어질까요?&lt;/code>&lt;/li>
&lt;/ul>
&lt;p>그래서 실제 Terraform을 사용하려면 상태 파일은 로컬 컴퓨터가 아닌, git같은 버전 관리 시스템도 아닌 어딘가 안전하고 항상 접근 가능한 곳에 저장되어야 합니다. 그리고 가능하면 암호화되어야 겠죠! 이 글 서두에 보셨던 &lt;code>backend&lt;/code>가 바로 이런 상태 파일을 어딘가에서 안전하게 잘 관리해주는 역할을 합니다. 우리는 지금 &lt;code>AWS&lt;/code>를 사용하고 있죠? 그렇다면 이제 &lt;code>S3&lt;/code>를 통해 &lt;code>backend&lt;/code>를 구성해보겠습니다.&lt;/p>
&lt;h2 id="s3-backend-구성">S3 backend 구성&lt;/h2>
&lt;p>&lt;code>S3&lt;/code>로 &lt;code>backend&lt;/code>를 구성하려면 우선 &lt;code>S3&lt;/code>를 생성해야겠죠? 일단 Terraform으로 &lt;code>S3&lt;/code>를 생성하고 그 이후에 &lt;code>backend&lt;/code>를 구성해서 상태를 &lt;code>backend&lt;/code>로 옮기겠습니다. 새로 폴더를 만들고 &lt;code>main.tf&lt;/code>를 다음과 같이 작성합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-terraform" data-lang="terraform">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// AWS 프로바이더 설정
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">provider&lt;/span> &lt;span class="s2">&amp;#34;aws&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // 아시아 태평양(서울) 리전
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">region&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ap-northeast-2&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># S3 버킷 생성
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_s3_bucket&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;terraform_state&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">bucket&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;terraform-state-example-20231118&amp;#34;&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> # 실수로 버킷이 삭제되지 않도록 하려면 아래 주석을 해제하세요.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> # lifecycle {
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> # prevent_destroy = true
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> # }
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 버킷 버전 관리 활성화(상태 파일의 히스토리를 관리하기 위함)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_s3_bucket_versioning&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;enabled&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">bucket&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">aws_s3_bucket&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">terraform_state&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">id&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">versioning_configuration&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">status&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;Enabled&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># S3에 저장될 때 암호화 하도록 설정
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_s3_bucket_server_side_encryption_configuration&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;default&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">bucket&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">aws_s3_bucket&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">terraform_state&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">id&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">rule&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">apply_server_side_encryption_by_default&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">sse_algorithm&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;AES256&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 모든 public access를 차단(실수로 버킷이 공개되지 않도록 하기 위함)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_s3_bucket_public_access_block&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;public_access&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">bucket&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">aws_s3_bucket&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">terraform_state&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">id&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">block_public_acls&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">block_public_policy&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">ignore_public_acls&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">restrict_public_buckets&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 여러 사람이 동시에 상태 파일을 수정하지 못하도록 DynamoDB를 사용한 락 설정
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_dynamodb_table&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;terraform_locks&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;terraform_locks&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">billing_mode&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;PAY_PER_REQUEST&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">hash_key&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;LockID&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">attribute&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;LockID&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;S&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>우선 &lt;code>aws_s3_bucket&lt;/code> 리소스를 통해 &lt;code>S3&lt;/code> 버킷을 생성하는데요, 이 버킷에 상태 파일을 저장하게 됩니다. 그리고 필요한 경우 상태 파일의 히스토리를 버전 별로 관리할 수 있도록 버전 관리를 활성화 합니다. 버전 관리를 사용하도록 설정한다면 뭔가 상태 파일에 문제가 있을 경우 이전 버전으로 복구할 수 있겠죠?&lt;/p>
&lt;p>그리고 상태 파일은 암호화되어 저장되도록 설정했고, 실수로 버킷이 공개되지 않도록 모든 public access를 차단했습니다. 마지막으로 여러 사람이 동시에 상태 파일을 수정하지 못하도록 DynamoDB를 사용한 락을 설정했습니다. 이제 &lt;code>tf init&lt;/code>을 실행해봅시다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; tf init
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Terraform has been successfully initialized!
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>그리고 &lt;code>tf plan&lt;/code>으로 변경될 리소스를 확인합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; tf plan
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Plan: &lt;span class="m">5&lt;/span> to add, &lt;span class="m">0&lt;/span> to change, &lt;span class="m">0&lt;/span> to destroy.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>이어서 &lt;code>tf apply&lt;/code>로 리소스를 생성합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; tf apply
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Apply complete! Resources: &lt;span class="m">5&lt;/span> added, &lt;span class="m">0&lt;/span> changed, &lt;span class="m">0&lt;/span> destroyed.
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>만약 이전글에서 사용했던 것처럼 제한된 IAM 사용자 권한을 사용하는 경우 &amp;ldquo;sts:GetCallerIdentity&amp;rdquo;,&amp;ldquo;s3:CreateBucket&amp;rdquo;,&amp;ldquo;dynamodb:CreateTable&amp;rdquo;,&amp;ldquo;dynamodb:DescribeTable&amp;rdquo;,&amp;ldquo;s3:ListBucket&amp;rdquo;,&amp;ldquo;s3:GetBucketPolicy&amp;rdquo;,&amp;ldquo;s3:GetBucketAcl&amp;rdquo;,&amp;ldquo;s3:GetBucketCORS&amp;rdquo;,&amp;ldquo;s3:GetBucketWebsite&amp;rdquo;,&amp;ldquo;s3:GetBucketVersioning&amp;rdquo;,&amp;ldquo;s3:GetAccelerateConfiguration&amp;rdquo;,&amp;ldquo;s3:GetBucketRequestPayment&amp;rdquo;,&amp;ldquo;s3:GetBucketLogging&amp;rdquo;,&amp;ldquo;s3:GetLifecycleConfiguration&amp;rdquo;,&amp;ldquo;s3:GetReplicationConfiguration&amp;rdquo;,&amp;ldquo;s3:GetEncryptionConfiguration&amp;rdquo;,&amp;ldquo;s3:GetBucketObjectLockConfiguration&amp;rdquo;,&amp;ldquo;s3:GetBucketTagging&amp;rdquo;,&amp;ldquo;s3:PutBucketVersioning&amp;rdquo;,&amp;ldquo;dynamodb:DescribeContinuousBackups&amp;rdquo;,&amp;ldquo;s3:PutBucketPublicAccessBlock&amp;rdquo;,&amp;ldquo;s3:PutEncryptionConfiguration&amp;rdquo;,&amp;ldquo;dynamodb:DescribeTimeToLive&amp;rdquo;,&amp;ldquo;dynamodb:ListTagsOfResource&amp;rdquo;,&amp;ldquo;s3:GetBucketPublicAccessBlock&amp;rdquo;,&amp;ldquo;s3:GetObject&amp;rdquo;,&amp;ldquo;s3:GetObjectVersion&amp;rdquo;,&amp;ldquo;dynamodb:GetItem&amp;rdquo;,&amp;ldquo;dynamodb:PutItem&amp;rdquo;,&amp;ldquo;dynamodb:DeleteItem&amp;rdquo; 등의 권한이 추가로 필요합니다.&lt;/p>&lt;/blockquote>
&lt;p>&lt;code>S3&lt;/code>는 잘 생성되었지만, 여전히 &lt;code>terraform.tfstate&lt;/code>파일은 현재 폴더에 그대로 남아있습니다. 파일 내용을 확인해보면, 방금 생성한 &lt;code>S3&lt;/code>의 정보가 담겨있습니다. 아직 &lt;code>backend&lt;/code>설정을 하지 않았기 때문에 여전히 상태 파일은 로컬 컴퓨터에서 관리하고 있는 거죠. 그렇다면 &lt;code>backend&lt;/code>를 &lt;code>S3&lt;/code>로 설정하겠습니다. &lt;code>main.tf&lt;/code>에서 기존에 작성된 코드 위에 다음 코드를 추가합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-terraform" data-lang="terraform">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Terraform 설정
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="nx">terraform&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> # 필요한 프로바이더 목록과 버전 정보
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">required_providers&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">aws&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">source&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;hashicorp/aws&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">version&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;~&amp;gt; 5.0&amp;#34;&lt;/span>&lt;span class="c1"> # 5.x 버전 사용
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> # 상태 파일을 S3에 저장하도록 설정
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">backend&lt;/span> &lt;span class="s2">&amp;#34;s3&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">bucket&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;terraform-state-example-20231118&amp;#34;&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> # 상태 파일이 저장될 경로
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">key&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;example/terraform.tfstate&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">region&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ap-northeast-2&amp;#34;&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> # 상태 파일을 락으로 사용할 DynamoDB 테이블
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">dynamodb_table&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;terraform_locks&amp;#34;&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> # 상태 파일을 암호화
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">encrypt&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">...&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Terraform 블록을 선언하고 사용할 프로바이더와 버전 정보, 그리고 &lt;code>S3&lt;/code>를 &lt;code>backend&lt;/code>로 사용하도록 설정했습니다. 이제 &lt;code>tf init&lt;/code>을 실행하면 로컬에 저장된 상태 파일을 새로 지정된 &lt;code>S3&lt;/code>로 이동하게 됩니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; tf init
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Initializing the backend...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Acquiring state lock. This may take a few moments...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Do you want to copy existing state to the new backend?
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> Pre-existing state was found &lt;span class="k">while&lt;/span> migrating the previous &lt;span class="s2">&amp;#34;local&amp;#34;&lt;/span> backend to the
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> newly configured &lt;span class="s2">&amp;#34;s3&amp;#34;&lt;/span> backend. No existing state was found in the newly
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> configured &lt;span class="s2">&amp;#34;s3&amp;#34;&lt;/span> backend. Do you want to copy this state to the new &lt;span class="s2">&amp;#34;s3&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> backend? Enter &lt;span class="s2">&amp;#34;yes&amp;#34;&lt;/span> to copy and &lt;span class="s2">&amp;#34;no&amp;#34;&lt;/span> to start with an empty state.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> Enter a value: yes
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Releasing state lock. This may take a few moments...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Successfully configured the backend &lt;span class="s2">&amp;#34;s3&amp;#34;&lt;/span>! Terraform will automatically
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">use this backend unless the backend configuration changes.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>로컬에 저장된 상태를 &lt;code>S3&lt;/code>로 복사하겠냐는 질문이 나오는데, &lt;code>yes&lt;/code>를 입력하면 로컬에 저장된 상태 파일이 &lt;code>S3&lt;/code>로 복사됩니다. 그리고 &lt;code>terraform.tfstate&lt;/code> 파일이 남아있긴 하지만, 내용을 확인 해보면 텅텅 비어 있습니다. 이제 삭제해도 문제가 없겠죠! 참고로 &lt;code>backend&lt;/code>에서 상태 파일을 로컬로 다운로드 하고 싶다면 &lt;code>terraform state pull&lt;/code> 명령을 사용하면 됩니다.&lt;/p>
&lt;blockquote>
&lt;p>&lt;code>iamlive&lt;/code>를 실행 중이라면 &lt;code>tls: failed to verify certificate: x509&lt;/code> 오류나 &lt;code>request send failed, Post &amp;quot;https://sts.ap-northeast-2.amazonaws.com/&amp;quot;: proxyconnect tcp: dial tcp 127.0.0.1:80&lt;/code> 등의 오류가 발생할 수 있습니다. &lt;code>iamlive&lt;/code>의 실행을 위해 선언해둔 환경 변수 때문인데요, 해당 환경 변수를 주석처리하고 터미널 세션을 다시 시작하거나, &lt;code>unset&lt;/code> 등의 명령어로 현재 터미널 세션에서 환경 변수를 제거할 수 있습니다.&lt;/p>&lt;/blockquote>
&lt;p>그렇다면 이제 간단한 EC2 인스턴스를 추가해서 상태가 잘 관리되는지 확인하겠습니다. &lt;code>main.tf&lt;/code>에 다음 코드를 추가합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-terraform" data-lang="terraform">&lt;span class="line">&lt;span class="cl">&lt;span class="p">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_instance&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;example&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // ap-northeast-2 리전의 Ubuntu 20.04 AMI
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">ami&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ami-0c6e5afdd23291f73&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">instance_type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;t2.micro&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>tf plan&lt;/code>과 &lt;code>tf apply&lt;/code>를 실행하여 동작을 확인합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; tf plan
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Plan: &lt;span class="m">1&lt;/span> to add, &lt;span class="m">0&lt;/span> to change, &lt;span class="m">0&lt;/span> to destroy.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt; tf apply
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Apply complete! Resources: &lt;span class="m">1&lt;/span> added, &lt;span class="m">0&lt;/span> changed, &lt;span class="m">0&lt;/span> destroyed.
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>더 이상 로컬에 상태 파일이 생성되지 않지만, 원격의 &lt;code>S3&lt;/code>에서 상태를 읽어와서 잘 관리하고 있네요!&lt;/p>
&lt;h1 id="마치며">마치며&lt;/h1>
&lt;p>이제 우리는 상태를 로컬 파일이 아니라 &lt;code>S3&lt;/code>를 통해 안전하고 안정적으로 그리고 어디서나 활용할 수 있도록 변경할 수 있습니다. 하지만 여전히 불안한 점은 남아있습니다. EC2를 추가하면서 plan, apply를 실행해보신 분들은 아시겠지만, 여전히 이미 생성된 &lt;code>S3&lt;/code>에 대한 상태를 매번 비교하고 있습니다. 하나의 상태에 많은 리소스가 연결되면 이렇게 아주 작은 부분만을 바꿀 때도 전체 상태와 비교를 하게 됩니다. 그리고 아무리 리소스 파일이 공유된 상태라고는 하지만, 여러 사람이 동시에 서로 다른 부분에서 코드를 변경하면 예상하지 어려운 상황이 발생하겠죠. 그래서 상태 파일은 가능하면 작게 유지하는 게 좋습니다. 다음 시간에는 상태 파일을 작게 유지하는 방법에 대해 알아보겠습니다.&lt;/p>
&lt;h1 id="참고자료">참고자료&lt;/h1>
&lt;ul>
&lt;li>&lt;a href="https://www.terraformupandrunning.com/">Terraform Up and Running, 3rd Edition&lt;/a>&lt;/li>
&lt;/ul>
&lt;h1 id="license">License&lt;/h1>
&lt;p>&lt;a href="https://creativecommons.org/licenses/by-nc-nd/2.0/kr/">저작자표시-비영리-변경금지 2.0 대한민국 (CC BY-NC-ND 2.0 KR)&lt;/a>&lt;/p></content></item><item><title>How to Terraform(2) - 변수와 출력</title><link>https://netscout.github.io/posts/how-to-terraform-2-%EB%B3%80%EC%88%98%EC%99%80-%EC%B6%9C%EB%A0%A5/</link><pubDate>Sat, 11 Nov 2023 15:30:01 +0900</pubDate><guid>https://netscout.github.io/posts/how-to-terraform-2-%EB%B3%80%EC%88%98%EC%99%80-%EC%B6%9C%EB%A0%A5/</guid><description>이전 글에서 작성한 코드를 다시 한 번 볼까요?</description><content>&lt;h2 id="시리즈-목차">시리즈 목차&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="../How%20to%20Terraform%281%29%20-%20%ED%99%98%EA%B2%BD%20%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0%2FHow%20to%20Terraform%281%29%20-%20%ED%85%8C%EB%9D%BC%ED%8F%BC%EA%B3%BC%EC%9D%98%20%EA%B0%80%EB%B2%BC%EC%9A%B4%28%3F%29%20%EC%B2%AB%20%EB%A7%8C%EB%82%A8.md">How to Terraform(1) - 테라폼과의 가벼운(?) 첫 만남&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="이전-글-복습">이전 글 복습&lt;/h2>
&lt;p>&lt;a href="../How%20to%20Terraform%281%29%20-%20%ED%99%98%EA%B2%BD%20%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0%2FHow%20to%20Terraform%281%29%20-%20%ED%85%8C%EB%9D%BC%ED%8F%BC%EA%B3%BC%EC%9D%98%20%EA%B0%80%EB%B2%BC%EC%9A%B4%28%3F%29%20%EC%B2%AB%20%EB%A7%8C%EB%82%A8.md">이전 글&lt;/a>에서 작성한 코드를 다시 한 번 볼까요?&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-terraform" data-lang="terraform">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// AWS 프로바이더 설정
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">provider&lt;/span> &lt;span class="s2">&amp;#34;aws&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // 아시아 태평양(서울) 리전
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">region&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ap-northeast-2&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_instance&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;example&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // ap-northeast-2 리전의 Ubuntu 20.04 AMI
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">ami&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ami-0c6e5afdd23291f73&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">instance_type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;t2.micro&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">vpc_security_group_ids&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="nx">aws_security_group&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">example&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">id&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // 최초 인스턴스 생성 시에만 실행
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">user_data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;-EOF&lt;/span>&lt;span class="s">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> #!/bin/bash
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> echo &amp;#34;Hello, World&amp;#34; &amp;gt; index.html
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> nohup busybox httpd -f -p 8080 &amp;amp;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> &lt;/span>&lt;span class="o">EOF&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">tags&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">Name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;terraform-example&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_security_group&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;example&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;terraform-example&amp;#34;&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // 인바운드 규칙
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">ingress&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">from_port&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">8080&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">to_port&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">8080&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">protocol&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;tcp&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">cidr_blocks&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;0.0.0.0/0&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>위 코드에는 몇 가지 개선할 점이 있습니다. 만약 EC2 인스턴스를 몇 개 더 만든다고 했을 때 중복될 만한 부분이 있습니다. AMI ID나 인스턴스 타입 등이 그렇죠. 이렇게 중복될 만한 내용은 변수로 선언하여 중복을 줄일 수 있고, 중복을 줄이면 실수를 줄일 수 있습니다. 또한 EC2 인스턴스에 접근할 수 있는 IP를 AWS 콘솔에서 확인하는 번거로움이 있었습니다. 이 또한 출력을 통해 확인할 수 있습니다. 자 그럼 하나씩 해봅시다!&lt;/p>
&lt;h2 id="변수">변수&lt;/h2>
&lt;p>가장 먼저 AMI ID 부터 변수를 선언해볼까요? &lt;code>main.tf&lt;/code> 파일이 있는 위치에 &lt;code>variables.tf&lt;/code> 파일을 만들고 아래와 같이 작성해봅시다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-terraform" data-lang="terraform">&lt;span class="line">&lt;span class="cl">&lt;span class="kr">variable&lt;/span> &lt;span class="s2">&amp;#34;ami_id&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">string&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">default&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ami-0c6e5afdd23291f73&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>변수의 이름은 &lt;code>ami_id&lt;/code>이고, 타입은 &lt;code>string&lt;/code>입니다. 그리고 &lt;code>default&lt;/code>에는 별도로 값이 주어지지 않는 경우 사용할 기본값을 설정합니다. 이제 &lt;code>main.tf&lt;/code> 파일에서 &lt;code>ami&lt;/code> 속성을 변수를 통해 입력받도록 변경합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-terraform" data-lang="terraform">&lt;span class="line">&lt;span class="cl">&lt;span class="kr">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_instance&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;example&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">ami&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">var&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">ami_id&lt;/span>&lt;span class="c1"> # 변수 ami_id 참조
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">instance_type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;t2.micro&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">vpc_security_group_ids&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="nx">aws_security_group&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">example&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">id&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>VS Code를 사용하신다면 Terraform Extension for Visual Studio Code를 꼭 설치하세요! 선언된 변수나 리소스에 대해서 자동완성 기능과 오류 등을 미리 확인할 수 있게 도와줍니다!&lt;/p>&lt;/blockquote>
&lt;p>기존에 직접 값을 지정했던 ami 속성에 변수 ami_id를 참조하도록 변경했습니다. &lt;code>tf plan&lt;/code>을 통해 스크립트에 이상이 없는지 확인합니다. 참고로 지난 시간에 만든 EC2 인스턴스는 &lt;code>tf destroy&lt;/code>를 통해 삭제되었다고 가정하겠습니다.&lt;/p>
&lt;blockquote>
&lt;p>&lt;code>terraform&lt;/code>이라고 매번 입력하는게 어려우니 .zshrc나 .bashrc에 다음과 같이 alias 설정을 해서 &lt;code>tf&lt;/code>로 사용하는 것도 방법입니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">alias tf=terraform
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/blockquote>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; tf plan
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">symbols:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + create
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Terraform will perform the following actions:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># aws_instance.example will be created&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + resource &lt;span class="s2">&amp;#34;aws_instance&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;example&amp;#34;&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">ami&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ami-0c6e5afdd23291f73&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># aws_security_group.example will be created&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + resource &lt;span class="s2">&amp;#34;aws_security_group&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;example&amp;#34;&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Plan: &lt;span class="m">2&lt;/span> to add, &lt;span class="m">0&lt;/span> to change, &lt;span class="m">0&lt;/span> to destroy.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Note: You didn&lt;span class="s1">&amp;#39;t use the -out option to save this plan, so Terraform can&amp;#39;&lt;/span>t guarantee to take exactly these actions &lt;span class="k">if&lt;/span> you run
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;terraform apply&amp;#34;&lt;/span> now.
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>ami 속성이 변수에 설정된 기본값으로 설정된 걸 확인할 수 있습니다. 그렇다면 기본값 대신에 변수에 값을 넘겨볼까요?&lt;/p>
&lt;h3 id="커맨드로-변수-지정하기">커맨드로 변수 지정하기&lt;/h3>
&lt;p>&lt;code>tf plan&lt;/code> 또는 &lt;code>tf apply&lt;/code>를 실행할 때 &lt;code>-var&lt;/code> 옵션을 사용하면 변수에 값을 넘길 수 있습니다. &lt;code>-var&lt;/code> 옵션은 변수의 개수 만큼 여러 번 사용할 수 있습니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; tf plan -var &lt;span class="s2">&amp;#34;ami_id=ami-09eb4311cbaecf89d&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># aws_instance.example will be created&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + resource &lt;span class="s2">&amp;#34;aws_instance&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;example&amp;#34;&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">ami&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ami-09eb4311cbaecf89d&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="파일로-변수-지정하기">파일로 변수 지정하기&lt;/h3>
&lt;p>이번에는 &lt;code>terraform.tfvars&lt;/code> 파일을 통해 변수에 값을 지정해보겠습니다. &lt;code>terraform.tfvars&lt;/code> 파일을 만들고 아래와 같이 작성해봅시다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-terraform" data-lang="terraform">&lt;span class="line">&lt;span class="cl">&lt;span class="nx">ami_id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ami-09eb4311cbaecf89d&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>그리고 &lt;code>tf plan&lt;/code>을 실행하면, 동일한 결과를 확인할 수 있습니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; tf plan
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># aws_instance.example will be created&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + resource &lt;span class="s2">&amp;#34;aws_instance&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;example&amp;#34;&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">ami&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ami-09eb4311cbaecf89d&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>파일 이름이 &lt;code>terraform.tfvars&lt;/code> 또는 &lt;code>terraform.tfvars.json&lt;/code>(json 형태로 작성가능)이거나, 파일 이름이 &lt;code>.auto.tfvars&lt;/code> 또는 &lt;code>.auto.tfvars.json&lt;/code>으로 끝나는 경우, Terraform 코드가 실행 될 때 자동으로 파일을 읽어서 변수에 값을 지정합니다. 만약 파일 이름 앞서 설명드린 규칙과 다르다면, 파일 이름을 &lt;code>-var-file&lt;/code> 옵션을 사용하여 파일을 지정할 수 있습니다.&lt;/p>
&lt;p>한 가지 주의 할 점은 &lt;code>terraform.tfvars&lt;/code> 파일을 사용하는 경우, 반드시 .gitignore에 terraform.tfvars를 추가해야 합니다! 참고로 &lt;a href="https://www.toptal.com/developers/gitignore/">gitignore.io&lt;/a>를 통해 Terraform의 .gitignore 파일을 생성해보면 다음과 같습니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-gdscript3" data-lang="gdscript3">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Created by https://www.toptal.com/developers/gitignore/api/terraform&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Edit at https://www.toptal.com/developers/gitignore?templates=terraform&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">### Terraform ###&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Local .terraform directories&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">**/.&lt;/span>&lt;span class="n">terraform&lt;/span>&lt;span class="o">/*&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># .tfstate files&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">*.&lt;/span>&lt;span class="n">tfstate&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">*.&lt;/span>&lt;span class="n">tfstate&lt;/span>&lt;span class="o">.*&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Crash log files&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">crash&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">log&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">crash&lt;/span>&lt;span class="o">.*.&lt;/span>&lt;span class="n">log&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Exclude all .tfvars files, which are likely to contain sensitive data, such as&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># password, private keys, and other secrets. These should not be part of version&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># control as they are data points which are potentially sensitive and subject&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># to change depending on the environment.&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">*.&lt;/span>&lt;span class="n">tfvars&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">*.&lt;/span>&lt;span class="n">tfvars&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">json&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Ignore override files as they are usually used to override resources locally and so&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># are not checked in&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">override&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">tf&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">override&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">tf&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">json&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">*&lt;/span>&lt;span class="n">_override&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">tf&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">*&lt;/span>&lt;span class="n">_override&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">tf&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">json&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Include override files you do wish to add to version control using negated pattern&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># !example_override.tf&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># example: *tfplan*&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Ignore CLI configuration files&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">.&lt;/span>&lt;span class="n">terraformrc&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">terraform&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">rc&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># End of https://www.toptal.com/developers/gitignore/api/terraform&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="환경변수로-변수-지정하기">환경변수로 변수 지정하기&lt;/h3>
&lt;p>마지막으로는 환경변수를 지정하는 방법이 있습니다. &lt;code>TF_VAR_&lt;/code>로 시작해서 변수 이름을 적어주면 됩니다. &lt;code>~/.zshrc&lt;/code>등에 환경변수를 적어도 되지만 일단은 확인을 위해 인라인으로 환경변수를 지정해서 &lt;code>tf plan&lt;/code>을 실행해보겠습니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; &lt;span class="nv">TF_VAR_ami_id&lt;/span>&lt;span class="o">=&lt;/span>ami-09eb4311cbaecf89d tf plan
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># aws_instance.example will be created&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + resource &lt;span class="s2">&amp;#34;aws_instance&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;example&amp;#34;&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">ami&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ami-09eb4311cbaecf89d&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="변수-작업을-더-해보자">변수 작업을 더 해보자&lt;/h2>
&lt;p>이제 변수를 사용하는 방법을 알았으니 나머지 값들도 변수로 변경하겠습니다.&lt;/p>
&lt;p>우선 변수를 선언합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-terraform" data-lang="terraform">&lt;span class="line">&lt;span class="cl">&lt;span class="kr">variable&lt;/span> &lt;span class="s2">&amp;#34;ami_id&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">string&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">default&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ami-0c6e5afdd23291f73&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">variable&lt;/span> &lt;span class="s2">&amp;#34;instance_type&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">string&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">default&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;t2.micro&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">variable&lt;/span> &lt;span class="s2">&amp;#34;port&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">number&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">variable&lt;/span> &lt;span class="s2">&amp;#34;cidr_blocks&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">type&lt;/span> &lt;span class="o">=&lt;/span>&lt;span class="nb"> list&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">string&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">default&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;0.0.0.0/0&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>그리고 이 변수를 사용하도록 코드를 변경합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-terraform" data-lang="terraform">&lt;span class="line">&lt;span class="cl">&lt;span class="kr">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_instance&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;example&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // ap-northeast-2 리전의 Ubuntu 20.04 AMI
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">ami&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">var&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">ami_id&lt;/span>&lt;span class="c1"> # 변수 ami_id 참조
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">instance_type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">var&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">instance_type&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">vpc_security_group_ids&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="nx">aws_security_group&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">example&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">id&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // 최초 인스턴스 생성 시에만 실행
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">user_data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;-EOF&lt;/span>&lt;span class="s">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> #!/bin/bash
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> echo &amp;#34;Hello, World&amp;#34; &amp;gt; index.html
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> nohup busybox httpd -f -p ${var.port} &amp;amp;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> &lt;/span>&lt;span class="o">EOF&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">tags&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">Name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;terraform-example&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_security_group&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;example&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;terraform-example&amp;#34;&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // 인바운드 규칙
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">ingress&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">from_port&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">var&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">port&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">to_port&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">var&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">port&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">protocol&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;tcp&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">cidr_blocks&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">var&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">cidr_blocks&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>그리고 &lt;code>terraform.tfvars&lt;/code> 파일을 사용해서 변수를 지정합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-terraform" data-lang="terraform">&lt;span class="line">&lt;span class="cl">&lt;span class="nx">ami_id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ami-09eb4311cbaecf89d&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">port&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">8080&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>마지막으로 &lt;code>tf plan&lt;/code>을 실행해서 변수가 잘 작동하는지 확인합니다.&lt;/p>
&lt;h2 id="다음은-출력">다음은 출력&lt;/h2>
&lt;p>현재 작성 중인 코드에는 외부에서 EC2 인스턴스에 접근할 수 있는 IP를 확인할 수 있는 방법이 없고, AWS 콘솔에 접속해서 생성된 EC2 인스턴스를 찾아가야만 합니다. 이제 출력값을 설정해서 생성된 EC2 인스턴스의 IP를 확인해 보겠습니다.&lt;/p>
&lt;p>&lt;code>outputs.tf&lt;/code> 파일을 만들고 아래와 같이 작성합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-terraform" data-lang="terraform">&lt;span class="line">&lt;span class="cl">&lt;span class="kr">output&lt;/span> &lt;span class="s2">&amp;#34;public_ip&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">value&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">aws_instance&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">example&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">public_ip&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">sensitive&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">false&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>그리고 &lt;code>tf plan&lt;/code>을 실행합니다. 그리고 마지막에 출력되는 내용을 잘 보세요!&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; tf plan
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Plan: &lt;span class="m">2&lt;/span> to add, &lt;span class="m">0&lt;/span> to change, &lt;span class="m">0&lt;/span> to destroy.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Changes to Outputs:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">public_ip&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>출력값이 추가되었다는 걸 알려주죠? 이 출력값은 EC2 인스턴스가 실제로 만들어진 다음에 확인할 수 있기 때문에 &lt;code>known after apply&lt;/code>라고 표시되었습니다. 이제 &lt;code>tf apply&lt;/code>를 실행해봅시다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; tf apply
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Apply complete! Resources: &lt;span class="m">2&lt;/span> added, &lt;span class="m">0&lt;/span> changed, &lt;span class="m">0&lt;/span> destroyed.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Outputs:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">public_ip&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;13.209.17.62&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>약 1-2분 뒤에 해당 IP의 지정된 포트(기본 값은 8080으로 설정했었죠?)로 접속하면 &lt;code>Hello, World&lt;/code>가 출력되는 걸 확인할 수 있습니다.&lt;/p>
&lt;p>그런데 이런 출력 값이 있다는 건 어디서 알 수 있는 걸까요? &lt;a href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance">EC2 인스턴스의 공식 문서&lt;/a>를 확인해볼까요?&lt;/p>
&lt;p>이 문서에는 EC2 인스턴스를 Terraform으로 관리할 때 사용할 수 있는 속성들이 아주 많이, 상세하게 정리되어 있습니다. 여기서 우리가 주목해야 할 곳은 문서 우측 상단의 &lt;code>ON THIS PAGE&lt;/code> 영역의 &lt;code>Attribute Reference&lt;/code>입니다.&lt;/p>
&lt;p align="center">&lt;img src="./01.png">&lt;/p>
&lt;p>이 영역에는 생성된 EC2 인스턴스를 통해 확인할 수 있는 속성들이 정리되어 있습니다. &lt;code>public_ip&lt;/code>를 찾아볼까요?&lt;/p>
&lt;p align="center">&lt;img src="./02.png">&lt;/p>
&lt;p>이렇게 필요한 속성을 찾아서 활용하면 됩니다. 물론&amp;hellip; 보시면 알겠지만 속성이 좀 많습니다. 뭐 하다보면 하나씩 눈에 보이는 거죠 하하하하하&amp;hellip;&lt;/p>
&lt;h2 id="내친-김에-ssh-키도-설정해보자">내친 김에 SSH 키도 설정해보자&lt;/h2>
&lt;p>이번에는 EC2 인스턴스에 접속할 때 SSH 키를 사용하도록 설정해보겠습니다. 먼저 &lt;code>main.tf&lt;/code>에서 SSH 키를 생성 및 설정합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-terraform" data-lang="terraform">&lt;span class="line">&lt;span class="cl">&lt;span class="p">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_instance&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;example&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">key_name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">aws_key_pair&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">ssh&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">key_name&lt;/span>&lt;span class="c1"> # ssh 키 이름 참조
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">tags&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">Name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;terraform-example&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_security_group&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;example&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">...&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // ssh 접속을 위한 인바운드 규칙
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">ingress&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">from_port&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">22&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">to_port&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">22&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">protocol&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;tcp&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">cidr_blocks&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">var&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">cidr_blocks&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># ssh 키 쌍(pair) 생성
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">resource&lt;/span> &lt;span class="s2">&amp;#34;tls_private_key&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;ssh&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">algorithm&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;RSA&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">rsa_bits&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">4096&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># ssh 키 쌍(pair) 리소스
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_key_pair&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;ssh&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">key_name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;terraform-example&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">public_key&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">tls_private_key&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">ssh&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">public_key_openssh&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>그리고 &lt;code>outputs.tf&lt;/code>에 SSH 키를 출력하도록 설정합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-terraform" data-lang="terraform">&lt;span class="line">&lt;span class="cl">&lt;span class="kr">output&lt;/span> &lt;span class="s2">&amp;#34;tls_private_key&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">value&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">tls_private_key&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">ssh&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">private_key_pem&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">sensitive&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">true&lt;/span>&lt;span class="c1"> # 민감한 정보이므로 출력하지 않음
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>tls_private_key&lt;/code> 리소스는 hashicorp/tls 프로바이더를 통해 제공되므로 &lt;code>tf init&lt;/code>을 통해 프로바이더를 설치합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; tf init
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Initializing the backend...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Initializing provider plugins...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">- Installing hashicorp/tls v4.0.4...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">- Installed hashicorp/tls v4.0.4 &lt;span class="o">(&lt;/span>signed by HashiCorp&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Terraform has been successfully initialized!
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>그리고 &lt;code>tf plan&lt;/code>으로 이상이 없는지 확인합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; tf plan
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Plan: &lt;span class="m">3&lt;/span> to add, &lt;span class="m">0&lt;/span> to change, &lt;span class="m">0&lt;/span> to destroy.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Changes to Outputs:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">public_ip&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">tls_private_key&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>sensitive value&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>이제 &lt;code>tf apply&lt;/code>를 실행합니다. 그런데 만약 이전 글의 내용을 따라 오면서 제한된 IAM이 설정된 계정을 사용하신다면 이런 에러가 발생합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; tf apply
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ Error: importing EC2 Key Pair &lt;span class="o">(&lt;/span>terraform-example&lt;span class="o">)&lt;/span>: UnauthorizedOperation: You are not authorized to perform this operation. User: arn:aws:iam::246181472423:user/terraform-user is not authorized to perform: ec2:ImportKeyPair on resource:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>이 작업을 위해서는 여기서 에러가 발생한 &lt;code>ec2:ImportKeyPair&lt;/code>, 그리고 &lt;code>ec2:DescribeKeyPairs&lt;/code>, &lt;code>ec2:DeleteKeyPair&lt;/code> 권한이 필요합니다. 이 권한을 추가해줍시다. 권한을 추가하고 다시 &lt;code>tf apply&lt;/code>를 실행합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; tf apply
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Apply complete! Resources: &lt;span class="m">2&lt;/span> added, &lt;span class="m">0&lt;/span> changed, &lt;span class="m">1&lt;/span> destroyed.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Outputs:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">public_ip&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;15.164.214.233&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">tls_private_key&lt;/span> &lt;span class="o">=&lt;/span> &amp;lt;sensitive&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>tls_private_key&lt;/code>는 민감한 정보를 의미하는 &lt;code>sensitive = true&lt;/code>로 설정되었으므로 터미널을 통해서는 확인할 수 없습니다. 하지만 EC2에 접속하려면 ssh 파일이 필요하죠? Terraform의 상태로 부터 이 파일을 생성합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; tf output tls_private_key &amp;gt; ~/.ssh/ec2_example.pem
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt; chmod &lt;span class="m">400&lt;/span> ~/.ssh/ec2_example.pem &lt;span class="c1"># 권한 설정&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>그리고 생성된 파일을 통해 EC2에 접속해봅시다. 그리고 접속이 확인되면 &lt;code>exit&lt;/code>을 통해 접속을 종료합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; ssh -i ~/.ssh/ec2_example.pem ubuntu@15.164.214.233
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Welcome to Ubuntu 20.04.6 LTS &lt;span class="o">(&lt;/span>GNU/Linux 5.15.0-1048-aws x86_64&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">ubuntu@ip-172-31-43-230:~$ &lt;span class="nb">exit&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>모두 확인이 되었다면 &lt;code>tf destroy&lt;/code>를 통해 리소스를 꼭 삭제 해주세요!&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; tf destroy
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Destroy complete! Resources: &lt;span class="m">4&lt;/span> destroyed.
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="하나만-더">하나만 더!&lt;/h2>
&lt;p>참고로 지금 우리가 사용한 pem 파일은 로컬 폴더의 &lt;code>terraform.tfstate&lt;/code>에 저장되어 있어서 언제든지 파일로 생성할 수 있는 상태므로, 이 파일은 권한이 없는 사람들이 접근할 수 없도록 관리되어야 합니다. 만약 이 파일에서 pem 파일을 생성하고 싶지 않다면, 별도로 파일을 생성한 뒤에 생성된 파일을 Terraform 코드를 통해 주입하는 방법이 있습니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; ssh-keygen -t rsa -b &lt;span class="m">4096&lt;/span> -f ~/.ssh/ec2_example
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Generating public/private rsa key pair.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Enter passphrase &lt;span class="o">(&lt;/span>empty &lt;span class="k">for&lt;/span> no passphrase&lt;span class="o">)&lt;/span>:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Enter same passphrase again:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Your identification has been saved in /Users/onlifecoding/.ssh/ec2_example
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>보안을 위해 passphrase에 원하는 암호를 설정할 수 있으며, 암호를 입력하고 싶지 않은 경우는 그냥 엔터를 누르면 됩니다. 그리고 생성된 파일을 Terraform코드에서 참조하도록 설정합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-terraform" data-lang="terraform">&lt;span class="line">&lt;span class="cl">&lt;span class="kr">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_key_pair&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;ssh&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">key_name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;terraform-example&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">public_key&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">file&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;~/.ssh/ec2_example.pub&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>이렇게 하면 Terraform의 상태에 키 값을 저장하지 않고도 Terraform 코드를 통해 키 값을 주입할 수 있습니다. 상황에 맞게 적절한 방법을 사용하면 되겠죠!&lt;/p>
&lt;h1 id="마치며">마치며&lt;/h1>
&lt;p>사실 Terraform에서 제일 중요한 걸 한 가지 꼽아보자면, Terraform의 상태를 잘 관리하는 겁니다. 지금까지는 Terraform 상태에 대한 고려 없이 그냥 진행했고, 상태는 로컬의 &lt;code>terraform.tfstate&lt;/code>파일에 저장되어 있습니다. 다음에는 Terraform의 상태를 어떻게 관리하면 좋을지 살펴보겠습니다.&lt;/p>
&lt;h1 id="참고자료">참고자료&lt;/h1>
&lt;ul>
&lt;li>&lt;a href="https://www.terraformupandrunning.com/">Terraform Up and Running, 3rd Edition&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://ercanermis.com/creating-ssh-keys-for-secure-access-to-aws-ec2-instances-with-terraform/">Creating SSH Keys for Secure Access to AWS EC2 Instances with Terraform&lt;/a>&lt;/li>
&lt;/ul>
&lt;h1 id="license">License&lt;/h1>
&lt;p>&lt;a href="https://creativecommons.org/licenses/by-nc-nd/2.0/kr/">저작자표시-비영리-변경금지 2.0 대한민국 (CC BY-NC-ND 2.0 KR)&lt;/a>&lt;/p></content></item><item><title>How to Terraform(1) - 테라폼과의 가벼운(?) 첫 만남</title><link>https://netscout.github.io/posts/how-to-terraform-1/</link><pubDate>Wed, 15 Mar 2023 09:00:00 +0900</pubDate><guid>https://netscout.github.io/posts/how-to-terraform-1/</guid><description>Terraform은 DevOps의 필수 구성 요소로 자리 잡고 있습니다. Terraform을 통해 서비스를 지탱하는 인프라에 대한 정의, 배포, 업데이트 그리고 삭제를 코드로 정의할 수 있으며 이러한 개념을 IaC(infrastructure as code)라고 합니다.</description><content>&lt;h2 id="terraform이란">Terraform이란?&lt;/h2>
&lt;p>Terraform은 DevOps의 필수 구성 요소로 자리 잡고 있습니다. Terraform을 통해 서비스를 지탱하는 인프라에 대한 정의, 배포, 업데이트 그리고 삭제를 코드로 정의할 수 있으며 이러한 개념을 IaC(infrastructure as code)라고 합니다.&lt;/p>
&lt;blockquote>
&lt;p>DevOps는 소프트웨어 배포를 빠르고 효율적으로 할 수 있게 해주는 프로세스, 아이디어, 테크닉을 말한다.&lt;/p>&lt;/blockquote>
&lt;p>그런데, 인프라를 코드로 작성하면 무슨 장점이 있는 걸까요?&lt;/p>
&lt;ul>
&lt;li>&lt;strong>자동화&lt;/strong>: 인프라를 코드로 작성할 수 있다면 자동화할 수 있고, 필요할 때 언제든 즉시 실행 가능합니다.&lt;/li>
&lt;li>&lt;strong>실수 방지&lt;/strong>: 자동화를 통해 수작업에서 발생하는 오류를 줄일 수 있고, 몇 번이고 반복해서 실행해도 안심할 수 있죠.&lt;/li>
&lt;li>&lt;strong>문서화&lt;/strong>: 또한 코드는 인프라에 대한 문서로 볼 수도 있습니다. 누군가의 머리 속에만 존재하지 않고, 누구나 볼 수 있는 코드에 인프라의 정보가 담기는 셈이죠.&lt;/li>
&lt;li>&lt;strong>버전 관리&lt;/strong>: 그리고 매우 큰 장점이 또 있는데요, 마치 소스 코드를 git으로 버전 관리 하듯이 인프라의 구성 역시 코드로써 버전 관리 할 수 있습니다. 뭔가 잘 못 됐을 때, 빠르게 커밋 로그를 통해 변경점을 찾을 수 있고 이전 버전으로 돌아갈 수도 있죠! 😊&lt;/li>
&lt;/ul>
&lt;p>그런데 Terraform으로 관리를 시작하면 누구나 거치는 어려움이 있습니다. 그건 바로 모든 리소스를 Terraform을 통해서만 관리해야 한다는 점입니다. Terraform으로 리소스를 만들어 놓고 나서, 나도 모르게 습관적으로 포털에 들어가서 마우스를 클릭클릭해서 설정을 변경하고 싶은 유혹에 빠집니다. 수작업을 추가하는 순간 Terraform의 상태 관리에서 벗어나기 시작하므로 피치 못할 사정이 아니면 Terraform을 통해서 상태를 변경해야 합니다.&lt;/p>
&lt;blockquote>
&lt;p>오래된 습관은 아주 무섭습니다. 문제를 해결하려다 보면 저도 모르게 포털에 들어가서 설정을 바꾸곤 합니다&amp;hellip;😅&lt;/p>&lt;/blockquote>
&lt;h2 id="terraform-설치하기">Terraform 설치하기&lt;/h2>
&lt;p>Terraform을 설치하는 방법은 여려가지가 있지만, 저는 &lt;code>tfenv&lt;/code>를 추천합니다. &lt;code>tfenv&lt;/code>는 Terraform의 버전을 관리해주는 도구로, 여러 버전의 Terraform을 설치하고 각각의 버전을 쉽게 전환할 수 있습니다. 예를 들어 1.4.0 버전의 Terraform을 사용하던 중에 1.5.0이 출시되었다고 해보죠. 1.5.0을 사용해보다가 뭔가 문제가 있어서 다시 1.4.0으로 돌아오고 싶을 수도 있습니다. 그런 경우에 1.4.0을 삭제하고 1.5.0을 설치하고&amp;hellip; 다시 1.5.0을 삭제하고 1.4.0을 설치하고&amp;hellip; 하는 번거로운 작업을 해야 하지만, &lt;code>tfenv&lt;/code>를 사용하면 여러 버전을 동시에 설치하고 각각의 버전을 쉽게 전환할 수 있습니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># tfenv 설치&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt; brew install tfenv
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 설치 가능한 버전 목록 확인하기&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt; tfenv list-remote
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">1.7.0-alpha20231025
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">1.6.2
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">1.6.1
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">1.6.0
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">1.6.0-rc1
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">1.6.0-beta3
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">1.6.0-beta2
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">1.6.0-beta1
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">1.6.0-alpha20230816
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">1.6.0-alpha20230802
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">1.6.0-alpha20230719
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">1.5.7
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">1.5.6
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 현재 설치된 버전 확인(terraform을 alias인 tf로 등록해서 사용하고 있습니다.)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt; tf version
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Terraform v1.5.3
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">on darwin_arm64
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Your version of Terraform is out of date! The latest version
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">is 1.6.2. You can update by downloading from https://www.terraform.io/downloads.html
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 1.6.2 버전 설치하기&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt; tfenv install 1.6.2
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Installing Terraform v1.6.2
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Installation of terraform v1.6.2 successful. To make this your default version, run &lt;span class="s1">&amp;#39;tfenv use 1.6.2&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 1.6.2 버전으로 전환하기&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt; tfenv use 1.6.2
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 현재 설치된 버전 확인하기&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt; tf version
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Terraform v1.6.2
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">on darwin_arm64
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>&lt;code>terraform&lt;/code>이라고 매번 입력하는게 어려우니 .zshrc나 .bashrc에 다음과 같이 alias 설정을 해서 &lt;code>tf&lt;/code>로 사용하는 것도 방법입니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">alias tf=terraform
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/blockquote>
&lt;blockquote>
&lt;p>terraform 1.0 부터는 &lt;a href="https://developer.hashicorp.com/terraform/language/v1-compatibility-promises">v1-compatibility-promises&lt;/a>가 적용되는데요, 1.0 부터 향후 출시될 1.x 버전까지는 코드 변경 없이 동작한다는 걸 보장합니다. 따라서 1.x 버전에서는 최신 버전을 사용하지 않을 이유가 없을지도&amp;hellip;?&lt;/p>&lt;/blockquote>
&lt;h2 id="aws-iam-사용자-생성하기">AWS IAM 사용자 생성하기&lt;/h2>
&lt;p>Terraform이 AWS의 리소스를 관리하기 위해서는 Terraform이 사용할 수 있는 AWS IAM 사용자가 필요합니다. AWS IAM 사용자를 생성하고 Terraform이 사용할 수 있는 권한을 부여해보겠습니다.&lt;/p>
&lt;h3 id="iam-사용자-생성하기">IAM 사용자 생성하기&lt;/h3>
&lt;p>먼저 AWS 계정이 필요하겠죠? 계정을 생성하고 로그인하면 AWS 콘솔에 접속할 수 있습니다. AWS 콘솔에서 IAM을 검색하고 IAM을 선택합니다.&lt;/p>
&lt;p align="center">&lt;img src="./01.png">&lt;/p>
&lt;p>좌측의 &lt;code>엑세스 관리&lt;/code> &amp;gt; &lt;code>사용자&lt;/code> &amp;gt; &lt;code>사용자 생성&lt;/code>을 클릭합니다. 이어지는 단계에서 사용자 이름을 입력하고 다음으로 이동합니다.&lt;/p>
&lt;p align="center">&lt;img src="./02.png">&lt;/p>
&lt;p>우선 &lt;code>사용자 그룹 생성&lt;/code>을 눌러 사용자 그룹의 이름을 설정하고 &lt;code>권한 정책&lt;/code>에서는 일단 모든 AWS 리소스에 대한 권한을 가지는 &lt;code>AdministratorAccess&lt;/code>를 선택하고 &lt;code>사용자 그룹 생성&lt;/code>을 누릅니다.&lt;/p>
&lt;p align="center">&lt;img src="./03.png">&lt;/p>
&lt;blockquote>
&lt;p>전체 권한이 부여된 계정이 잘못 사용되면 큰 문제를 일으킬 수 있으므로 필요한 권한만을 부여하는 게 좋습니다. 필요한 만큼 권한을 부여하는 방법에 대해서는 추후 다시 설명하겠습니다.&lt;/p>&lt;/blockquote>
&lt;p>사용자 그룹이 생성되면 다음과 같이 생성된 그룹을 선택하고 &lt;code>다음&lt;/code>을 누릅니다.&lt;/p>
&lt;p align="center">&lt;img src="./04.png">&lt;/p>
&lt;p>그리고 마지막으로 &lt;code>검토 및 생성&lt;/code>단계에서 사용자 정보를 확인하고 &lt;code>사용자 생성&lt;/code>을 누릅니다. 이제 사용자 목록에서 생성된 사용자를 확인할 수 있습니다.&lt;/p>
&lt;p align="center">&lt;img src="./05.png">&lt;/p>
&lt;p>사용자 이름을 눌러 세부 정보 페이지로 이동하고 우측 상단의 &lt;code>액세스 키 만들기&lt;/code>를 클릭하고, 목록에서 &lt;code>Command Line Interface(CLI)&lt;/code>를 선택하고 &lt;code>다음&lt;/code>을 누릅니다.&lt;/p>
&lt;p align="center">&lt;img src="./06.png">&lt;/p>
&lt;p>&lt;code>설명 태그 설정&lt;/code>에서 태그 이름을 작성(ex: Terraform-Access)하고 &lt;code>액세스 키 만들기&lt;/code>를 누릅니다. 이제 액세스 키 ID와 비밀 액세스 키를 확인할 수 있습니다.&lt;/p>
&lt;p align="center">&lt;img src="./07.png">&lt;/p>
&lt;p>비밀 액세스 키를 잃어버리면 다시 발급해야 하므로 잘 보관해두시기 바랍니다.&lt;/p>
&lt;h2 id="terraform-계정-정보-설정하기">Terraform 계정 정보 설정하기&lt;/h2>
&lt;p>앞서 Terraform이 사용할 계정을 생성하고 해당 계정의 액세스 키도 생성을 마쳤습니다. 이제 Terraform이 해당 계정을 사용할 수 있도록 환경 변수에 계정 정보를 설정해보겠습니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># zsh을 사용하는 경우&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt; vi ~/.zshrc
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># bash를 사용하는 경우&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt; vi ~/.bashrc
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>그리고 다음과 같이 환경 변수를 설정합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">export&lt;/span> &lt;span class="nv">AWS_ACCESS_KEY_ID&lt;/span>&lt;span class="o">={&lt;/span>액세스 ID&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">export&lt;/span> &lt;span class="nv">AWS_SECRET_ACCESS_KEY&lt;/span>&lt;span class="o">={&lt;/span>비밀 액세스 키&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>참고로 vi로 파일을 열고 &lt;code>i&lt;/code>를 누르면 편집 모드로 전환되고, &lt;code>esc&lt;/code>를 누르면 편집 모드에서 빠져나올 수 있습니다. &lt;code>:wq&lt;/code>를 입력하면 저장하고 빠져나올 수 있습니다.
그리고 환경 변수를 설정한 후에는 &lt;code>source ~/.zshrc&lt;/code> 또는 &lt;code>source ~/.bashrc&lt;/code>를 입력해서 환경 변수를 적용할 수 있습니다.&lt;/p>&lt;/blockquote>
&lt;p>다음 명령어를 통해서 환경 변수가 잘 설정되었는지 확인할 수 있습니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; &lt;span class="nb">echo&lt;/span> &lt;span class="nv">$AWS_ACCESS_KEY_ID&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">{&lt;/span>액세스 ID&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="첫-terraform-코드-작성하기">첫 Terraform 코드 작성하기&lt;/h2>
&lt;p>이제 Terraform을 사용할 준비가 끝났습니다. 터미널을 열고 다음과 같이 작업할 공간을 생성합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">~/src
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt; mkdir how-to-terraform
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">~/src
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt; &lt;span class="nb">cd&lt;/span> how-to-terraform
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">~/src/how-to-terraform
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt; code .
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>이 시리즈에서는 Visual Studio Code를 사용합니다.&lt;/p>&lt;/blockquote>
&lt;p>에디터에서 &lt;code>chapter01&lt;/code> 폴더를 생성하고 폴더 안에 &lt;code>main.tf&lt;/code> 파일을 생성합니다. 그리고 다음과 같이 코드를 작성합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-terraform" data-lang="terraform">&lt;span class="line">&lt;span class="cl">&lt;span class="kr">provider&lt;/span> &lt;span class="s2">&amp;#34;aws&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // 아시아 태평양(서울) 리전
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">region&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ap-northeast-2&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_instance&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;example&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // ap-northeast-2 리전의 Ubuntu 20.04 AMI
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">ami&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ami-0c6e5afdd23291f73&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">instance_type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;t2.micro&amp;#34;&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // 최초 인스턴스 생성 시에만 실행
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">user_data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;-EOF&lt;/span>&lt;span class="s">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> #!/bin/bash
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> echo &amp;#34;Hello, World&amp;#34; &amp;gt; index.html
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> nohup busybox httpd -f -p 8080 &amp;amp;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> &lt;/span>&lt;span class="o">EOF&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">tags&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">Name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;terraform-example&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>AWS에서 제공하는 프로바이더를 선언하였고, AWS의 ap-northeast-2(서울)리전을 대상으로 Terraform 코드를 실행하도록 설정하였습니다. 그리고 Ubuntu 20.04로 동작하는 EC2 인스턴스를 하나 생성하였습니다. 그리고 최초 인스턴스가 생성 될 때 &lt;code>user_data&lt;/code>에 지정한 스크립트가 실행되면서 웹에서 접속하면 &lt;code>Hello, World&lt;/code>를 출력하는 웹 서버가 실행되도록 설정하였습니다.&lt;/p>
&lt;h2 id="terraform-초기화-및-실행-계획-확인하기">Terraform 초기화 및 실행 계획 확인하기&lt;/h2>
&lt;p>&lt;code>main.tf&lt;/code> 파일에 우클릭하고 &lt;code>통합 터미널에서 열기&lt;/code>를 선택하여 &lt;code>main.tf&lt;/code>파일이 위치한 경로에서 터미널을 실행합니다.&lt;/p>
&lt;p align="center">&lt;img src="./08.png">&lt;/p>
&lt;p>그리고 다음과 같이 Terraform을 초기화합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; tf init
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Initializing the backend...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Initializing provider plugins...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">- Finding latest version of hashicorp/aws...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">- Installing hashicorp/aws v5.23.1...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">- Installed hashicorp/aws v5.23.1 &lt;span class="o">(&lt;/span>signed by HashiCorp&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Terraform has created a lock file .terraform.lock.hcl to record the provider
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">selections it made above. Include this file in your version control repository
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">so that Terraform can guarantee to make the same selections by default when
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">you run &lt;span class="s2">&amp;#34;terraform init&amp;#34;&lt;/span> in the future.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Terraform has been successfully initialized!
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">You may now begin working with Terraform. Try running &lt;span class="s2">&amp;#34;terraform plan&amp;#34;&lt;/span> to see
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">any changes that are required &lt;span class="k">for&lt;/span> your infrastructure. All Terraform commands
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">should now work.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">If you ever &lt;span class="nb">set&lt;/span> or change modules or backend configuration &lt;span class="k">for&lt;/span> Terraform,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">rerun this &lt;span class="nb">command&lt;/span> to reinitialize your working directory. If you forget, other
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">commands will detect it and remind you to &lt;span class="k">do&lt;/span> so &lt;span class="k">if&lt;/span> necessary.
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>AWS 프로바이더 5.23.1 버전이 설치되었고, Terraform이 정상적으로 초기화 되었음을 알 수 있습니다. 그렇다면, 이제 Terraform 코드로 인프라가 어떻게 구성될지 미리 살펴볼까요?&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; tf plan
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Terraform used the selected providers to generate the following execution plan. Resource
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">actions are indicated with the following symbols:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + create
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Terraform will perform the following actions:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># aws_instance.example will be created&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + resource &lt;span class="s2">&amp;#34;aws_instance&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;example&amp;#34;&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">ami&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ami-0c6e5afdd23291f73&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">arn&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">associate_public_ip_address&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">availability_zone&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">cpu_core_count&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">cpu_threads_per_core&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">disable_api_stop&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">disable_api_termination&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">ebs_optimized&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">get_password_data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">false&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">host_id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">host_resource_group_arn&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">iam_instance_profile&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">instance_initiated_shutdown_behavior&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">instance_lifecycle&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">instance_state&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">instance_type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;t2.micro&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">ipv6_address_count&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">ipv6_addresses&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">key_name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">monitoring&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">outpost_arn&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">password_data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">placement_group&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">placement_partition_number&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">primary_network_interface_id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">private_dns&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">private_ip&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">public_dns&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">public_ip&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">secondary_private_ips&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">security_groups&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">source_dest_check&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">spot_instance_request_id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">subnet_id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">tags&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="s2">&amp;#34;Name&amp;#34;&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;terraform-example&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">tags_all&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="s2">&amp;#34;Name&amp;#34;&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;terraform-example&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">tenancy&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">user_data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;c765373c563b260626d113c4a56a46e8a8c5ca33&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">user_data_base64&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">user_data_replace_on_change&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">false&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">vpc_security_group_ids&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Plan: &lt;span class="m">1&lt;/span> to add, &lt;span class="m">0&lt;/span> to change, &lt;span class="m">0&lt;/span> to destroy.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">──────────────────────────────────────────────────────────────────────────────────────────────
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Note: You didn&lt;span class="s1">&amp;#39;t use the -out option to save this plan, so Terraform can&amp;#39;&lt;/span>t guarantee to take
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">exactly these actions &lt;span class="k">if&lt;/span> you run &lt;span class="s2">&amp;#34;terraform apply&amp;#34;&lt;/span> now.
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>tf plan&lt;/code>명령을 실행하면 Terraform이 현재 인프라의 상태와 코드에 정의된 인프라를 비교해서 어떻게 인프라에 반영할 것인지 미리 확인해볼 수 있습니다. 추가될 요소는 앞에 &lt;code>+&lt;/code>가 붙고 삭제된 요소는 앞에 &lt;code>-&lt;/code>가 붙습니다. 그리고 코드에서 지정해준 인스턴스의 ami, instance_type, user_data 등을 제외하면 모두 &lt;code>known after apply&lt;/code>라고 표시되어 있습니다. 이런 정보는 인스턴스가 실제로 생성되고 나서 확인할 수 있다는 의미입니다.&lt;/p>
&lt;p>이렇게 코드가 반영되면 어떻게 인프라가 변경될지 미리 상세하게 확인해볼 수 있구요, 맨 마지막 줄에는 요약 정보가 표시됩니다. 코드의 실행 게획을 미리 짜본 결과 1개의 리소스가 추가되고, 변경될 리소스는 0개, 삭제될 리소스 역시 0개라고 합니다. Terraform 코드를 처음 실행하는 거니까 당연한 결과겠죠?&lt;/p>
&lt;h2 id="terraform-코드-실행하기">Terraform 코드 실행하기&lt;/h2>
&lt;p>실행 계획을 확인해보고 문제가 없으면 코드를 실행해서 인프라를 변경할 수 있습니다. 다음과 같이 &lt;code>tf apply&lt;/code>를 입력하면 코드가 실행되고 인프라가 변경됩니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; tf apply
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Terraform used the selected providers to generate the following execution plan. Resource
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">actions are indicated with the following symbols:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + create
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Terraform will perform the following actions:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># aws_instance.example will be created&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + resource &lt;span class="s2">&amp;#34;aws_instance&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;example&amp;#34;&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">ami&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ami-0c6e5afdd23291f73&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">arn&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">associate_public_ip_address&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">availability_zone&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">cpu_core_count&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">cpu_threads_per_core&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">disable_api_stop&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">disable_api_termination&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">ebs_optimized&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">get_password_data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">false&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">host_id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">host_resource_group_arn&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">iam_instance_profile&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">instance_initiated_shutdown_behavior&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">instance_lifecycle&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">instance_state&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">instance_type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;t2.micro&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">ipv6_address_count&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">ipv6_addresses&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">key_name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">monitoring&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">outpost_arn&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">password_data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">placement_group&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">placement_partition_number&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">primary_network_interface_id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">private_dns&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">private_ip&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">public_dns&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">public_ip&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">secondary_private_ips&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">security_groups&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">source_dest_check&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">spot_instance_request_id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">subnet_id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">tags&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="s2">&amp;#34;Name&amp;#34;&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;terraform-example&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">tags_all&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="s2">&amp;#34;Name&amp;#34;&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;terraform-example&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">tenancy&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">user_data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;c765373c563b260626d113c4a56a46e8a8c5ca33&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">user_data_base64&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">user_data_replace_on_change&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">false&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">vpc_security_group_ids&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Plan: &lt;span class="m">1&lt;/span> to add, &lt;span class="m">0&lt;/span> to change, &lt;span class="m">0&lt;/span> to destroy.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Do you want to perform these actions?
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> Terraform will perform the actions described above.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> Only &lt;span class="s1">&amp;#39;yes&amp;#39;&lt;/span> will be accepted to approve.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> Enter a value:
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>코드를 실행하면 앞서 확인한 것 처럼 실행 계획을 한 번 더 확인합니다. 그리고 정말 이 코드를 실행하려면 &lt;code>yes&lt;/code>를 입력하라고 합니다. &lt;code>yes&lt;/code>이외의 값을 입력하면 코드 실행이 취소됩니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">aws_instance.example: Creating...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">aws_instance.example: Still creating... &lt;span class="o">[&lt;/span>10s elapsed&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">aws_instance.example: Still creating... &lt;span class="o">[&lt;/span>20s elapsed&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">aws_instance.example: Creation &lt;span class="nb">complete&lt;/span> after 22s &lt;span class="o">[&lt;/span>&lt;span class="nv">id&lt;/span>&lt;span class="o">=&lt;/span>i-00229af6743e0ba4b&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Apply complete! Resources: &lt;span class="m">1&lt;/span> added, &lt;span class="m">0&lt;/span> changed, &lt;span class="m">0&lt;/span> destroyed.
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>참고로 실행 계획을 생성할 때, 실행 계획을 파일로 출력하여 코드를 실행할 때 실행 계획대로 바로 실행되도록 할 수도 있습니다. &lt;code>tf plan -out plan.out&lt;/code>을 입력하면 실행 계획이 &lt;code>plan.out&lt;/code> 파일로 저장되고, &lt;code>tf apply plan.out&lt;/code>을 입력하면 &lt;code>plan.out&lt;/code> 파일에 저장된 실행 계획대로 코드가 실행됩니다.&lt;/p>&lt;/blockquote>
&lt;p>코드 실행 결과로 1개의 리소스가 생성되었습니다. 포털에서 EC2로 검색하여 EC2 포털로 들어가면 &lt;code>인스턴스(실행 중)&lt;/code> 항목이 &lt;code>1&lt;/code>인 걸 확인할 수 있으며, 해당 항목을 누르면 실행 중인 EC2를 확인할 수 있습니다.&lt;/p>
&lt;p align="center">&lt;img src="./09.png">&lt;/p>
&lt;p>인스턴스 ID를 눌러 상세 페이지로 들어가면 우측 상단에서 &lt;code>퍼블릭 IPv4 주소&lt;/code>, &lt;code>퍼블릭 IPv4 DNS&lt;/code> 등을 확인할 수 있지만, 해당 주소로 접속은 불가합니다.&lt;/p>
&lt;p>&lt;code>main.tf&lt;/code> 코드에 다음 항목을 추가해서 외부에서의 접속을 허용합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-terraform" data-lang="terraform">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// AWS 프로바이더 설정
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">provider&lt;/span> &lt;span class="s2">&amp;#34;aws&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // 아시아 태평양(서울) 리전
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">region&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ap-northeast-2&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_instance&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;example&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // ap-northeast-2 리전의 Ubuntu 20.04 AMI
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">ami&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ami-0c6e5afdd23291f73&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">instance_type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;t2.micro&amp;#34;&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // 외부에서 접속을 허용하기 위한 설정
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">vpc_security_group_ids&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="nx">aws_security_group&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">example&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">id&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // 최초 인스턴스 생성 시에만 실행
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">user_data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;-EOF&lt;/span>&lt;span class="s">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> #!/bin/bash
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> echo &amp;#34;Hello, World&amp;#34; &amp;gt; index.html
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> nohup busybox httpd -f -p 8080 &amp;amp;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s"> &lt;/span>&lt;span class="o">EOF&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">tags&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">Name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;terraform-example&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 인바운드 규칙을 설정하기 위한 보안 그룹
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_security_group&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;example&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;terraform-example&amp;#34;&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> // 인바운드 규칙
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">ingress&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">from_port&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">8080&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">to_port&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">8080&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">protocol&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;tcp&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">cidr_blocks&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;0.0.0.0/0&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>다시 실행 계획을 확인해봅니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; tf plan
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">aws_instance.example: Refreshing state... &lt;span class="o">[&lt;/span>&lt;span class="nv">id&lt;/span>&lt;span class="o">=&lt;/span>i-00229af6743e0ba4b&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Terraform used the selected providers to generate the following execution plan. Resource
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">actions are indicated with the following symbols:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + create
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ~ update in-place
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Terraform will perform the following actions:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># aws_instance.example will be updated in-place&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ~ resource &lt;span class="s2">&amp;#34;aws_instance&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;example&amp;#34;&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;i-00229af6743e0ba4b&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">tags&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;Name&amp;#34;&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;terraform-example&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ~ &lt;span class="nv">vpc_security_group_ids&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="s2">&amp;#34;sg-0908fdbf1d8c6156e&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">]&lt;/span> -&amp;gt; &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># (31 unchanged attributes hidden)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># (8 unchanged blocks hidden)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># aws_security_group.example will be created&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + resource &lt;span class="s2">&amp;#34;aws_security_group&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;example&amp;#34;&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">arn&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">description&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;Managed by Terraform&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">egress&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">ingress&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">cidr_blocks&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="s2">&amp;#34;0.0.0.0/0&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">description&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">from_port&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">8080&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">ipv6_cidr_blocks&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">prefix_list_ids&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">protocol&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;tcp&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">security_groups&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">self&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">false&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">to_port&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">8080&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;terraform-example&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">name_prefix&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">owner_id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">revoke_rules_on_delete&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">false&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">tags_all&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> + &lt;span class="nv">vpc_id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>known after apply&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Plan: &lt;span class="m">1&lt;/span> to add, &lt;span class="m">1&lt;/span> to change, &lt;span class="m">0&lt;/span> to destroy.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">──────────────────────────────────────────────────────────────────────────────────────────────
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Note: You didn&lt;span class="s1">&amp;#39;t use the -out option to save this plan, so Terraform can&amp;#39;&lt;/span>t guarantee to take
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">exactly these actions &lt;span class="k">if&lt;/span> you run &lt;span class="s2">&amp;#34;terraform apply&amp;#34;&lt;/span> now.
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>새로운 리소스(시큐리티 그룹)이 추가되고 시큐리티 그룹을 통해 외부에서의 접속을 허용하도록 EC2 인스턴스가 변경되는 것을 확인할 수 있습니다. 이제 코드를 실행합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; tf apply
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">aws_security_group.example: Creating...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">aws_security_group.example: Creation &lt;span class="nb">complete&lt;/span> after 1s &lt;span class="o">[&lt;/span>&lt;span class="nv">id&lt;/span>&lt;span class="o">=&lt;/span>sg-057069d47b3e7f650&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">aws_instance.example: Modifying... &lt;span class="o">[&lt;/span>&lt;span class="nv">id&lt;/span>&lt;span class="o">=&lt;/span>i-00229af6743e0ba4b&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">aws_instance.example: Modifications &lt;span class="nb">complete&lt;/span> after 2s &lt;span class="o">[&lt;/span>&lt;span class="nv">id&lt;/span>&lt;span class="o">=&lt;/span>i-00229af6743e0ba4b&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Apply complete! Resources: &lt;span class="m">1&lt;/span> added, &lt;span class="m">1&lt;/span> changed, &lt;span class="m">0&lt;/span> destroyed.
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>이제 다시 &lt;code>퍼블릭 IPv4 주소&lt;/code>, &lt;code>퍼블릭 IPv4 DNS&lt;/code>를 통해 8080번 포트로 접속하면 &lt;code>Hello, World&lt;/code>를 확인할 수 있습니다.&lt;/p>
&lt;p align="center">&lt;img src="./10.png">&lt;/p>
&lt;h2 id="리소스-삭제하기">리소스 삭제하기&lt;/h2>
&lt;p>Terraform 코드로 생성된 리소스는 &lt;code>destroy&lt;/code> 명령어로 일괄 삭제할 수 있다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; tf destroy
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">aws_security_group.example: Refreshing state... &lt;span class="o">[&lt;/span>&lt;span class="nv">id&lt;/span>&lt;span class="o">=&lt;/span>sg-057069d47b3e7f650&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">aws_instance.example: Refreshing state... &lt;span class="o">[&lt;/span>&lt;span class="nv">id&lt;/span>&lt;span class="o">=&lt;/span>i-00229af6743e0ba4b&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Terraform used the selected providers to generate the following execution plan. Resource
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">actions are indicated with the following symbols:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - destroy
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Terraform will perform the following actions:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># aws_instance.example will be destroyed&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - resource &lt;span class="s2">&amp;#34;aws_instance&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;example&amp;#34;&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">ami&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ami-0c6e5afdd23291f73&amp;#34;&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">arn&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;arn:aws:ec2:ap-northeast-2:246181472423:instance/i-00229af6743e0ba4b&amp;#34;&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">associate_public_ip_address&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">true&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">availability_zone&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ap-northeast-2c&amp;#34;&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">cpu_core_count&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">1&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">cpu_threads_per_core&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">1&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">disable_api_stop&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">false&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">disable_api_termination&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">false&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">ebs_optimized&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">false&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">get_password_data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">false&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">hibernation&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">false&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;i-00229af6743e0ba4b&amp;#34;&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">instance_initiated_shutdown_behavior&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;stop&amp;#34;&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">instance_state&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;running&amp;#34;&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">instance_type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;t2.micro&amp;#34;&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">ipv6_address_count&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">0&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">ipv6_addresses&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">[]&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">monitoring&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">false&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">placement_partition_number&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">0&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">primary_network_interface_id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;eni-06474393b32e2d8fc&amp;#34;&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">private_dns&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ip-172-31-45-210.ap-northeast-2.compute.internal&amp;#34;&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">private_ip&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;172.31.45.210&amp;#34;&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">public_dns&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ec2-3-39-10-27.ap-northeast-2.compute.amazonaws.com&amp;#34;&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">public_ip&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;3.39.10.27&amp;#34;&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">secondary_private_ips&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">[]&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">security_groups&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="s2">&amp;#34;terraform-example&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">]&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">source_dest_check&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">true&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">subnet_id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;subnet-03d036291a1b8a65a&amp;#34;&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">tags&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="s2">&amp;#34;Name&amp;#34;&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;terraform-example&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">tags_all&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="s2">&amp;#34;Name&amp;#34;&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;terraform-example&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">tenancy&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;default&amp;#34;&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">user_data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;c765373c563b260626d113c4a56a46e8a8c5ca33&amp;#34;&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">user_data_replace_on_change&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">false&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">vpc_security_group_ids&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="s2">&amp;#34;sg-057069d47b3e7f650&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">]&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - capacity_reservation_specification &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">capacity_reservation_preference&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;open&amp;#34;&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - cpu_options &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">core_count&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">1&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">threads_per_core&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">1&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - credit_specification &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">cpu_credits&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;standard&amp;#34;&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - enclave_options &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">enabled&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">false&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - maintenance_options &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">auto_recovery&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;default&amp;#34;&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - metadata_options &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">http_endpoint&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;enabled&amp;#34;&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">http_protocol_ipv6&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;disabled&amp;#34;&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">http_put_response_hop_limit&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">1&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">http_tokens&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;optional&amp;#34;&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">instance_metadata_tags&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;disabled&amp;#34;&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - private_dns_name_options &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">enable_resource_name_dns_a_record&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">false&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">enable_resource_name_dns_aaaa_record&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">false&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">hostname_type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ip-name&amp;#34;&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - root_block_device &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">delete_on_termination&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">true&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">device_name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;/dev/sda1&amp;#34;&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">encrypted&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">false&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">iops&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">100&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">tags&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">{}&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">throughput&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">0&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">volume_id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;vol-0f74f2dbc1d7880c1&amp;#34;&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">volume_size&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">8&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">volume_type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;gp2&amp;#34;&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># aws_security_group.example will be destroyed&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - resource &lt;span class="s2">&amp;#34;aws_security_group&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;example&amp;#34;&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">arn&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;arn:aws:ec2:ap-northeast-2:246181472423:security-group/sg-057069d47b3e7f650&amp;#34;&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">description&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;Managed by Terraform&amp;#34;&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">egress&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">[]&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;sg-057069d47b3e7f650&amp;#34;&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">ingress&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">cidr_blocks&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="s2">&amp;#34;0.0.0.0/0&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">description&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">from_port&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">8080&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">ipv6_cidr_blocks&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">prefix_list_ids&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">protocol&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;tcp&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">security_groups&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">self&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">false&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">to_port&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">8080&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">]&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;terraform-example&amp;#34;&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">owner_id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;246181472423&amp;#34;&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">revoke_rules_on_delete&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">false&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">tags&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">{}&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">tags_all&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">{}&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - &lt;span class="nv">vpc_id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;vpc-089687c07f7572271&amp;#34;&lt;/span> -&amp;gt; null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Plan: &lt;span class="m">0&lt;/span> to add, &lt;span class="m">0&lt;/span> to change, &lt;span class="m">2&lt;/span> to destroy.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Do you really want to destroy all resources?
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> Terraform will destroy all your managed infrastructure, as shown above.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> There is no undo. Only &lt;span class="s1">&amp;#39;yes&amp;#39;&lt;/span> will be accepted to confirm.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> Enter a value: yes
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">aws_instance.example: Destroying... &lt;span class="o">[&lt;/span>&lt;span class="nv">id&lt;/span>&lt;span class="o">=&lt;/span>i-00229af6743e0ba4b&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">aws_instance.example: Still destroying... &lt;span class="o">[&lt;/span>&lt;span class="nv">id&lt;/span>&lt;span class="o">=&lt;/span>i-00229af6743e0ba4b, 10s elapsed&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">aws_instance.example: Still destroying... &lt;span class="o">[&lt;/span>&lt;span class="nv">id&lt;/span>&lt;span class="o">=&lt;/span>i-00229af6743e0ba4b, 20s elapsed&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">aws_instance.example: Destruction &lt;span class="nb">complete&lt;/span> after 30s
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">aws_security_group.example: Destroying... &lt;span class="o">[&lt;/span>&lt;span class="nv">id&lt;/span>&lt;span class="o">=&lt;/span>sg-057069d47b3e7f650&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">aws_security_group.example: Destruction &lt;span class="nb">complete&lt;/span> after 0s
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Destroy complete! Resources: &lt;span class="m">2&lt;/span> destroyed.
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>만약 특정한 리소스만 삭제하고 싶다면 &lt;code>tf destroy -target {리소스 타입}.{리소스 이름}&lt;/code>을 입력하면 됩니다.
리소스 이름을 어떻게 확인하냐구요? 좋은 질문입니다! 리소스 이름은 &lt;code>tf state list&lt;/code>를 입력하면 확인할 수 있습니다!&lt;/p>&lt;/blockquote>
&lt;h2 id="iam-권한-제한하기">IAM 권한 제한하기&lt;/h2>
&lt;p>IAM에 딱 필요한 권한 허용하려면, 우선 어떤 권한이 필요한지 알아야 합니다. 그런데&amp;hellip;. 그걸 어떻게 알 수 있을까요??&lt;/p>
&lt;p>여기서 &lt;a href="https://github.com/iann0036/iamlive">iamlive&lt;/a>이 등장할 차례입니다!&lt;/p>
&lt;p>설명보다는 iamlive 사이트에서 제공하는 예시를 한 번 보시죠.&lt;/p>
&lt;p>&lt;img src="https://raw.githubusercontent.com/iann0036/iamlive/assets/iamlive.gif" />&lt;br />&lt;/p>
&lt;p>감이 오시나요?&lt;/p>
&lt;p>aws를 대상으로 뭔가 작업을 진행할 때, 그 작업에서 요구되는 IAM을 바로 확인할 수 있게 해줍니다!&lt;/p>
&lt;h3 id="iamlive-설정하기">iamlive 설정하기&lt;/h3>
&lt;p>iamlive는 homebrew등으로 직접 설치할 수도 있지만, 설치하지 않고 &lt;a href="https://meirg.co.il/2021/04/23/determining-aws-iam-policies-according-to-terraform-and-aws-cli/">docker를 이용하는 방법&lt;/a>도 있습니다.&lt;/p>
&lt;p>여기서는 docker를 통해 iamlive를 실행하겠습니다. 우선, docker로 해당 이미지를 실행합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; docker run &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> -p 80:10080 &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> -p 443:10080 &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --name iamlive-test &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> -it unfor19/iamlive-docker &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --mode proxy &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --bind-addr 0.0.0.0:10080 &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --force-wildcard-resource &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --output-file &lt;span class="s2">&amp;#34;/app/iamlive.log&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>처음 실행 하는 거기 때문에 이미지를 다운로드 받고 실행이 됩니다. 실행이 됐을 때 별도로 메세지가 표시되지는 않기 때문에 에러 없이 대기 상태에 있다면 정상적으로 실행된 것입니다.&lt;/p>
&lt;blockquote>
&lt;p>만약 iamlive 컨테이너를 실행 중에 ctrl+c를 눌러서 종료하면, 다음에 실행하고 싶을 때 &lt;code>docker start iamlive-test&lt;/code>를 입력하면 됩니다. 그리고 &lt;code>docker attach iamlive-test&lt;/code>를 입력하면 실행 중인 컨테이너에 접속할 수 있습니다.&lt;/p>&lt;/blockquote>
&lt;p>이제 별도로 터미널을 한 개 더 열고 다음 명령어를 실행합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; docker cp iamlive-test:/home/appuser/.iamlive ~/
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>proxy 모드로 실행되는 iamlive에 접속하기 위한 키 파일을 프로필 루트 디렉토리로 복사했습니다. 다음 명령을 통해서 제대로 복사되었는지 확인할 수 있습니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; ls ./.iamlive
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">ca.key ca.pem
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="iamlive을-통해-권한-확인하기">iamlive을 통해 권한 확인하기&lt;/h3>
&lt;p>원문에서 권장하는 방법은 권한이 하나도 없는 사용자를 만들고, 계속 명령어를 실행하면서 꼭 필요한 권한만 하나씩 복사하는 방식입니다. 그런데 이렇게 하면 필요한 권한이 많은 수록 여러번 명령을 반복적으로 실행하면서 권한을 하나씩 확인하고, 하나씩 추가해야 합니다. 꽤나 번거로운 작업이죠. 그래서 저는 그냥 어드민 권한이 있는 계정으로 테스트해서 전체 권한을 확인하고, 필요한 권한을 한 번에 할당하는 방식으로 진행하겠습니다.&lt;/p>
&lt;p>앞서 작성한 코드를 대상으로 &lt;code>terraform apply&lt;/code>를 실행하여 인프라를 배포합니다. 그리고 iamlive가 실행 중인 터미널을 잘 살펴보세요. 그러면 뭐가 막 지나가는 데 마지막 줄이 핵심입니다. 마지막 줄에는 다음과 같은 권한이 표시됩니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;Version&amp;#34;&lt;/span>: &lt;span class="s2">&amp;#34;2012-10-17&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;Statement&amp;#34;&lt;/span>: &lt;span class="o">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;Effect&amp;#34;&lt;/span>: &lt;span class="s2">&amp;#34;Allow&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;Action&amp;#34;&lt;/span>: &lt;span class="o">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;sts:GetCallerIdentity&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;ec2:CreateSecurityGroup&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;ec2:DescribeSecurityGroups&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;ec2:DescribeNetworkInterfaces&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;ec2:DeleteSecurityGroup&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;ec2:RevokeSecurityGroupEgress&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;ec2:AuthorizeSecurityGroupIngress&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;ec2:RunInstances&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;ec2:DescribeInstances&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;ec2:DescribeInstanceTypes&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;ec2:DescribeTags&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;ec2:DescribeVpcs&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;ec2:DescribeInstanceAttribute&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;ec2:DescribeVolumes&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;ec2:DescribeInstanceCreditSpecifications&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">]&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;Resource&amp;#34;&lt;/span>: &lt;span class="s2">&amp;#34;*&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>즉, 현재까지 작성된 terraform 코드를 실행해서 인프라를 구성하기 위해서는 이런 권한이 모두 필요하다는 거죠! 그럼 &lt;code>tf destroy&lt;/code>도 바로 이어서 한 번 해볼까요? 그러면 최종적으로 이런 권한이 필요하다고 합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;Version&amp;#34;&lt;/span>: &lt;span class="s2">&amp;#34;2012-10-17&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;Statement&amp;#34;&lt;/span>: &lt;span class="o">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;Effect&amp;#34;&lt;/span>: &lt;span class="s2">&amp;#34;Allow&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;Action&amp;#34;&lt;/span>: &lt;span class="o">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;sts:GetCallerIdentity&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;ec2:CreateSecurityGroup&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;ec2:DescribeSecurityGroups&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;ec2:DescribeNetworkInterfaces&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;ec2:DeleteSecurityGroup&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;ec2:RevokeSecurityGroupEgress&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;ec2:AuthorizeSecurityGroupIngress&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;ec2:RunInstances&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;ec2:DescribeInstances&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;ec2:DescribeInstanceTypes&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;ec2:DescribeTags&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;ec2:DescribeVpcs&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;ec2:DescribeInstanceAttribute&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;ec2:DescribeVolumes&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;ec2:DescribeInstanceCreditSpecifications&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;ec2:ModifyInstanceAttribute&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;ec2:TerminateInstances&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">]&lt;/span>,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;Resource&amp;#34;&lt;/span>: &lt;span class="s2">&amp;#34;*&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>이렇게 이쁘게 표시되지는 않습니다만&amp;hellip; &lt;a href="https://jsonformatter.org/json-pretty-print">JSON Formatter&lt;/a>등의 사이트를 통해 이쁘게 변환하시면 됩니다!&lt;/p>&lt;/blockquote>
&lt;p>네, 그럼 새로운 사용자를 만들어서 이 권한을 부여하겠습니다. 앞서 계정을 생성했던 것과 동일한 절차로 사용자 계정을 새로 생성합니다. 사용자 이름과 그룹 이름은 &lt;code>terraform-user&lt;/code>로 설정하고, &lt;code>그룹에는 아무런 권한을 주지 않습니다!&lt;/code>&lt;/p>
&lt;p>&lt;code>다시 한번 말씀드리면 그룹에는 아무런 권한을 주지 마세요!&lt;/code>&lt;/p>
&lt;blockquote>
&lt;p>혹시 잊으실까봐 그러는데, 액세스 키와 비밀 액세스 키는 따로 저장해두셔야 합니다.&lt;/p>&lt;/blockquote>
&lt;p>자 그럼 그룹 설정에서 &lt;code>권한&lt;/code>탭을 확인합니다. 현재 아무런 권한이 없는데요, 여기서 &lt;code>권한 추가&lt;/code> -&amp;gt; &lt;code>인라인 정책 생성&lt;/code>을 선택합니다.&lt;/p>
&lt;p align="center">&lt;img src="./11.png">&lt;/p>
&lt;p>그리고 &lt;code>권한 지정&lt;/code> 페이지에서 &lt;code>JSON&lt;/code>탭을 선택하고, 앞서 iamlive에서 확인한 권한을 복사해서 붙여넣습니다.&lt;/p>
&lt;p align="center">&lt;img src="./12.png">&lt;/p>
&lt;p>그리고 &lt;code>다음&lt;/code>을 선택하고,&lt;/p>
&lt;p align="center">&lt;img src="./13.png">&lt;/p>
&lt;p>&lt;code>정책 이름&lt;/code>을 &lt;code>terraform-user&lt;/code>로 설정하고, &lt;code>정책 생성&lt;/code>을 선택합니다. &lt;code>정책 생성&lt;/code> 또는 &lt;code>변경 사항 저장&lt;/code>(수정할 때)을 꼭 눌러주셔야만 반영됩니다.&lt;/p>
&lt;p>자 그러면 새로 만든 유저로 동일한 코드를 실행해볼까요?&lt;/p>
&lt;p>설정 파일(~/.zshrc)을 열어서 다음 내용을 새 유저의 액세스 키와 비밀 액세스 키로 변경합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 기존 유저 액세스 키&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># export AWS_ACCESS_KEY_ID=...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># export AWS_SECRET_ACCESS_KEY=...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 새 유저 액세스 키&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">export&lt;/span> &lt;span class="nv">AWS_ACCESS_KEY_ID&lt;/span>&lt;span class="o">=&lt;/span>...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">export&lt;/span> &lt;span class="nv">AWS_SECRET_ACCESS_KEY&lt;/span>&lt;span class="o">=&lt;/span>...
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>그리고 변경된 설정 파일을 꼭 적용해주셔야 합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; &lt;span class="nb">source&lt;/span> ~/.zshrc
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>자 그리고 다시 apply 해봅시다!&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&amp;gt; tf apply
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">aws_instance.example: Creating...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">╷
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ Error: creating EC2 Instance: UnauthorizedOperation: You are not authorized to perform this operation. User: arn:aws:iam::246181472423:user/terraform-user is not authorized to perform: ec2:CreateTags on resource: arn:aws:ec2:ap-northeast-2:246181472423:instance/* because no identity-based policy allows the ec2:CreateTags action. Encoded authorization failure message: -Ebof-TaMnw5iPJ_dVKP00sOBTScilmv_M3-TgALYm6r48Fi4oAIxOOMWghh0LZkPXrH1yqS5XIR9dsIgCLrHl2lua-CgXDXXWc0uq-QBmKupfCnhtGx2Sdu0-IqDwlImA5bmNOIlktmOj0WUUak8G4OtphB2zL0Yi7WnfDAruVd_CHJdYrkTEIW1are7RDvgX753V5h96s9_8zn7A8KVR479FT5qLrMy3lFAN1sfauVatYkbl8EztWa9qBC7zQ7goAq682lc-A0IbGrgQ3whJMqGaLwvK3Q5kL7QyvkJ-VXe5dq58YpZnMlvsc5uH76QVKiie_tdjMy28xpQ2EmRI3nqa9-1uvGIO6-1MKhwBbAeHQdz7kgmcp2aTI2BjBurhyDxQKWUKJqQCrY7-FTx4d2xdxyBaDM-LCujL2O-oFx2NBNYYBsRKO1E22gxcSakpwNqjg8omJ8-7X-8JhBGebfT6WM4ociL1T8OxIr6JG8dEnJWRzma4feKGZVCmkLxJbHPQW0IPF3FGtGbTFyir9YALbQDPX9yUwz4_w09slZdG7y-8aWBrlrCHccmcOmm8hpsthiNJbgtjTPxjZdHNWglMiUJ8PmiazOK04QcBLv5N71icCWdogluVBsCxmehFnPNWYq3BzWSdEhLtdQIK5sokmMEY2KFsJQ32cnBg
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ status code: 403, request id: 88a0f4a9-c313-47b6-9677-7862747f9fb9
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ with aws_instance.example,
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ on main.tf line 7, in resource &lt;span class="s2">&amp;#34;aws_instance&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;example&amp;#34;&lt;/span>:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 7: resource &lt;span class="s2">&amp;#34;aws_instance&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;example&amp;#34;&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>그런데 오류가 발생하네요..! iamlive가 &lt;code>ec2:CreateTags&lt;/code> 권한을 제대로 캐치를 하지 못해서 그렇습니다. 이 권한을 계정에 추가해주고 다시 확인해보면 생성과 삭제 모두 문제 없이 진행되는 걸 확인할 수 있습니다. 물론 저 권한을 하나씩 확인하면서 추가했다면 꽤나 복잡했겠죠? 그러다가 &lt;code>아 ** 안해&lt;/code>하게 됩니다. 하하하하하&amp;hellip;.개발이 다 그렇죠 뭐&amp;hellip;&lt;/p>
&lt;h2 id="참고자료">참고자료&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://github.com/iann0036/iamlive">https://github.com/iann0036/iamlive&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://meirg.co.il/2021/04/23/determining-aws-iam-policies-according-to-terraform-and-aws-cli/">Determining AWS IAM Policies According To Terraform And AWS CLI&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.terraformupandrunning.com/">Terraform Up and Running, 3rd Edition&lt;/a>&lt;/li>
&lt;/ul>
&lt;h1 id="license">License&lt;/h1>
&lt;p>&lt;a href="https://creativecommons.org/licenses/by-nc-nd/2.0/kr/">저작자표시-비영리-변경금지 2.0 대한민국 (CC BY-NC-ND 2.0 KR)&lt;/a>&lt;/p></content></item></channel></rss>