<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>쉽지않은 개발 블로그</title>
    <link>https://no-easy-dev.tistory.com/</link>
    <description>시간이 걸릴뿐
bob.jeong28@gmail.com</description>
    <language>ko</language>
    <pubDate>Sun, 5 Apr 2026 14:46:51 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>no-easy-ray</managingEditor>
    <image>
      <title>쉽지않은 개발 블로그</title>
      <url>https://tistory1.daumcdn.net/tistory/4728684/attach/dd5a2eac90764be98894b1bcf1272be6</url>
      <link>https://no-easy-dev.tistory.com</link>
    </image>
    <item>
      <title>NewRelic (FutureStack Seoul)</title>
      <link>https://no-easy-dev.tistory.com/entry/NewRelicFutureStack-Seoul</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #172b4d;&quot;&gt;지난 10월 5일 뉴렐릭 코리아에서 진행하는 FutureStack Seoul에 다녀온 내용에 대해서 기록을 남겨보려고 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;참여-이유&quot; data-renderer-start-pos=&quot;93&quot; data-ke-size=&quot;size26&quot;&gt;참여 이유&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;101&quot; data-ke-size=&quot;size16&quot;&gt;현재 저는 회사에서 EKS에서 운영되는 서비스들의 Monitoring을 위하여 NewRelic을 사용하고 있습니다.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;154&quot; data-ke-size=&quot;size16&quot;&gt;이번에 뉴렐릭 세션에 참여해보고 싶었던 이유는 다른 회사들은 뉴렐릭을 어떻게 사용하는지를 알고 싶었습니다.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;214&quot; data-ke-size=&quot;size16&quot;&gt;종종 메가존 클라우드와 뉴렐릭 코리아와의 미팅을 통해 뉴렐릭에 대한 가이드와 신규 기능들에 대해 소개를 해주시지만 일종의 가이드일 뿐 실제 사례에 대한 내용들이 부족하다고 느꼈고, 이러한 궁금증들이 어느 정도 해결이 될 거라는 기대로 참여하게 되었습니다.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;214&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-renderer-start-pos=&quot;214&quot; data-ke-size=&quot;size23&quot;&gt;행사 목차&lt;/h3&gt;
&lt;p id=&quot;오전-세션&quot; data-renderer-start-pos=&quot;376&quot; data-ke-size=&quot;size18&quot;&gt;오전 세션&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-indent-level=&quot;1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Open Telemetry FOK (핸즈온&amp;nbsp;워크샵&amp;nbsp;-&amp;nbsp;랩탑&amp;nbsp;지참)&lt;/li&gt;
&lt;li&gt;Observability as a code (핸즈온 워크샵 - 랩탑 지참)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;오후-세션&quot; data-renderer-start-pos=&quot;470&quot; data-ke-size=&quot;size18&quot;&gt;오후 세션&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-indent-level=&quot;1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;옵저버빌리티를 통한 IT 전략의 변화&lt;/li&gt;
&lt;li&gt;뉴렐릭 솔루션 Overview (Observability and M.E.L.T)&lt;/li&gt;
&lt;li&gt;코빗(Korbit) 사례 공유&lt;/li&gt;
&lt;li&gt;How NR operates Kubernetes at scale as an Observability platform&lt;/li&gt;
&lt;li&gt;How to Troubleshoot your Full Stack in Context (Infra, NPM, Logs)&lt;/li&gt;
&lt;li&gt;How to accelerate innovation to develop &amp;amp; operate service using AWS Marketplace (AWS Marketplace)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-renderer-start-pos=&quot;214&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;214&quot; data-ke-size=&quot;size16&quot;&gt;모든 목차에 대해서 소개하기보다는 행사에 참여하면서 개인적으로 경험해보고 인상 깊었던 내용들을 정리해 보려고 합니다.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;214&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;Monitoring-vs-Observability&quot; data-renderer-start-pos=&quot;865&quot; data-ke-size=&quot;size26&quot;&gt;Monitoring vs Observability&lt;b&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;895&quot; data-ke-size=&quot;size16&quot;&gt;NewRelic은 Monitoring 툴이 아닌 &lt;b&gt;Observability&lt;/b&gt; 툴 이라고 설명하는 점이 가장 인상 깊었고, 주로 사용되는 DataDog 등이 어떤 설루션인지에 대한 이해도가 증가했던 것 같습니다.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1009&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1011&quot; data-ke-size=&quot;size16&quot;&gt;간단히 정리하자면&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1022&quot; data-ke-size=&quot;size16&quot;&gt;Monitoring은 현재 상태를 진단하는것이라고 볼 수 있습니다.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1061&quot; data-ke-size=&quot;size16&quot;&gt;예시로 동네 병원에서 간단한 진료받는것을 생각해보면 이해가 쉬울 것 같습니다. 현재 내가 코로나가 걸렸는지 안 걸렸는지 현재 상태만을 보고 검진하여 판단을 내리게 됩니다.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1156&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1158&quot; data-ke-size=&quot;size16&quot;&gt;하지만 &lt;b&gt;Observability&lt;/b&gt; 는 보다 확장된 개념이라고 볼 수 있습니다.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1202&quot; data-ke-size=&quot;size16&quot;&gt;뉴렐릭 측에서는 과거의 상태 현재의 상태 종합적인 정보들을 활용하여 미래를 예측 및 대비할 수 있는 것이라고 정의합니다.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1270&quot; data-ke-size=&quot;size16&quot;&gt;예시로 종합병원에서 전문적인 건강검진을 받는것을 생각해볼 수 있습니다. 과거의 내 몸의 상태가 어땠는지? 지금까지의 식습관은 어땠는지? 현재의 상태는 어땠는지 등 다양한 정보를 수집하여 앞으로 조심해야 하는 행동들과 일어날 수 있는 상태들을 예측할 수 있게 됩니다.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1416&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1418&quot; data-ke-size=&quot;size16&quot;&gt;이러한 부분에 있어서 Monitoring과 &lt;b&gt;Observability의&lt;/b&gt; 차이점이 존재하고, 뉴렐릭은 &lt;b&gt;Observability를&lt;/b&gt; 도와주는 솔루션이라고 소개해 주었습니다.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1418&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1418&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;Observability-as-Code&quot; data-renderer-start-pos=&quot;1516&quot; data-ke-size=&quot;size26&quot;&gt;Observability as Code&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;1540&quot; data-ke-size=&quot;size16&quot;&gt;이번 행사에서 개인적으로 가장 큰 임팩트가 있다고 생각했던 부분 중 하나입니다.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1540&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1584&quot; data-ke-size=&quot;size16&quot;&gt;확실히 Terraform이 트렌드라는 것을 확인할 수 있었고(행사장에서 Terraform을 거의 대부분의 회사가 사용한다는 점을 느낄 수 있었습니다.), Terraform은 IaC(Infra as a Code)로서만 사용된다고 생각했는데 이제는 다양한 SaaS의 형상까지 관리하게 되었다는 게 놀라웠습니다.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1756&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1758&quot; data-ke-size=&quot;size16&quot;&gt;APM을 제외한 모든 부분, DashBoard, Alert, Log DropFilter, synthetics 등 뉴렐릭에서 사용자가 직접 손으로 만들 수 있는 모든 부분을 이제는 Code로서 관리할 수 있다는 점이 개인적으로는 맘에 들었던 것 같습니다.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1896&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1898&quot; data-ke-size=&quot;size16&quot;&gt;Code로 관리되었을 때 이점은 다음과 같습니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-indent-level=&quot;1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;생성과 삭제가 빠르고 깔끔하다.&lt;/li&gt;
&lt;li&gt;코드 리뷰를 할 수 있다. (서로 간의 검증이 가능해진다.)&lt;/li&gt;
&lt;li&gt;리소스 관리가 쉽다. (Terraform에 익숙해졌을 경우)&lt;/li&gt;
&lt;li&gt;변경이력이 남는다. (퇴사자 혹은 신규 입사자에게 도움이 될 수 있다.)&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-renderer-start-pos=&quot;2065&quot; data-ke-size=&quot;size16&quot;&gt;위의 이점들은 뉴렐릭의 기능들을 더 다양하게 사용할수록 더욱더 발휘될 것이라고 생각합니다.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2117&quot; data-ke-size=&quot;size16&quot;&gt;현재의 회사에는 APM을 제외한 NewRelic의 기능들을 사용자(제가...)가 직접 추가하고 있기에, 추후에 NewRelic 기능 사용에 대한 고도화가 이루어진다면 terraform을 사용해보는 것을 어떨까 생각해 볼 수 있었습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-renderer-start-pos=&quot;2237&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2237&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;MELT-(Metrics,-Events,-Logs,-Traces)&quot; data-renderer-start-pos=&quot;2239&quot; data-ke-size=&quot;size26&quot;&gt;MELT (Metrics, Events, Logs, Traces)&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;2278&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Observability를&lt;/b&gt; 위해서 과거와 현재의 다양한 정보들을 확인해야 하는데 이를 위해 확인하는 정보들이 바로 &lt;b&gt;MELT라고&lt;/b&gt; 뉴렐릭에서는 이야기합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;newrelic.png&quot; data-origin-width=&quot;533&quot; data-origin-height=&quot;668&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/badzyr/btrOx91Te8i/8Zu0kW3WabZKDgSUkRjPAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/badzyr/btrOx91Te8i/8Zu0kW3WabZKDgSUkRjPAk/img.png&quot; data-alt=&quot;MELT를 뉴렐릭에서 확인&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/badzyr/btrOx91Te8i/8Zu0kW3WabZKDgSUkRjPAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbadzyr%2FbtrOx91Te8i%2F8Zu0kW3WabZKDgSUkRjPAk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;440&quot; height=&quot;668&quot; data-filename=&quot;newrelic.png&quot; data-origin-width=&quot;533&quot; data-origin-height=&quot;668&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;MELT를 뉴렐릭에서 확인&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;뉴렐릭을 통해서 위의 데이터를 확인하여 현재 서비스들의 상태를 측정하고 미래를 예측 및 대비할 수 있게 된다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;Guide-or-Tip&quot; data-renderer-start-pos=&quot;2436&quot; data-ke-size=&quot;size26&quot;&gt;Guide or Tip&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;2451&quot; data-ke-size=&quot;size16&quot;&gt;세션을 진행하면서 스피커로 참여하신 뉴렐릭 코리아 시니어 개발자 분들이 가이드 하는 내용을 정리합니다.&lt;/p&gt;
&lt;h4 data-renderer-start-pos=&quot;2510&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 id=&quot;Versioning&quot; data-renderer-start-pos=&quot;2510&quot; data-ke-size=&quot;size20&quot;&gt;Versioning&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-renderer-start-pos=&quot;2522&quot; data-ke-size=&quot;size16&quot;&gt;뉴렐릭 관련 라이브러리, agent의 버전을 항상 최신으로 유지하는 것을 권장한다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-renderer-start-pos=&quot;2570&quot; data-ke-size=&quot;size16&quot;&gt;뉴렐릭의 새로운 기능들이 호환되지 않을 수가 있다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 id=&quot;Alert&quot; data-renderer-start-pos=&quot;2604&quot; data-ke-size=&quot;size20&quot;&gt;Alert&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-indent-level=&quot;1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;workload를 활용하라 (Incident는 추후 지원되지 않을 예정)&lt;/li&gt;
&lt;li&gt;모든 APM 리소스에 대해서 Alert를 걸어두는 것이 중요하다. (&lt;span data-renderer-mark=&quot;true&quot; data-mark-type=&quot;annotation&quot; data-mark-annotation-type=&quot;inlineComment&quot; data-id=&quot;e309e2cb-6bf8-4c92-996a-fdd8d41045a7&quot;&gt;회&lt;/span&gt;색으로 표기된 것이 없어야 한다.)&lt;/li&gt;
&lt;li&gt;WorkLoad를 이용하게 될 경우 특정 조건이 발생했을 시 다른 정보도 같이 추가할 수 있다.&lt;br /&gt;(ex: Frontend CPU &amp;gt; 80 알람 발생 시 다른 API의 메트릭 정보도 같이 보내줄 수 있음.)&lt;/li&gt;
&lt;li&gt;Alert에 대한 채널 관리 및 네이밍에 신경 써라&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 id=&quot;Log&quot; data-renderer-start-pos=&quot;2865&quot; data-ke-size=&quot;size20&quot;&gt;Log&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-renderer-start-pos=&quot;2870&quot; data-ke-size=&quot;size16&quot;&gt;로그를 수집할 때 기본 형태가 아닌 특정 포맷으로 파싱 되어 들어올 수 있도록 설정하는 것을 추천&lt;/p&gt;
&lt;blockquote data-renderer-start-pos=&quot;2870&quot; data-ke-style=&quot;style2&quot;&gt;설정 안 하면 message로 오지만 설정하면 해당 포맷(ex: nginx log format)으로 들어오게 됨&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a title=&quot;built-log-parsing-rules&quot; href=&quot;https://docs.newrelic.com/docs/logs/ui-data/built-log-parsing-rules/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://docs.newrelic.com/docs/logs/ui-data/built-log-parsing-rules/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 id=&quot;NRQL&quot; data-renderer-start-pos=&quot;2990&quot; data-ke-size=&quot;size20&quot;&gt;NRQL&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-renderer-start-pos=&quot;2996&quot; data-ke-size=&quot;size16&quot;&gt;뉴렐릭에 어느 정도 적응이 되었다면 NRQL을 이용해 보는 것이 더 좋을 수 있을 거 같다.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3045&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 id=&quot;Kubernetes-Resource-optimization&quot; data-renderer-start-pos=&quot;3047&quot; data-ke-size=&quot;size20&quot;&gt;Kubernetes Resource optimization&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-renderer-start-pos=&quot;3081&quot; data-ke-size=&quot;size16&quot;&gt;리소스 최적화에 대해서는 끝이 없다.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3103&quot; data-ke-size=&quot;size16&quot;&gt;초기에는 여유 있게 운영 한 되 뉴렐릭을 활용하여 점차 줄이는 방향으로 할 수밖에 없는 것 같다. (뉴렐릭도 그렇게 한다. 대부분 동의하는듯했음)&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-renderer-start-pos=&quot;3183&quot; data-ke-size=&quot;size16&quot;&gt;줄이는 과정에서는 Alert를 활용할 수 있다. 특정 지점에 대한 Alert가 주기적으로 발생되지 않는다면 리소스를 더 줄여도 된다는 의미로 사용한다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-renderer-start-pos=&quot;3270&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 id=&quot;NewRelic-Pixie&quot; data-renderer-start-pos=&quot;3272&quot; data-ke-size=&quot;size20&quot;&gt;NewRelic Pixie&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-renderer-start-pos=&quot;3288&quot; data-ke-size=&quot;size16&quot;&gt;쿠버네티스 모니터링과 APM이 존재하면 크게 사용할 이유는 없으나, 고객 사례로 요청에 대한 패킷 모니터링을 원하여 사용하는 사례가 있다.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3367&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 id=&quot;SRE&quot; data-renderer-start-pos=&quot;3369&quot; data-ke-size=&quot;size20&quot;&gt;SRE&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-renderer-start-pos=&quot;3374&quot; data-ke-size=&quot;size16&quot;&gt;SRE관점에서 SLI, SLO를 설정한 뒤, 이를 기반으로 한 KPI를 작성해 볼 수도 있다.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3374&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;소감&quot; data-renderer-start-pos=&quot;3617&quot; data-ke-size=&quot;size26&quot;&gt;소감&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;3622&quot; data-ke-size=&quot;size16&quot;&gt;여러 기업들의 다양한 사례를 듣고 싶었지만 생각보다 다양하다고 생각되지는 않았던 것 같습니다.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3716&quot; data-ke-size=&quot;size16&quot;&gt;하지만, 뉴렐릭을 좀 더 다양한 방면에서 활용하는 사례를 알 수 있어 좋았고, Terraform이 인프라 외적으로도 더많이 사용되고 있는것(Observability as a Code) 을 체험해볼 수 있어서 신기했습니다.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3830&quot; data-ke-size=&quot;size16&quot;&gt;뉴렐릭 코리아에서 best practice 느낌으로 이야기 해준 가이드 들은 회사에도 적용할 수 있으면 좋겠다고 생각해보는 시간이 되었습니다.&lt;/p&gt;</description>
      <category>daliy</category>
      <category>Datadog</category>
      <category>FutureStack Seoul</category>
      <category>newrelic</category>
      <category>newrelic(FutureStack Seoul)</category>
      <category>Observability</category>
      <category>뉴렐릭</category>
      <category>뉴렐릭 서울</category>
      <author>no-easy-ray</author>
      <guid isPermaLink="true">https://no-easy-dev.tistory.com/42</guid>
      <comments>https://no-easy-dev.tistory.com/entry/NewRelicFutureStack-Seoul#entry42comment</comments>
      <pubDate>Thu, 13 Oct 2022 23:52:52 +0900</pubDate>
    </item>
    <item>
      <title>Git Cache Clean</title>
      <link>https://no-easy-dev.tistory.com/entry/Git-Cache-Clean</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Git을 사용하다보면 간혹 .gitignore에 추가된 내용이 제대로 반영되지 않는 경우가 종종있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런경우 Cache가 남아있는거 이기에 Cache를 제거해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1665671296160&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git rm -r --cached .
git status
git add .&lt;/code&gt;&lt;/pre&gt;</description>
      <category>git</category>
      <category>git</category>
      <category>git cache</category>
      <category>git cache clean</category>
      <author>no-easy-ray</author>
      <guid isPermaLink="true">https://no-easy-dev.tistory.com/41</guid>
      <comments>https://no-easy-dev.tistory.com/entry/Git-Cache-Clean#entry41comment</comments>
      <pubDate>Thu, 13 Oct 2022 23:29:25 +0900</pubDate>
    </item>
    <item>
      <title>AWS | Karpenter</title>
      <link>https://no-easy-dev.tistory.com/entry/AWS-Karpenter</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;회사에서는 CA(Cluster Autoscaler)를 사용하고 있지만, 오토스케일링 속도를 향상하기 위해 &lt;span style=&quot;background-color: #ffffff;&quot;&gt;Karpenter를 설치하여 속도를 비교해 보았고 테스트 했던 내용을 정리해보려고 합니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;Karpenter&quot; data-renderer-start-pos=&quot;1&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Karpenter&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-renderer-start-pos=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;AWS에서 오픈소스로 개발한 기존 Cluster AutoScaler와 동일하게 클러스터의 오토스케일링을 가능하게 해주는 도구이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;Karpenter-Inastall&quot; data-renderer-start-pos=&quot;96&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Karpenter Inastall&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-renderer-start-pos=&quot;116&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Karpenter 설치의 경우 가이드가 잘되어있기 때문에 따로 작성하지 않는다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-renderer-start-pos=&quot;163&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Cluster AutoScaler(CA)를 사용하고 있기 때문에 마이그레이션 부분을 참고하여 진행하였습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;a style=&quot;color: #333333;&quot; href=&quot;https://karpenter.sh/v0.6.3/getting-started/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://karpenter.sh/v0.6.3/getting-started/&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;a style=&quot;color: #333333;&quot; href=&quot;https://karpenter.sh/v0.15.0/getting-started/migrating-from-cas/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://karpenter.sh/v0.15.0/getting-started/migrating-from-cas/&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;Karpenter-특징&quot; data-renderer-start-pos=&quot;17441&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Karpenter 특징&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-renderer-start-pos=&quot;17455&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Karpenter는 고성능 쿠버네티스 오토스케일러라고 소개되고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;17494&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;하지만 현재 지원은 AWS EKS와 온프레미스 쿠버네티스만을 지원하고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;17572&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;따라서 Karpenter는 CA와 주로 비교되고 있고, 현재 숨고에서는 CA로 오토스케일링을 하고 있기 때문에 CA와 비교되는 특징들을 정리해 보려고 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;17572&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 id=&quot;Group-less-node-provisioning&quot; data-renderer-start-pos=&quot;17658&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Group-less node provisioning&lt;/span&gt;&lt;/h4&gt;
&lt;p data-renderer-start-pos=&quot;17688&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;가장 큰 특징으로는 오토스케일링을 수행하기 위해 관리하는 대상의 차이점이 존재합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;17734&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;CA의 경우 EKS의 NodeGoup을 컨트롤하여 연관되는 ASG의 Scale을 수정함으로써 새로운 노드를 확보하게 되는 반면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;17805&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Karpenter의 경우 직접 파드 스케쥴링에 필요한 스펙의 인스턴스를 확보합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;17856&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;17858&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;CA를 이용할 경우 운영하는 서비스들이 다양한 스펙의 컴퓨팅 자원을 필요로 한다면, 각 타입에 맞게 NodeGroup을 구성하여 운영해야 합니다. (CPU특화, GPU특화 등&amp;hellip; 또한 시작 템플릿에 정의된 Spec으로 밖에 인스턴스가 구동되지 못하는 점도 존재합니다.)&lt;/span&gt;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;17858&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;18005&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;각 특성에 맞는 NodeGroup을 생성하는 이유는 CA의 동작원리 때문입니다. (NodeGroup과 ASG를 이용한 스케일링 이기 때문)&lt;/span&gt;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;18083&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;하지만, Karpenter의 경우 그룹을 이용하는 게 아닌 직접 필요한 인스턴스를 관리하기 때문에 그룹이라는 제한 없이 필요한 스펙의 인스턴스를 확보할 수 있는 차이점이 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-renderer-start-pos=&quot;18083&quot; data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;추가로 Karpenter는 Instance Type 선정 시 &lt;a style=&quot;color: #333333;&quot; title=&quot;binpacking&quot; href=&quot;https://en.wikipedia.org/wiki/Bin_packing_problem#First_Fit_Decreasing_(FFD)&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;binpacking&lt;/a&gt;&amp;nbsp;알고리즘을 사용한다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-renderer-start-pos=&quot;18083&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 id=&quot;Scheduling-enforcement&quot; data-renderer-start-pos=&quot;18234&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Scheduling enforcement&lt;/span&gt;&lt;/h4&gt;
&lt;p data-renderer-start-pos=&quot;18258&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Karpenter의 장점 중 하나는 Pod의 스케쥴링이 CA보다 빠른 점이 있다. (Pod의 스케쥴링 시점이 더 빠르다)&lt;/span&gt;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;18324&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;보통 EKS의 경우 노드가 준비되고 나서 Pod가 스케쥴링되지만, Karpenter의 경우 시작하는 노드에 파드가 스케쥴링되도록 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;18324&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-renderer-start-pos=&quot;18324&quot; data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;문서상 노드 시작 대기 시간을 몇 초 절약할 수 있다고 나와있습니다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-renderer-start-pos=&quot;18324&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;a style=&quot;color: #333333;&quot; href=&quot;https://karpenter.sh/v0.9.0/concepts/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://karpenter.sh/v0.9.0/concepts/&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-renderer-start-pos=&quot;18486&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-renderer-start-pos=&quot;18486&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;테스트 진행 결과&lt;/span&gt;&lt;/h4&gt;
&lt;p data-renderer-start-pos=&quot;18486&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;Karpenter&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;karpenter.png&quot; data-origin-width=&quot;1194&quot; data-origin-height=&quot;100&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pw03t/btrOyNqCtXy/0oKymfhJI7YBR9ZhoJI0WK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pw03t/btrOyNqCtXy/0oKymfhJI7YBR9ZhoJI0WK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pw03t/btrOyNqCtXy/0oKymfhJI7YBR9ZhoJI0WK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fpw03t%2FbtrOyNqCtXy%2F0oKymfhJI7YBR9ZhoJI0WK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1194&quot; height=&quot;100&quot; data-filename=&quot;karpenter.png&quot; data-origin-width=&quot;1194&quot; data-origin-height=&quot;100&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;CA(Cluster AutoScaler)&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;CA.png&quot; data-origin-width=&quot;1212&quot; data-origin-height=&quot;150&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dCqF2Z/btrOxS62Eso/k7ykzFRQpDhAYHSowIXTW0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dCqF2Z/btrOxS62Eso/k7ykzFRQpDhAYHSowIXTW0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dCqF2Z/btrOxS62Eso/k7ykzFRQpDhAYHSowIXTW0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdCqF2Z%2FbtrOxS62Eso%2Fk7ykzFRQpDhAYHSowIXTW0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1212&quot; height=&quot;150&quot; data-filename=&quot;CA.png&quot; data-origin-width=&quot;1212&quot; data-origin-height=&quot;150&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-renderer-start-pos=&quot;18486&quot; data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;테스트는 노드가 0개인 상태에서 기본 nginx이미지를 사용하는 Pod를 띄우는 것으로 테스트를 진행했습니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;실제로 속도 비교 시 약 10~15초 정도 빠른 걸로 확인된다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-renderer-start-pos=&quot;18486&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;18486&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;Karpenter-구성&quot; data-renderer-start-pos=&quot;18642&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Karpenter 구성&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-renderer-start-pos=&quot;18656&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Helm Chart로 Karpenter 설치 후 Provisioner라는 CRD를 추가로 설치하여 운영하게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-renderer-start-pos=&quot;18721&quot; data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Provisioner의 설정값을 통해 상세한 Instance Type과 AutoScaling 옵션 등을 설정할 수 있습니다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-renderer-start-pos=&quot;18721&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;18721&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333;&quot;&gt;Karpenter에서 인스턴스를 구동시키는 방법은 NodeGroup에 지정된 시작 템플릿을 기반으로 잠시 생성하고, 생성된 시작 템플릿으로 인스턴스를 구동시키는 것을 확인할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-renderer-start-pos=&quot;18721&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;a style=&quot;color: #333333;&quot; href=&quot;https://karpenter.sh/v0.15.0/tasks/provisioning/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://karpenter.sh/v0.15.0/tasks/provisioning/&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-renderer-start-pos=&quot;18721&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;18721&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;18721&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333;&quot;&gt;시작 템플릿 생성 후 인스턴스 생성&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;karpenter_1.png&quot; data-origin-width=&quot;1512&quot; data-origin-height=&quot;45&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cptAQM/btrOw2I7yUe/u7o2SzEcEvD3xHU9t6wd30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cptAQM/btrOw2I7yUe/u7o2SzEcEvD3xHU9t6wd30/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cptAQM/btrOw2I7yUe/u7o2SzEcEvD3xHU9t6wd30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcptAQM%2FbtrOw2I7yUe%2Fu7o2SzEcEvD3xHU9t6wd30%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1512&quot; height=&quot;45&quot; data-filename=&quot;karpenter_1.png&quot; data-origin-width=&quot;1512&quot; data-origin-height=&quot;45&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333;&quot;&gt;인스턴스 생성 후 시작 템플릿 삭제&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;karpenter_2.png&quot; data-origin-width=&quot;1388&quot; data-origin-height=&quot;32&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pKwLz/btrOxLGRZiR/6PRA1DwEEuVuE865yBPxQK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pKwLz/btrOxLGRZiR/6PRA1DwEEuVuE865yBPxQK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pKwLz/btrOxLGRZiR/6PRA1DwEEuVuE865yBPxQK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpKwLz%2FbtrOxLGRZiR%2F6PRA1DwEEuVuE865yBPxQK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1388&quot; height=&quot;32&quot; data-filename=&quot;karpenter_2.png&quot; data-origin-width=&quot;1388&quot; data-origin-height=&quot;32&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;18721&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-renderer-start-pos=&quot;18721&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;결론&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;karpenter를 사용했을 경우 노드가 스케일링 되어 프로비저닝이 완료되는데까지의 시간이 10~15초 정도 줄어드는 것으로 확인되었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333;&quot;&gt;Karpenter의 경우 서비스가 필요한 인스턴스 타입이 다양하여 NodeGroup이 많거나 많아지고 있는 상황에서 이점이 많이 크다고 생각합니다. (혹은 앞으로 다양한 인스턴스 타입을 사용하여 Pod를 Node안에 꽉꽉 채워 넣도록 하는 최적화를 진행하거나&amp;hellip;)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333;&quot;&gt;그리고 &lt;span style=&quot;background-color: #ffffff;&quot;&gt;Karpenter가 나온 지 얼마 되지 않아 문제가 있을 수 있다는 평이 많아 회사에서 적용하지는 못했지만, 개인적은 프로젝트에는 적용해볼 법하다고 생각됩니다. (그리고 실제로 프로덕션에 사용하는 회사도 있습니다.)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>aws</category>
      <category>ASG</category>
      <category>AWS</category>
      <category>CA</category>
      <category>cluster autoscaler</category>
      <category>k8s</category>
      <category>karpenter</category>
      <category>Kubernetes</category>
      <author>no-easy-ray</author>
      <guid isPermaLink="true">https://no-easy-dev.tistory.com/40</guid>
      <comments>https://no-easy-dev.tistory.com/entry/AWS-Karpenter#entry40comment</comments>
      <pubDate>Thu, 13 Oct 2022 22:47:02 +0900</pubDate>
    </item>
    <item>
      <title>Terraform | EKS 만들어 보기</title>
      <link>https://no-easy-dev.tistory.com/entry/Terraform-EKS-%EB%A7%8C%EB%93%A4%EC%96%B4-%EB%B3%B4%EA%B8%B0</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;테라폼을 이용하여 EKS를 생성하는 방법을 정리해 보려고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EKS를 구성하고 있는 각각의 테라폼 리소스를 이용하여 만들 수 도 있지만 테라폼에서 제공하는 EKS모듈을 이용하면 보다 쉽게 만들 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://registry.terraform.io/modules/terraform-aws-modules/eks/aws/latest&quot;&gt;Terraform EKS Module&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;github의 example에 들어가 보시면 example이 존재합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/terraform-aws-modules/terraform-aws-eks/tree/master/examples&quot;&gt;Terrarom EKS Module Example&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시로는 테라폼에서 제공하는 노드 그룹을 전부 이용하는 예제가 제공되고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단하게 실습용으로 만들 것이기 때문에 제공하는 example보다는 간소화해서 만들어보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만들기 전에 기본적인 설정들을 정리하도록 하겠습니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;i&gt;EKS를 만들기 위해서 추가적으로 &lt;b&gt;awscli2, kubectl, helm&lt;/b&gt;(CA(&lt;a href=&quot;https://github.com/kubernetes/autoscaler/tree/master/charts/cluster-autoscaler&quot;&gt;cluster-autoscaler&lt;/a&gt; 설치))이 필요합니다.&lt;/i&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 AWS Provider설정을 합니다.&lt;/p&gt;
&lt;pre class=&quot;nginx&quot;&gt;&lt;code&gt;# main.tf
provider &quot;aws&quot; {
  region = var.region

  default_tags {
    tags = {
      Terraform = &quot;true&quot;
      Project   = &quot;${var.cluster_name}-project&quot;
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Region과 생성된 리소스들에 대해서 지정함 default tag를 작성합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EKS등에서 사용될 variables를 생성합니다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;# variables.tf
variable &quot;region&quot; {
  default = &quot;ap-northeast-2&quot;
}

variable &quot;azs&quot; {
  description = &quot;A list of availability zones names or ids in the region&quot;
  type = list(string)
  default = [&quot;ap-northeast-2a&quot;, &quot;ap-northeast-2c&quot;]
}

variable &quot;cluster_name&quot; {
  description = &quot;Cluster Name&quot;
  type = string
  default = null
}

variable &quot;cluster_version&quot; {
  description = &quot;Cluster Version&quot;
  type = string
  default = null
}

variable &quot;vpc_cidr&quot; {
  description = &quot;VPC CIDR Range&quot;
  type = string
  default = null
}

variable &quot;vpc_name&quot; {
  description = &quot;VPC Name&quot;
  type = string
  default = null
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;# terraform.auto.tfvars
vpc_name     = &quot;ray-vpc&quot;
vpc_cidr     = &quot;192.168.0.0/16&quot;

cluster_name     = &quot;my-cluster&quot;
cluster_version  = &quot;1.21&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테라폼 실행 시 해당 파일에 작성한 변수명과 일치하는 variables에 맞게 사용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 파일들이 준비가 되었으면 먼저 새로운 VPC를 생성할 수 있도록 작성합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VPC 또한 테라폼에서 제공하는 &lt;a href=&quot;https://registry.terraform.io/modules/terraform-aws-modules/vpc/aws/latest&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;모듈&lt;/a&gt;을 이용하면 손쉽게 만들 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;nix&quot;&gt;&lt;code&gt;# vpc.tf
module &quot;vpc&quot; {
  source = &quot;terraform-aws-modules/vpc/aws&quot;

  name = var.vpc_name
  azs  = var.azs
  cidr = var.vpc_cidr

  # NAT게이트웨이를 생성합니다.
  enable_nat_gateway = true
  # NAT게이트웨이를 1개만 생성합니다.
  single_nat_gateway = true

  public_subnets = [for index in range(2):
                      cidrsubnet(var.vpc_cidr, 4, index)]

  private_subnets = [for index in range(2):
                      cidrsubnet(var.vpc_cidr, 4, index + 2)]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.terraform.io/language/functions/cidrsubnet&quot;&gt;cidrsubnet&lt;/a&gt; 서브넷 cidr을 나눠주기 위해 사용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EKS를 생성합니다.&lt;/p&gt;
&lt;pre class=&quot;nix&quot;&gt;&lt;code&gt;data &quot;aws_caller_identity&quot; &quot;current&quot; {}

locals {
  node_group_name        = &quot;${var.cluster_name}-node-group&quot;
  iam_role_policy_prefix = &quot;arn:aws:iam::${data.aws_caller_identity.current.account_id}:policy&quot;
}

module &quot;eks&quot; {
  # 모듈 사용
  source = &quot;terraform-aws-modules/eks/aws&quot;

  cluster_name    = var.cluster_name
  cluster_version = var.cluster_version

  cluster_endpoint_private_access = true
  cluster_endpoint_public_access  = true

  vpc_id          = module.vpc.vpc_id
  subnet_ids      = module.vpc.private_subnets
  
  # 관리형 노드 그룹 사용 (기본 설정)
  eks_managed_node_group_defaults = {
    ami_type               = &quot;AL2_x86_64&quot; # 
    disk_size              = 10           # EBS 사이즈
    instance_types         = [&quot;t2.small&quot;]
    # vpc_security_group_ids = [aws_security_group.additional.id]
    vpc_security_group_ids = []
		
		# cluster-autoscaler에 사용 될 IAM 등록
    iam_role_additional_policies = [&quot;${local.iam_role_policy_prefix}/${module.iam_policy_autoscaling.name}&quot;]
  }

  # 관리형 노드 그룹 사용 (노드별 추가 설정)
  eks_managed_node_groups = {
    (&quot;${var.cluster_name}-node-group&quot;) = {
      # node group 스케일링
      min_size     = 1 # 최소
      max_size     = 3 # 최대
      desired_size = 2 # 기본 유지

      # 생성된 node에 labels 추가 (kubectl get nodes --show-labels로 확인 가능)
      labels = {
        ondemand = &quot;true&quot;
      }

      # 생성되는 인스턴스에 tag추가
      tags = {
        &quot;k8s.io/cluster-autoscaler/enabled&quot; : &quot;true&quot;
        &quot;k8s.io/cluster-autoscaler/${var.cluster_name}&quot; : &quot;true&quot;
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테라폼 EKS모듈(현재 18.2.3 버전)에서는 3가지의 node group을 제공합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS EKS에서 제공하는 Node Group은 &lt;a href=&quot;https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/eks-compute.html&quot;&gt;여기&lt;/a&gt;에서 확일 할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Node Group에 사용될 IAM Policy를 생성합니다. (cluster-autoscaler를 사용하기 위함입니다.)&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;module &quot;iam_policy_autoscaling&quot; {
  source = &quot;terraform-aws-modules/iam/aws//modules/iam-policy&quot;

  name = &quot;${var.cluster_name}-cluster-autoscaler&quot;
  path = &quot;/&quot;
  description = &quot;Autoscaling policy for cluster ${var.cluster_name}&quot;

  policy      = data.aws_iam_policy_document.worker_autoscaling.json
}

data &quot;aws_iam_policy_document&quot; &quot;worker_autoscaling&quot; {
  statement {
    sid    = &quot;eksWorkerAutoscalingAll&quot;
    effect = &quot;Allow&quot;

    actions = [
      &quot;autoscaling:DescribeAutoScalingGroups&quot;,
      &quot;autoscaling:DescribeAutoScalingInstances&quot;,
      &quot;autoscaling:DescribeLaunchConfigurations&quot;,
      &quot;autoscaling:DescribeTags&quot;,
      &quot;ec2:DescribeLaunchTemplateVersions&quot;,
    ]

    resources = [&quot;*&quot;]
  }

  statement {
    sid    = &quot;eksWorkerAutoscalingOwn&quot;
    effect = &quot;Allow&quot;

    actions = [
      &quot;autoscaling:SetDesiredCapacity&quot;,
      &quot;autoscaling:TerminateInstanceInAutoScalingGroup&quot;,
      &quot;autoscaling:UpdateAutoScalingGroup&quot;,
    ]

    resources = [&quot;*&quot;]

    condition {
      test     = &quot;StringEquals&quot;
      variable = &quot;autoscaling:ResourceTag/kubernetes.io/cluster/${var.cluster_name}&quot;
      values   = [&quot;owned&quot;]
    }

    condition {
      test     = &quot;StringEquals&quot;
      variable = &quot;autoscaling:ResourceTag/k8s.io/cluster-autoscaler/enabled&quot;
      values   = [&quot;true&quot;]
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Cluster Autoscaler가 IAM 역할을 사용하기 위해 &lt;a href=&quot;https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/cluster-autoscaler.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;필요한 권한&lt;/a&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기까지 작성 후 테라폼 명령을 이용하여 생성하도록 합니다.&lt;/p&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;terraform init

terraform plan

terraform apply
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kubecofing설정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EKS를 생성하게 되면 생성한 IAM User에 대해서 system:master 권한을 갖게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 초기 설정을 위해서 system:master로 클러스터에 접속하게 되는데 이때, 다음 명령을 통해 해당 User에 대해서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EKS 클러스터에 접속할 수 있는 토큰을 발급하여 사용하도록 하는 kubeconfig를 생성합니다.&lt;/p&gt;
&lt;pre class=&quot;dsconfig&quot;&gt;&lt;code&gt;# EKS생성에 사용된 IAM configure를 이용해야합니다. (~/.aws)
aws eks --region ap-northeast-2 update-kubeconfig --name my-cluster
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성된 kubeconfig 예시&lt;/p&gt;
&lt;pre class=&quot;stata&quot;&gt;&lt;code&gt;# ~/.kube/kubeconfig
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: ********==
    server: https://********.***.ap-northeast-2.eks.amazonaws.com
  name: arn:aws:eks:ap-northeast-2:********:cluster/my-cluster
contexts:
- context:
    cluster: arn:aws:eks:ap-northeast-2:********:cluster/my-cluster
    user: arn:aws:eks:ap-northeast-2:********:cluster/my-cluster
  name: arn:aws:eks:ap-northeast-2:********:cluster/my-cluster
current-context: arn:aws:eks:ap-northeast-2:********:cluster/my-cluster
kind: Config
preferences: {}
users:
- name: arn:aws:eks:ap-northeast-2:********:cluster/my-cluster
  user:
    exec:
      apiVersion: client.authentication.k8s.io/v1alpha1
      args:
      - --region
      - ap-northeast-2
      - eks
      - get-token
      - --cluster-name
      - my-cluster
      command: aws
      env:
      - name: AWS_PROFILE
        value: my-aws-profile
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kubeconfig가 생성되면 다음과 같은 config가 생성된 걸 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kubectl을 이용하여 해당 EKS Api서버로 요청이 잘 가는지 확인합니다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;# 생성된 EKS의 Node 확인
kubectl get nodes

# 만약 연결이 되지 않는 경우 kubeconfig가 제대로 지정 되지 않았을 수 도 있습니다.
export KUBECONFIG=&quot;~/.kube/{해당 config파일}&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 EKS 사용량에 따라 node group의 node들이 스케일링이 가능해지도록 CA(cluster-autoscaler)를 설치합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 CA(cluster-autoscaler)에 사용될 values.yaml을 생성합니다.&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;# values.yaml
autoDiscovery:
  clusterName: my-cluster # eks cluster name

awsRegion: ap-northeast-2 # eks region

extraArgs:
  logtostderr: true
  stderrthreshold: info
  v: 4
  expander: random
  scale-down-enabled: true # 사용량이 적을경우 scale-down허용
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각각의 옵션은 &lt;a href=&quot;https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/FAQ.md#i-have-a-couple-of-nodes-with-low-utilization-but-they-are-not-scaled-down-why&quot;&gt;여기&lt;/a&gt;서 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 Helm install을 통해 CA(cluster-autoscaler)를 설치합니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;helm repo add autoscaler &amp;lt;https://kubernetes.github.io/autoscaler&amp;gt;

helm repo update

helm install cluster-autoscaler autoscaler/cluster-autoscaler --values=./valuse.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Iac</category>
      <category>eks</category>
      <category>terraform</category>
      <category>Terraform EKS</category>
      <category>Terraform EKS Module</category>
      <category>테라폼 EKS</category>
      <author>no-easy-ray</author>
      <guid isPermaLink="true">https://no-easy-dev.tistory.com/39</guid>
      <comments>https://no-easy-dev.tistory.com/entry/Terraform-EKS-%EB%A7%8C%EB%93%A4%EC%96%B4-%EB%B3%B4%EA%B8%B0#entry39comment</comments>
      <pubDate>Fri, 28 Jan 2022 16:58:40 +0900</pubDate>
    </item>
    <item>
      <title>Python | Python 데코레이터(Decorator)</title>
      <link>https://no-easy-dev.tistory.com/entry/Python-Python-%EB%8D%B0%EC%BD%94%EB%A0%88%EC%9D%B4%ED%84%B0Decorator</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬의 데코레이터에 대해서 정리합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬의 웹 프레임워크나 라이브러리들을 사용할 때 &lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;@&lt;/b&gt;&lt;/span&gt;로 시작하는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 파이썬에서는 데코레이터라고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;데코레이터(Decorator)&lt;/b&gt;는 기존 함수의 변경 없이 추가적인 기능을 덧붙일 수 있도록 해 주는 함수라고 보시면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단하게 메서드의 시간을 측정하는 기능을 하는 데코레이터를 만들어 보면서 데코레이터가 어떤 것인지 정리해보도록 하겠습니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;데코레이터는 함수와 클래스 둘 다 이용하여 만들 수 있습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;데코레이터(함수)&lt;/h3&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;from time import sleep, perf_counter

def time_check_func(func):
    def check(*args):
        start = perf_counter()
        func(*args) # 받아온 함수 실행!
        end = perf_counter()
        print(f'&amp;gt;&amp;gt; {start} / {end} / {end - start}')

    return check
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같이 데코레이터는 함수를 매개변수로 받아서 내부의 함수에서 실행하는 구조로 되어있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같은 함수를 이용해서 시간을 측정한다고 했을 경우 다음과 같이 할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;# 테스트 함수
def test_decorator_func(*args):
    print(f'run function decorator &amp;gt;&amp;gt; {args}')
    sleep(1)

time_check_func(test_decorator_func)('A','B','C','D')
# run function decorator &amp;gt;&amp;gt; ('A', 'B', 'C', 'D')
# &amp;gt;&amp;gt; 290215.2574023 / 290216.2585761 / 1.0011737999739125
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같이 time_check_func이라는 함수에 매개변수로 test_decorator_func을 넣고 time_check_func내부의 check를 이용하여 호출하게 되는 것인데, 너무 코드가 길어지고 복잡해집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 데코레이터를 이용하면 쉽게 사용할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;@time_check_func
def test_decorator_func(*args):
    print(f'run function decorator &amp;gt;&amp;gt; {args}')
    sleep(1)

test_decorator_func('A','B','C','D')
# run function decorator &amp;gt;&amp;gt; ('A', 'B', 'C', 'D')
# &amp;gt;&amp;gt; 290215.2574023 / 290216.2585761 / 1.0011737999739125

@time_check_func
def other_func():
    print('other function run')
    sleep(2)

other_func()
# other function run
# &amp;gt;&amp;gt; 290877.8528502 / 290879.8550702 / 2.002219999965746
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트 함수 위에 &lt;b&gt;@time_check_func&lt;/b&gt;를 작성하게 되면 이전에 사용한 것처럼 동작하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 다른 함수들에도 데코레이터를 재사용함으로써 시간을 측정하는 기능을 손쉽게 적용할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;데코레이터(클래스)&lt;/h3&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;class time_check_cls:
    def __init__(self, func):
        self._func = func

    def __call__(self):
        start = perf_counter()
        self._func()
        end = perf_counter()
        print(f'&amp;gt;&amp;gt; {start} / {end} / {end - start}')
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스 형태로 데코레이터를 작성할 경우 &lt;b&gt;init&lt;/b&gt; 메서드에 매개변수로 func을 받도록 하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;call&lt;/b&gt; 메서드를 구현함으로써 생성할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용은 함수로 만든 경우와 동일하게 사용할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;@time_check_cls
def test_decorator_cls():
    print('run class decorator')
    sleep(1)

test_decorator_cls()
# run class decorator
# &amp;gt;&amp;gt; 290879.8553817 / 290880.8566954 / 1.00131370004965
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;마무리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬 데코레이터에 대해서 정리해보는 시간이었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬에서는 데코레이터가 자주 사용되는 것을 확인할 수 있었습니다. Flask의 @route부터 시작해서 pythontips에서 예시로 제공한 인증처리 등 앞으로 파이썬으로 코딩을 하면서 데코레이터를 제대로 활용할 수 있으면 많은 도움이 될 것 같은 생각이 들었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;감사합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;참고자료&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://book.pythontips.com/en/latest/decorators.html#giving-a-function-as-an-argument-to-another-function&quot;&gt;https://book.pythontips.com/en/latest/decorators.html#giving-a-function-as-an-argument-to-another-function&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;https://dojang.io/mod/page/view.php?id=2427&lt;/p&gt;</description>
      <category>python</category>
      <category>decorator</category>
      <category>python</category>
      <category>python decorator</category>
      <category>데코레이터</category>
      <category>파이썬</category>
      <category>파이썬 데코레이터</category>
      <author>no-easy-ray</author>
      <guid isPermaLink="true">https://no-easy-dev.tistory.com/38</guid>
      <comments>https://no-easy-dev.tistory.com/entry/Python-Python-%EB%8D%B0%EC%BD%94%EB%A0%88%EC%9D%B4%ED%84%B0Decorator#entry38comment</comments>
      <pubDate>Wed, 26 Jan 2022 18:02:27 +0900</pubDate>
    </item>
    <item>
      <title>Python | Python 일급 함수(First Class function)</title>
      <link>https://no-easy-dev.tistory.com/entry/Python-Python-%EC%9D%BC%EA%B8%89-%ED%95%A8%EC%88%98</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬의 일급 함수에 대해서 정리해 보려고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 프로그래밍 언어에서 함수가 일급이라는 것은 다음의 조건을 만족하는 경우 일급 함수라고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;함수가&lt;b&gt; object 유형&lt;/b&gt;의 인스턴스인 경우.&lt;/li&gt;
&lt;li&gt;함수를 &lt;b&gt;변수에 저장&lt;/b&gt;할 수 있는 경우.&lt;/li&gt;
&lt;li&gt;함수를 다른 함수에 &lt;b&gt;매개변수로 전달&lt;/b&gt;할 수 있는 경우.&lt;/li&gt;
&lt;li&gt;함수에서 다른 &lt;b&gt;함수를 반환&lt;/b&gt;할 수 있는 경우.&lt;/li&gt;
&lt;li&gt;list, dict 등과 같은 &lt;b&gt;데이터 구조에 저장&lt;/b&gt;할 수 있는 경우.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각각을 예시를 통해 확인해 보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;함수가 &lt;span style=&quot;color: #ef5369;&quot;&gt;object 유형&lt;/span&gt;의 인스턴스인 경우.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 간단한 예시로 변수에 1을 할당해 보겠습니다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;num = 1 # 변수에 1을 할당
print(type(num))               # &amp;lt;class 'int'&amp;gt;
print(issubclass(int, object)) # True
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;후 타입을 확인해보면 int라는 클래스이고, int클래스는 object를 상속받는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 동일하게 확인을 해보면&lt;/p&gt;
&lt;pre class=&quot;scala&quot;&gt;&lt;code&gt;def im_object():
    return 'Im object'

print(type(im_object))               # &amp;lt;class 'function'&amp;gt;
print(isinstance(im_object, object)) # True
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 함수가 object유형의 인스턴스인 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;함수를 &lt;span style=&quot;color: #ef5369;&quot;&gt;변수에 저장&lt;/span&gt;할 수 있는 경우.&lt;/h4&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;def im_object():
    return 'Im object'

v_func = im_object # 변수에 저장
print(v_func())    # Im object
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수를 변수에 저장하여 해당 변수로 함수를 실행할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;함수를 다른 함수에 &lt;span style=&quot;color: #ef5369;&quot;&gt;매개변수로 전달&lt;/span&gt;할 수 있는 경우.&lt;/h4&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;def relay_func(msg):
    return f'&amp;gt;&amp;gt; sub : {msg}'

def main_func(func):
    print('&amp;gt;&amp;gt; run main')
    print(func('hello'))

main_func(relay_func)
# &amp;gt;&amp;gt; run main
# &amp;gt;&amp;gt; sub : hello&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메인 함수에 relay_func을 매개변수로 전달하여 메인 함수 내에서 relay_func함수를 실행하는 예제입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 예시로 자주 사용되는 map함수에서도 매개변수로 전달하여 사용할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;# map에 함수를 전달
result = list(map(relay_func, 'ABCDE'))
print(result) 
# ['&amp;gt;&amp;gt; sub : A', '&amp;gt;&amp;gt; sub : B', '&amp;gt;&amp;gt; sub : C', '&amp;gt;&amp;gt; sub : D', '&amp;gt;&amp;gt; sub : E']&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;함수에서 다른 &lt;span style=&quot;color: #ef5369;&quot;&gt;함수를 반환&lt;/span&gt;할 수 있는 경우.&lt;/h4&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;def create_adder(x):
    def adder(y):
        return x + y
    return adder

adder_100 = create_adder(100)
print(adder_100(10)) # 110
print(adder_100(20)) # 120
print(adder_100(30)) # 130
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;create_adder함수에서는 adder라는 다른 함수를 반환하고 있는 걸 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;list, dict 등과 같은 &lt;span style=&quot;color: #ef5369;&quot;&gt;데이터 구조에 저장&lt;/span&gt;할 수 있는 경우.&lt;/h4&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;def adder_1(x):
    return x + 1
    
def adder_2(x):
    return x + 2
    
def adder_3(x):
    return x + 3

adder_dict = {'one':adder_1, 'two': adder_2, 'three': adder_3}
adder_list = [adder_1, adder_2, adder_3]

print(adder_dict)
print(adder_list)

print(adder_dict.get('one')(100)) # 101
print(adder_list[1](100))         # 102
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 list, dict형태에 저장 가능한 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;마무리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일급 함수에 대한 내용은 파이썬뿐만 아니라 다은 프로그래밍 언어에도 적용이 되는 내용인 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수형 프로그래밍을 할 때 일급 함수에 대한 내용이 나오는데, 일급 함수에 대한 내용을 따로 정리해 볼 수 있는 시간이었던 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;감사합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;참고자료&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://book.pythontips.com/en/latest/decorators.html#giving-a-function-as-an-argument-to-another-function&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://book.pythontips.com/en/latest/decorators.html#giving-a-function-as-an-argument-to-another-function&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.w3schools.com/python/python_classes.asp&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.w3schools.com/python/python_classes.asp&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.geeksforgeeks.org/first-class-functions-python/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.geeksforgeeks.org/first-class-functions-python/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/27392402/what-is-first-class-function-in-python&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://stackoverflow.com/questions/27392402/what-is-first-class-function-in-python&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.tutorialspoint.com/first-class-citizens-in-python&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.tutorialspoint.com/first-class-citizens-in-python&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@shchoice/First-class-Function%EC%9D%BC%EA%B8%89-%ED%95%A8%EC%88%98-Higher-order-Function%EA%B3%A0%EC%9C%84-%ED%95%A8%EC%88%98&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://velog.io/@shchoice/First-class-Function%EC%9D%BC%EA%B8%89-%ED%95%A8%EC%88%98-Higher-order-Function%EA%B3%A0%EC%9C%84-%ED%95%A8%EC%88%98&lt;/a&gt;&lt;/p&gt;</description>
      <category>python</category>
      <category>first class function</category>
      <category>first-class citizen</category>
      <category>python</category>
      <category>python First Class function</category>
      <category>파이썬</category>
      <category>파이썬 일급함수</category>
      <author>no-easy-ray</author>
      <guid isPermaLink="true">https://no-easy-dev.tistory.com/37</guid>
      <comments>https://no-easy-dev.tistory.com/entry/Python-Python-%EC%9D%BC%EA%B8%89-%ED%95%A8%EC%88%98#entry37comment</comments>
      <pubDate>Wed, 26 Jan 2022 14:11:36 +0900</pubDate>
    </item>
    <item>
      <title>Python | Python 내부 동작과정</title>
      <link>https://no-easy-dev.tistory.com/entry/Python-Python-%EB%82%B4%EB%B6%80-%EB%8F%99%EC%9E%91%EA%B3%BC%EC%A0%95</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;내부적으로 파이썬 코드를 실행했을 때 어떻게 동작하는지 정리해보려고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Python Interperter&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬은 인터프리터 언어라고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬 코드를 작성할 때&amp;nbsp;인터프리터는 프로그램을 읽고&amp;nbsp;그&amp;nbsp;안의&amp;nbsp;명령을&amp;nbsp;실행하는 역할을 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터프리터의 실행 과정을 정리해보면 다음과 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;interpreter.png&quot; data-origin-width=&quot;811&quot; data-origin-height=&quot;301&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cfwS8i/btrrpUAToVr/HTF1D21MlJ2odOmM6Nyi91/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cfwS8i/btrrpUAToVr/HTF1D21MlJ2odOmM6Nyi91/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cfwS8i/btrrpUAToVr/HTF1D21MlJ2odOmM6Nyi91/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcfwS8i%2FbtrrpUAToVr%2FHTF1D21MlJ2odOmM6Nyi91%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;811&quot; height=&quot;301&quot; data-filename=&quot;interpreter.png&quot; data-origin-width=&quot;811&quot; data-origin-height=&quot;301&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;파이썬 코드를 작성합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;컴파일러&lt;/b&gt;는 소스 코드를 받습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;컴파일러&lt;/b&gt;는 소스 코드에서 각 줄의 구문을 확인합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;컴파일러&lt;/b&gt;에 오류가 발생하면 오류 메시지(Syntax error)와 함께 중지됩니다.&lt;/li&gt;
&lt;li&gt;구문 확인 후 소스 코드를 바이트코드로 변환합니다.&lt;/li&gt;
&lt;li&gt;바이트코드는 &lt;b&gt;PVM(Python Virtual Machine)&lt;/b&gt;으로 전송됩니다.&lt;/li&gt;
&lt;li&gt;입력 및 라이브러리 모듈과 함께 바이트 코드가 &lt;b&gt;PVM&lt;/b&gt;에 대한 입력으로 제공됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;PVM&lt;/b&gt;은 바이트코드를 실행하고 오류가 발생하면 오류 메시지(Runtime error)를 표시합니다.&lt;/li&gt;
&lt;li&gt;실행에 오류가 없으면 결과가 출력됩니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;파이썬 코드 작성&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;# hello_python.py
class Hello:
    def __init__(self, text) -&amp;gt; None:
        print(f'Run Init {text}')

h1 = Hello('Hello World')
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;파이썬 컴파일&lt;/p&gt;
&lt;pre class=&quot;vim&quot;&gt;&lt;code&gt;python3 -m compileall ./hello_python.py
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴파일하는 과정에서 Syntax 체크를 진행하고 문제가 없을 경우 소스코드를 바이트코드로 변환합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 컴파일 후 변환된 바이트 코드는 __pycahe__폴더 아래에 다음과 같이 pyc파일로 생성되는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;complie_test
├── __pycache__
│   └── hello_python.cpython-38.pyc
└── hello_python.py
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바이트 코드는 소스 코드와 기계 코드의 중간 코드입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바이트 코드는 인터프리터에 의해 기계 코드로 변환된 후 기계(컴퓨터)에서 읽을 수 있게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;바이트 코드 확인&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 바이트 코드는 파이썬의 dis모듈을 이용하여 확인해 볼 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;# disassembly.py
import hello_python
import dis

# 바이너리 코드 확인
dis.dis(hello_python)

# ------------------------------------------------------------
Disassembly of Hello:
Disassembly of __init__:
  3           0 LOAD_GLOBAL              0 (print)
              2 LOAD_CONST               1 ('Run Init ')
              4 LOAD_FAST                1 (text)
              6 FORMAT_VALUE             0
              8 BUILD_STRING             2
             10 CALL_FUNCTION            1
             12 POP_TOP
             14 LOAD_CONST               0 (None)
             16 RETURN_VALUE
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 바이트 코드는 인터프리터의 PVM으로 전송되어 기계어로 변환됨으로써 해당 프로그램이 실행됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;CPython&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Cpython은 C언어로 파이썬을 구현한 것입니다. python코드를 이해하고 한줄한줄 읽으며 cpu가 이해할 수 있게 번역하는 일을 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CPython은 Python의 기본 인터프리터로 사용되고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;CPython과 Python의 차이점&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CPython은 python.org에서 다운로드한 Python의 구현입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Python은 CPython에 의해 실행되는 프로그래밍 언어입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;마무리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단하게 정리하긴 했지만, 파이썬 코드가 어떤 식으로 동작하게 되는지 정리해보는 시간이었던 거 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞으로 공부해 나가면서 더 내부적인 원리들에 대해서 공부해보는 시간도 필요할 것 같다는 생각이 들었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;감사합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고자료&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;http://kimwooseok.com/python/2021/06/29/python-compile/&quot;&gt;http://kimwooseok.com/python/2021/06/29/python-compile/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.c-sharpcorner.com/article/why-learn-python-an-introduction-to-python/&quot;&gt;https://www.c-sharpcorner.com/article/why-learn-python-an-introduction-to-python/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/@kaushik.k/internal-working-of-python-415572929e7a&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://medium.com/@kaushik.k/internal-working-of-python-415572929e7a&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://techvidvan.com/tutorials/python-interpreter/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://techvidvan.com/tutorials/python-interpreter/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/@kaushik.k/internal-working-of-python-415572929e7a&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://medium.com/@kaushik.k/internal-working-of-python-415572929e7a&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;http://kimwooseok.com/python/2021/06/29/python-compile/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;http://kimwooseok.com/python/2021/06/29/python-compile/&lt;/a&gt;&lt;/p&gt;</description>
      <category>python</category>
      <author>no-easy-ray</author>
      <guid isPermaLink="true">https://no-easy-dev.tistory.com/36</guid>
      <comments>https://no-easy-dev.tistory.com/entry/Python-Python-%EB%82%B4%EB%B6%80-%EB%8F%99%EC%9E%91%EA%B3%BC%EC%A0%95#entry36comment</comments>
      <pubDate>Mon, 24 Jan 2022 13:22:22 +0900</pubDate>
    </item>
    <item>
      <title>Python | Class에 대해서</title>
      <link>https://no-easy-dev.tistory.com/entry/Python-Class%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬을 다시 공부하게 되면서 Class부터 정리를 해보려고 합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Class&lt;/h3&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;# 강아지를 생성하는 클래스입니다.
class Dog:
    def __init__(self, kind, name, age):
        self._kind = kind 
        self._name = name
        self._age  = age
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단한 예시로 클래스는 위와 같이 생성할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각각을 좀 더 정리를 해보도록 하겠습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;__init__&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;__init__&lt;/b&gt; 메서드는 &lt;b&gt;인스턴스가 생성될 때 실행&lt;/b&gt;되는 메서드로 Instance 변수를 지정합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(Java의 생성자 정도로 생각하시면 됩니다.)&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Instance 변수&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Instance 변수는 간단히 Instance에 대한 속성 값이라고 생각하면 됩니다.&lt;/p&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;    def __init__(self, kind, name, age):
        self._kind = kind 
        self._name = name
        self._age  = age
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 클래스를 작성했다면 해당 클래스로부터 생성된 인스턴스에는 _kind, _name, _age라는 속성(인스턴스 변수)이 존재합니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;이름 앞에 _를 붙인 이유는 class변수와 차별화하기 위함입니다. _를 붙이지 않아도 상관없습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인스턴스 생성&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;# 인스턴스 생성
dog1 = dog('maltese', 'max', 8)
dog2 = dog('husky', 'bob', 5)

print(dog1.__dict__) # {'_kind': 'maltese', '_name': 'max', '_age': 8}
print(dog2.__dict__) # {'_kind': 'husky', '_name': 'bob', '_age': 5}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 각각 생성된 dog1, dog2객체에는 각각 다른 값을 가지고 있는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Class 변수&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Class 변수는 클래스로부터 생성된 인스턴스들이 공유하는 변수입니다.&lt;/p&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;class Dog:
    managed_count = 0

    def __init__(self, kind, name, age) -&amp;gt; None:
        self._kind = kind 
        self._name = name
        self._age  = age

        # Class로 부터 인스턴스를 생성하면 count를 1 올립니다.
        Dog.managed_count += 1
		
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성된 강아지수를 관리하기 위해 managed_count라는 클래스 변수를 이용하여 관리하도록 합니다.&lt;/p&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;dog1 = Dog('maltese', 'max', 8)
dog2 = Dog('husky', 'bob', 5)

print(Dog.managed_count)  # 2
print(dog1.managed_count) # 2
print(dog2.managed_count) # 2
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 예시처럼 각각의 인스턴스들은 클래스 변수를 공유하는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기까지 강아지를 생성하는 Class를 만드는 예제를 다루어보았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 클래스로부터 만들어진 인스턴스(dog1, dog2...)에 기능을 추가하는 방법을 정리하도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Method&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Class에는 Method를 이용하여 생성된 인스턴스(강아지)에 기능을 추가할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Method는 3가지 종류가 있어 각각 예시를 통해 설명하도록 하겠습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Instance Method&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인스턴스 메서드는 기본적으로 클래스에서 만들어주는 메서드라고 생각하면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;강아지에게 짖을 수 있는 기능을 추가하려면 다음과 같이 인스턴스 메서드를 추가해주면 됩니다.&lt;/p&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;class Dog:
    def __init__(self, kind, name, age):
        self._kind = kind 
        self._name = name
        self._age  = age

    def bark(self):
        print(f'{self._name} 멍멍')
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;강아지에게 짖을 수 있는 기능을 추가하려면 다음과 같이 인스턴스 메서드를 추가해주면 됩니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;인스턴스 메서드에는 첫 번째 인자로 &lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;self&lt;/b&gt;&lt;/span&gt;를 받도록 해야 합니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인스턴스 메서드는 클래스로부터 인스턴스를 생성한 후에 생성된 인스턴스로부터 사용될 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;gcode&quot;&gt;&lt;code&gt;dog1 = Dog('maltese', 'max', 8)
dog2 = Dog('husky', 'bob', 5)

dog1.bark() # max 멍멍
dog2.bark() # bob 멍멍
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 bark라는 메서드를 실행하여 강아지가 짖을 수 있게 할 수 있습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Class Method&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스 메서드는 인스턴스를 생성하지 않아도 사용할 수 있는 메서드입니다.&lt;/p&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;class Dog:
    managed_count = 0

    def __init__(self, kind, name, age):
        self._kind = kind 
        self._name = name
        self._age  = age
        Dog.managed_count += 1

    def bark(self):
        print(f'{self._name} 멍멍')

    @classmethod
    def get_managed_count(cls):
				print(cls) # &amp;lt;class '__main__.Dog'&amp;gt;
        print(f'총 강아지 수 : {cls.managed_count}')
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스 메서드를 생성하려면 메서 드위에 &lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;@classmethod&lt;/b&gt;&lt;/span&gt;를 입력받아야 하고 첫 번째 인자로 &lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;cls&lt;/b&gt;&lt;/span&gt;를 반드시 받도록 되어야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(cls는 해당 클래스라고 생각하시면 됩니다. print를 해보면 Dog Class가 조회되는 걸 확인할 수 있습니다.)&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;Dog.get_managed_count()  # 2

dog1 = Dog('maltese', 'max', 8)
dog2 = Dog('husky', 'bob', 5)

dog1.get_managed_count() # 2
dog2.get_managed_count() # 2
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용은 클래스 자체에서 바로 사용할 수 있고, 추가로 생성된 인스턴스에서도 사용할 수 있습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Static Method&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스태틱 메서드는 클래스 메서드와 비슷하지만 지정된 인자(&lt;b&gt;self, cls&lt;/b&gt;)를 받지 않아도 된다는 차이점이 있습니다.&lt;/p&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;class Dog:
    managed_count = 0

    def __init__(self, kind, name, age):
        self._kind = kind 
        self._name = name
        self._age  = age
        Dog.managed_count += 1

    def bark(self):
        print(f'{self._name} 멍멍')

    @staticmethod
    def is_husky(inst):
        if inst._kind == &quot;husky&quot;:
            return True
        else:
            return False
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스태틱 메서드를 생성하려면 &lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;@staticmethod&lt;/b&gt;&lt;/span&gt;를 메서드 위에 작성해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재는 Dog 클래스로부터 만들어진 강아지(인스턴스)의 종류를 비교하는 메서드를 생성하였습니다.&lt;/p&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;dog1 = Dog('maltese', 'max', 8)
dog2 = Dog('husky', 'bob', 5)

print(Dog.is_husky(dog1)) # False
print(Dog.is_husky(dog2)) # True
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스태틱 메서드 또한 클래스에서 직접 사용할 수 있고 각각 생성된 인스턴스에서도 사용할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;self&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스에 인스턴스 메서드를 생성하면서 가장 첫 번째 인자로 &lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;self라는 게&lt;/b&gt;&lt;/span&gt; 있는 것을 확인할 수 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론적으로 &lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;self&lt;/b&gt;&lt;/span&gt;는 &lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;인스턴스 자체&lt;/b&gt;&lt;/span&gt;를 나타냅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인스턴스 자체라는 것을 확인하기 위해서 간단한 메서드를 만들어보겠습니다.&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;class Dog:
    managed_count = 0

    def __init__(self, kind, name, age):
        self._kind = kind 
        self._name = name
        self._age  = age
        Dog.managed_count += 1

    def get_inst_id(self):
        ''' get instance id'''
        return id(self)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스로부터 각각의 인스턴스들을 생성하고 확인을 해보도록 하겠습니다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;dog1 = Dog('maltese', 'max', 8)
dog2 = Dog('husky', 'bob', 5)

print(id.__doc__) # id라는 메서드는 객체의 id를 반환하는 메서드입니다.

print(id(dog1) == dog1.get_inst_id()) # True
print(id(dog2) == dog2.get_inst_id()) # True
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;id메서드로 각각의 객체와 self를 조회해보면 동일한 id가 나오는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 self의 의미는 클래스로부터 만들어진 인스턴스 자체라는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;마무리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬을 다시 공부하게 되면서 공부한 내용들을 계속해서 정리해 나가려고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;잘못 정리한 부분이 있거나 추가적인 설명이 필요한 부분이 있다면 댓글 남겨주시면 저에게 많은 도움이 될 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;감사합니다.&lt;/p&gt;</description>
      <category>python</category>
      <category>Class</category>
      <category>Pyhon</category>
      <category>Python Class</category>
      <category>파이썬</category>
      <category>파이썬 클래스</category>
      <author>no-easy-ray</author>
      <guid isPermaLink="true">https://no-easy-dev.tistory.com/35</guid>
      <comments>https://no-easy-dev.tistory.com/entry/Python-Class%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C#entry35comment</comments>
      <pubDate>Sun, 23 Jan 2022 21:54:05 +0900</pubDate>
    </item>
    <item>
      <title>Terraform | Terraform State</title>
      <link>https://no-easy-dev.tistory.com/entry/Terraform-Terraform-State</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;테라폼은 인프라가 변경될 때마다 형상을 tfstate파일에 기록함으로써 현재 생성되어 있는 인프라 형상을 관리합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 테라폼으로 인프라를 생성하면 현재 디렉터리에 terraform.tfstate라는 파일이 생성되는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;terraform backend&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로컬에서 state파일을 사용할 경우 다른 개발자와 tfstate파일을 공유하기에는 번거로움이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 문제를 해결하고자 테라폼에서는 backend라는 기능을 제공합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;terraform backend라는 것은 생성되는 tfstate파일을 AWS의 S3, kubernetes 등 따로 저장되도록 하여&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 사용자들에게 공유할 수 있도록 하는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS를 사용하고 있기 때문에 terraform backend로 S3를 사용하는 예제를 작성해보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 terraform backend 될 S3버킷을 생성합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1642938441706&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# s3.tf
resource &quot;aws_s3_bucket&quot; &quot;terraform_state&quot; {
    bucket = &quot;bob-terraform-state-bucket&quot;
    acl    = &quot;private&quot;

    # 코드의 이력을 관리하기 위해 활성화 합니다.
    versioning {
        enabled = true
    }

    # 서버 측 암호화를 활성화 합니다.(S3에 저장된 파일이 암호화 됩니다.)
    server_side_encryption_configuration {
        rule {
            apply_server_side_encryption_by_default {
                sse_algorithm = &quot;AES256&quot;
            }
        }
    }
    
    # s3에 파일이 존재 하더라도 강제로 지우도록 합니다.
    force_destroy = true

    tags = {
        Name        = &quot;state bucket&quot;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1642938931014&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;terraform init
terraform apply&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버킷을 생성하게 되면 현재 경로에 terraform.tfstate파일이 존재하는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 terraform backend로 S3를 지정하여 terraform.tfstate을 만들어둔 S3버킷으로 관리될 수 있도록 합니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1642938883688&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# main.tf
provider &quot;aws&quot; {
  region = &quot;ap-northeast-2&quot;

  default_tags {
    tags = {
      Terraform = &quot;true&quot;
    }
  }
}

terraform {
    backend &quot;s3&quot; {
      bucket = &quot;bob-terraform-state-bucket&quot;
      key    = &quot;terraform.tfstate&quot;
      region = &quot;ap-northeast-2&quot;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;terraform init을 하게되면 local에 있던 terraform.tfstate파일의 내용이 사라지고 만들어둔 S3에 해당 tfstate파일이 들어가 있는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이렇 게 공유된 tfstate을 여러 사용자가 동시에 사용한다고 했을 때 문제가 발생할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 두 명의 개발자가 서로 다르게 인프라를 변경을 한다면 변경된 내용을 tfstate에 지정하게 되는데 분명 &lt;b&gt;충돌&lt;/b&gt;이 일어날 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 terraform에는 &lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;잠금(lock)&lt;/b&gt;&lt;/span&gt; 기능을 제공합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;잠금 기능이란 한 명이 apply를 통해서 tfstate를 변경하는 작업을 진행 중이라면 다른 개발자는 apply를 진행할 수 없는 상태를 말합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;잠금 기능을 이용하기 위해서는 AWS의 &lt;b&gt;DynamoDB&lt;/b&gt;가 필요합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1642939237320&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# dynamodb.tf
resource &quot;aws_dynamodb_table&quot; &quot;terraform_locks&quot; {
    name           = &quot;bob-terraform-locks&quot;
    billing_mode   = &quot;PAY_PER_REQUEST&quot;
    hash_key       = &quot;LockID&quot;

    attribute {
        name = &quot;LockID&quot;
        type = &quot;S&quot;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 DynamoDB를 작성 후 apply를 통해 생성합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가적으로 해당 S3에서 tfstate를 사용하기 위해서는 IAM계정에 다음 2가지의 권한이 필요합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.terraform.io/language/settings/backends/s3#s3-bucket-permissions&quot;&gt;https://www.terraform.io/language/settings/backends/s3#s3-bucket-permissions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.terraform.io/language/settings/backends/s3#dynamodb-table-permissions&quot;&gt;https://www.terraform.io/language/settings/backends/s3#dynamodb-table-permissions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 main.tf에 설정된 terraform backend설정을 변경합니다&lt;/p&gt;
&lt;pre id=&quot;code_1642939365791&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# main.tf
...
terraform {
    backend &quot;s3&quot; {
      bucket = &quot;bob-terraform-state-bucket&quot;
      key    = &quot;terraform.state&quot;
      region = &quot;ap-northeast-2&quot;
	  
      # dynamodb추가
      dynamodb_table = &quot;bob-terraform-locks&quot;
      encrypt = true
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설정을 변경한 후 &lt;b&gt;terraform init -migrate-state&lt;/b&gt;을 이용하여 init을 하게 되면 앞으로 변경되는 state에 대해서 적용이 되는 걸 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;terraform workspace&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 하나의 프로젝트에서 하나의 tfstate가 아닌 각각의 tfstate를 사용하고 싶을 경우 테라폼에서 제공하는 workspace기능을 사용할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;명령어&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 사용중인 workspace를 조회합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1642940816484&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;terraform workspace show&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성되어있는 모든 workspace를 조회합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1642940823166&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;terraform workspace list&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로운 workspace를 생성합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1642940829541&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# prod라는 workspace를 생성합니다.
terraform workspace new prod&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만들어진 workspace를 선택합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1642940836749&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;terraform workspace select prod&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;workspace를 생성할 경우 위에서 생성된 내용이 아닌 완전히 새로운 tfstate인 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단한 예시로 다음과 같이 사용할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1642940954541&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Prod환경에서와 test환경에서 인스턴스 타입을 다르게 사용하는 예시
resource &quot;aws_instance&quot; &quot;web&quot; {
  ami           = data.aws_ami.ubuntu.id
  instance_type = terraform.workspace == &quot;prod&quot; ? &quot;m5.large&quot; : &quot;t2.micro&quot;
...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;마무리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테라폼을 사용하면서 state파일을 관리하는 방법들에 대해서 정리해보았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행한 예제를 삭제하기 위해서는 다음과같이 terraform backend를 지정한 것을 local로 돌린 후 삭제를 해야 에러 없이 삭제를 진행할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1642941390006&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# main.tf
provider &quot;aws&quot; {
  region = var.region

  default_tags {
    tags = {
      Terraform = &quot;true&quot;
    }
  }
}

# terraform {
#     backend &quot;s3&quot; {
#       bucket = &quot;bob-terraform-state-bucket&quot;
#       key    = &quot;terraform.state&quot;
#       region = &quot;ap-northeast-2&quot;

#       dynamodb_table = &quot;bob-terraform-locks&quot;
#       encrypt = true
#     }
# }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;terraform backend를 지정한 부분을 주석, 삭제 후 init를 진행하여 tfstate를 local에서 관리되도록 변경합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1642941403071&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;terraform init -migrate-state&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 리소스를 삭제합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1642941461701&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;terraform destroy&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;감사합니다.&lt;/p&gt;</description>
      <category>Iac</category>
      <category>terraform</category>
      <category>terraform state</category>
      <category>Terraform tfstate</category>
      <category>tfstate</category>
      <category>테라폼</category>
      <category>테라폼 상태관리</category>
      <author>no-easy-ray</author>
      <guid isPermaLink="true">https://no-easy-dev.tistory.com/34</guid>
      <comments>https://no-easy-dev.tistory.com/entry/Terraform-Terraform-State#entry34comment</comments>
      <pubDate>Sun, 23 Jan 2022 21:38:56 +0900</pubDate>
    </item>
    <item>
      <title>Terraform | Terraform 버전관리</title>
      <link>https://no-easy-dev.tistory.com/entry/Terraform-Terraform-%EB%B2%84%EC%A0%84%EA%B4%80%EB%A6%AC</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Terraform을 사용하면서 여러 Terraform버전을 사용해야 할 때가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럴 때마다 각각의 버전을 다운로드하는 것은 비효율적이고 귀찮습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 tfenv를 이용하여 Terraform버전을 관리하는 내용을 정리하려고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;tfenv&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;tfenv를 이용하면 여러 가지의 테라폼 버전을 다운로드할 수 있고 원하는 버전을 선택하여 사용할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 생각보다 간편합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;설치 방법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치방법은&amp;nbsp;&lt;a href=&quot;https://github.com/tfutils/tfenv&quot;&gt;tfenv&lt;/a&gt;에서 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Mac인 경우&lt;/p&gt;
&lt;pre id=&quot;code_1642770580178&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;brew install tfenv&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Linux인 경우&lt;/p&gt;
&lt;pre id=&quot;code_1642770585466&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git clone &amp;lt;https://github.com/tfutils/tfenv.git&amp;gt; ~/.tfenv

echo 'export PATH=&quot;$HOME/.tfenv/bin:$PATH&quot;' &amp;gt;&amp;gt; ~/.bash_profile

ln -s ~/.tfenv/bin/* /usr/local/bin&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;사용법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치가 완료되었으면 tfenv 명령을 이용하여 원하는 테라폼 버전을 설치할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치 가능한 테라폼 버전 목록 확인&lt;/p&gt;
&lt;pre id=&quot;code_1642770751010&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;tfenv list-remote&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;https://releases.hashicorp.com/terraform/ 경로에 있는 버전들을 가져옵니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원하는 버전 설치&lt;/p&gt;
&lt;pre id=&quot;code_1642770783366&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;tfenv install 1.1.3  #예시로 1.1.3 버전을 다운받습니다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다운로드한 테라폼 버전 사용&lt;/p&gt;
&lt;pre id=&quot;code_1642770805433&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;tfenv use 1.1.3 #다운받은 1.1.3버전을 사용합니다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치된 테라폼 버전 목록 확인&lt;/p&gt;
&lt;pre id=&quot;code_1642770811130&quot; class=&quot;applescript&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;tfenv list&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;tfenv_list.png&quot; data-origin-width=&quot;340&quot; data-origin-height=&quot;59&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/emEVlf/btrrlSQDFkj/987AOPa92Kfu3eXastWWc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/emEVlf/btrrlSQDFkj/987AOPa92Kfu3eXastWWc0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/emEVlf/btrrlSQDFkj/987AOPa92Kfu3eXastWWc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FemEVlf%2FbtrrlSQDFkj%2F987AOPa92Kfu3eXastWWc0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;340&quot; height=&quot;59&quot; data-filename=&quot;tfenv_list.png&quot; data-origin-width=&quot;340&quot; data-origin-height=&quot;59&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그림처럼 현재 다운로드한 목록을 볼 수 있고, 현재 사용 중인 버전에 &lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;*표시&lt;/b&gt;&lt;/span&gt;를 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 현재 사용 중인 테라폼 버전을 확인해보면 다운로드한 1.1.3 버전을 사용하는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1642770860410&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;terraform -v&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;마무리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 식으로 간편하게 필요한 테라폼 버전을 다운로드할 수 있고 사용할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테라폼을 설치할 때 하나의 버전만 설치하는 것보다 tfenv로 설치하여 사용하는 게 개인적으로 더 간편하다고 생각합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;감사합니다.&lt;/p&gt;</description>
      <category>Iac</category>
      <category>terraform</category>
      <category>tfenv</category>
      <category>테라폼</category>
      <category>테라폼 버전관리</category>
      <author>no-easy-ray</author>
      <guid isPermaLink="true">https://no-easy-dev.tistory.com/33</guid>
      <comments>https://no-easy-dev.tistory.com/entry/Terraform-Terraform-%EB%B2%84%EC%A0%84%EA%B4%80%EB%A6%AC#entry33comment</comments>
      <pubDate>Fri, 21 Jan 2022 22:19:49 +0900</pubDate>
    </item>
  </channel>
</rss>