<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Tae._.goo</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Fri, 20 Feb 2026 14:37:40 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>Tae._.goo</title>
            <url>https://velog.velcdn.com/images/taekyu_/profile/5ba3e490-7331-4209-b85d-8ff71a4e27c0/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. Tae._.goo. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/taekyu_" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[90DaysOfDevOps을 정리하며]]></title>
            <link>https://velog.io/@taekyu_/90DaysOfDevOps%EC%9D%84-%EC%A0%95%EB%A6%AC%ED%95%98%EB%A9%B0-d6gq3r8j</link>
            <guid>https://velog.io/@taekyu_/90DaysOfDevOps%EC%9D%84-%EC%A0%95%EB%A6%AC%ED%95%98%EB%A9%B0-d6gq3r8j</guid>
            <pubDate>Fri, 20 Feb 2026 14:37:40 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>해당 스터디는 90DaysOfDevOps
<a href="https://github.com/MichaelCade/90DaysOfDevOps">https://github.com/MichaelCade/90DaysOfDevOps</a>
를 기반으로 진행한 내용입니다.</strong></p>
</blockquote>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine1-90daysofdevops-스터디를-마무리하며span"><span style='background-color: MediumAquamarine'>1. 90DaysOfDevOps 스터디를 마무리하며</span></h2>
<hr>

<p>90DaysOfDevOps 스터디의 모든 강의 수강과 정리를 마쳤다. </p>
<p>방대한 DevOps 생태계와 클라우드 네이티브 기술들을 폭넓게 훑어볼 수 있는 시간이었다. 스터디를 리딩하며 함께 기술을 탐구하고, 실제 쿠버네티스 클러스터와 인프라를 운영하며 마주했던 여러 고민에 대한 해답을 엿볼 수 있었다.</p>
<p><strong>마지막 챕터인 만큼, 전체 강의 중에서도 내용이 특히 훌륭했거나 기술적으로 흥미로웠던 주제, 그리고 DevOps 엔지니어링 관점에서 앞으로 더 깊게 파고들어 공부해 볼 가치가 있는 강의들을 아래와 같이 추려보았다.</strong>
<br></p>
<p>📌 <span style="color: indianred"><strong>인상 깊었던 핵심 강의 리스트</strong></span></p>
<ul>
<li><p><span style="color: SlateBlue"><strong>Day 6.</strong></span> Kubernetes RBAC with Ansible: 쿠버네티스 RBAC 정책과 Ansible</p>
</li>
<li><p><span style="color: SlateBlue"><strong>Day 8.</strong></span> Culinary Coding: Crafting Infrastructure Recipes with OpenTofu: Terraform과 OpenTofu</p>
</li>
<li><p><span style="color: SlateBlue"><strong>Day 9.</strong></span> Why should developers care about container security?: 컨테이너 보안</p>
</li>
<li><p><span style="color: SlateBlue"><strong>Day 10.</strong></span> Is Kubernetes Too Complicated?: 쿠버네티스란?</p>
</li>
<li><p><span style="color: SlateBlue"><strong>Day 14.</strong></span> An introduction to API Security in Kubernetes: 웹 애플리케이션 방화벽(WAF)</p>
</li>
<li><p><span style="color: SlateBlue"><strong>Day 17.</strong></span> From Chaos to Resilience: Decoding the Secrets of Production Readiness: 서비스메시와 Istio</p>
</li>
<li><p><span style="color: SlateBlue"><strong>Day 19.</strong></span> Building Efficient and Secure Docker Images with Multi-Stage Builds: 멀티스테이지 빌드 (Multi-Stage Build)</p>
</li>
<li><p><span style="color: SlateBlue"><strong>Day 22.</strong></span> Test in Production with Kubernetes and Telepresence: 텔레프레즌스</p>
</li>
<li><p><span style="color: SlateBlue"><strong>Day 24.</strong></span> DevSecOps - Defined, Explained &amp; Explored: DevSecOps란</p>
</li>
<li><p><span style="color: SlateBlue"><strong>Day 25.</strong></span> Kube-Nation: Exploring the Land of Kubernetes: 쿠버네티스 아키텍처의 비유화 (국가)</p>
</li>
<li><p><span style="color: SlateBlue"><strong>Day 27.</strong></span> From Automated to Automatic - Event-Driven Infrastructure Management with Ansible: Ansible이란?</p>
</li>
<li><p><span style="color: SlateBlue"><strong>Day 33.</strong></span> GitOps made simple with ArgoCD and GitHub Actions: ArgoCD와 Github Actions을 이용한 CI/CD</p>
</li>
<li><p><span style="color: SlateBlue"><strong>Day 38.</strong></span> Open Standards: Empowering Cloud-Native Innovation: OCI (Open Container Initiative)와 K8s Interface</p>
</li>
<li><p><span style="color: SlateBlue"><strong>Day 39.</strong></span> Is TLS in Kubernetes really that hard to understand?: 쿠버네티스 인증서</p>
</li>
<li><p><span style="color: SlateBlue"><strong>Day 43.</strong></span> Let&#39;s go sidecarless in Ambient Mesh: Istio와 Ambient Mesh</p>
</li>
<li><p><span style="color: SlateBlue"><strong>Day 44.</strong></span> Exploring Firecracker: AWS Lambda와 Firecracker</p>
</li>
<li><p><span style="color: SlateBlue"><strong>Day 50.</strong></span> State of Cloud Native 2024: 주목받은 CNCF 생태계 툴</p>
</li>
<li><p><span style="color: SlateBlue"><strong>Day 52.</strong></span> Creating a custom Dev Container for your GitHub Codespace to start with Terraform on Azure: Github Codespace와 Dev Container</p>
</li>
<li><p><span style="color: SlateBlue"><strong>Day 55.</strong></span> Bringing Together IaC and CM with Terraform Provider for Ansible: Terraform과 Ansible</p>
</li>
<li><p><span style="color: SlateBlue"><strong>Day 60.</strong></span> Migrating a monolith to Cloud-Native and the stumbling blocks that you don’t know about: 마이그레이션을 굳이 해야 하는가?</p>
</li>
<li><p><span style="color: SlateBlue"><strong>Day 63.</strong></span> Diving into Container Network Namespaces: 쿠버네티스 CNI를 리눅스 커널로 구현하기</p>
</li>
<li><p><span style="color: SlateBlue"><strong>Day 68.</strong></span> Service Mesh for Kubernetes 101: The Secret Sauce to Effortless Microservices Management: Service Mesh (Istio)</p>
</li>
<li><p><span style="color: SlateBlue"><strong>Day 69.</strong></span> Enhancing Kubernetes security, visibility, and networking control logic at the Linux kernel: eBPF와 Cilium (K8s CNI)이란?</p>
</li>
<li><p><span style="color: SlateBlue"><strong>Day 70.</strong></span> Simplified Cloud Adoption with Microsoft&#39;s Terraforms Azure Landing Zone Module: 랜딩존이란?</p>
</li>
<li><p><span style="color: SlateBlue"><strong>Day 72.</strong></span> Infrastructure as Code with Pulumi: Pulumi란?</p>
</li>
<li><p><span style="color: SlateBlue"><strong>Day 73.</strong></span> Introducing the Terraform Test Framework: IaC 테스트</p>
</li>
<li><p><span style="color: SlateBlue"><strong>Day 76.</strong></span> All you need to know about AWS CDK: AWS CDK</p>
</li>
<li><p><span style="color: SlateBlue"><strong>Day 80.</strong></span> Unlocking K8s Troubleshooting Best Practices with Botkube: Botkube</p>
</li>
<li><p><span style="color: SlateBlue"><strong>Day 83.</strong></span> Saving Cloud Costs Using Existing Prometheus Metrics: KRR (Kubernetes Resource Recommender)</p>
</li>
<li><p><span style="color: SlateBlue"><strong>Day 84.</strong></span> Hacking Kubernetes For Beginners: 쿠버네티스 해킹</p>
</li>
<li><p><span style="color: SlateBlue"><strong>Day 87.</strong></span> Hands-on Performance Testing with k6: k6</p>
</li>
<li><p><span style="color: SlateBlue"><strong>Day 89.</strong></span> Seeding Infrastructures: Merging Terraform with Generative AI for Effortless DevOps Gardens: 시딩 엔진 (Seeding Engine)</p>
</li>
</ul>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine2-마치며span"><span style='background-color: MediumAquamarine'>2. 마치며</span></h2>
<hr>

<p>이번 스터디는 단순히 툴의 사용법을 익히는 것을 넘어, 왜 해당 기술이 등장했고 어떤 아키텍처적 이점을 주는지 깊이 고민해 볼 수 있는 계기가 되었다. </p>
<p><strong>특히 인프라 자동화(Ansible, Terraform)와 보안, 네트워크(eBPF, Istio) 영역은 단편적인 이해를 넘어 실질적인 구축 경험이 필수적임을 느꼈다.</strong></p>
<p>이 리스트에 포함된 주제들은 일회성 학습으로 끝내지 않고, 실제 인프라 환경이나 앞으로 진행할 프로젝트에 지속적으로 적용해 보며 완전히 내 것으로 만들어갈 계획이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[90DaysOfDevOps (Day 91)]]></title>
            <link>https://velog.io/@taekyu_/90DaysOfDevOps-Day-91-9ze5y1uv</link>
            <guid>https://velog.io/@taekyu_/90DaysOfDevOps-Day-91-9ze5y1uv</guid>
            <pubDate>Sun, 08 Feb 2026 07:45:09 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>해당 스터디는 90DaysOfDevOps
<a href="https://github.com/MichaelCade/90DaysOfDevOps">https://github.com/MichaelCade/90DaysOfDevOps</a>
를 기반으로 진행한 내용입니다.</strong></p>
</blockquote>
<p>** Day91 - Team Topologies and Platform Engineering **</p>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine1-빠른-흐름의-본질과-역-컨웨이-전략의-필요성span"><span style='background-color: MediumAquamarine'>1. 빠른 흐름의 본질과 역 컨웨이 전략의 필요성</span></h2>
<hr>

<p>데브옵스는 소규모 자율 팀이 피드백을 기반으로 빠르게 소프트웨어를 배포하는 것의 가치를 증명했다. </p>
<p><strong>하지만 진정한 의미의 빠른 흐름을 달성하기 위한 조직적, 문화적 변화는 여전히 미진한 상태다.</strong> </p>
<p><span style="color: indianred"><strong>우리는 기술보다 팀 구조와 상호작용에 주목해야 한다.</strong></span></p>
<h3 id="span-stylecolor-slateblue1-1-흐름과-사회-기술적-복잡성span"><span style="color: SlateBlue">1-1. 흐름과 사회-기술적 복잡성</span></h3>
<p>*<em>여기서 말하는 흐름이란 단순히 코드를 빨리 짜는 것이 아니라, 코드가 프로덕션 환경에 도달하기까지의 경로에 있는 모든 장애물을 제거하는 것을 의미한다. *</em></p>
<p>이는 서로 다른 팀과 도메인 간의 의존성을 해결하고, 팀 외부로 뻗어 있는 복잡한 기술의 덤불을 정리하는 과정이다.</p>
<p><span style="color: indianred"><strong>즉, 빠른 흐름은 주변의 사회-기술적 환경 전체를 단순화하여 가치를 더 빠르고 일관되게 전달하는 것이다.</strong></span>
<img src="https://velog.velcdn.com/images/taekyu_/post/91786c79-7bdf-46a1-b80b-2a340abe622e/image.png" width="50%" height="n%"></p>
<p>이러한 환경의 복잡성은 벤더의 제약, 예산 문제, 기술의 역사적 상태, 기존 팀 구조의 한계, 기술 부채 등 타당하고 역사적인 이유들로 인해 발생한다. </p>
<p><strong>따라서 모든 조직은 고유하며, 남들이 하는 방식을 그대로 따르는 것이 아니라 각 조직의 맥락에 맞는 독자적인 접근 방식이 필요하다.</strong>
<br></p>
<h3 id="span-stylecolor-slateblue1-2-컨웨이의-법칙과-역-컨웨이-전략span"><span style="color: SlateBlue">1-2. 컨웨이의 법칙과 역 컨웨이 전략</span></h3>
<p>*<em>조직 구조를 논할 때 컨웨이의 법칙(Conway&#39;s Law)은 매우 중요하다. *</em>
<img src="https://velog.velcdn.com/images/taekyu_/post/6e8c1bd1-8f92-48eb-99b6-6a72fa10e8f6/image.png" width="50%" height="n%"></p>
<p><span style="color: indianred"><strong>이 법칙은 조직은 그 조직의 의사소통 구조를 반영한 시스템을 설계하게 된다는 것을 의미한다. 쉽게 말해 여러분은 조직도를 소프트웨어로 배포한다는 것이다.</strong></span></p>
<p>문제는 실제 업무 현장에서는 사람들이 깔끔한 조직도에 구애받지 않고, 일을 처리하기 위해 필요한 사람과 무분별하게 소통한다는 점이다.</p>
<p>이는 조직도가 실제 소프트웨어 전달 흐름을 돕기는커녕, 서로 필요한 사람들을 멀리 떨어뜨려 놓음으로써 상황을 악화시킬 수 있음을 시사한다.
<br></p>
<p><span style="color: indianred"><strong>팀 토폴로지는 이를 뒤집는 역 컨웨이 전략(Reverse Conway Maneuver)을 제안한다.</strong> </span></p>
<p><strong>이는 만들고자 하는 소프트웨어 아키텍처와 시장에 전달하려는 가치에 맞춰 조직도를 역으로 설계하는 것이다.</strong></p>
<p>소프트웨어의 설계는 더 이상 팀의 설계와 분리될 수 없다. </p>
<p><strong>기술보다 팀을 우선순위에 두고, 팀 간의 불필요한 의존성을 줄여야 더 좋은 소프트웨어가 나온다는 것이 이 전략의 핵심이다.</strong></p>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine2-인지-부하의-한계와-플랫폼-팀의-역할span"><span style='background-color: MediumAquamarine'>2. 인지 부하의 한계와 플랫폼 팀의 역할</span></h2>
<hr>

<p>*<em>팀 토폴로지에서 가장 중요한 개념 중 하나는 팀이 감당할 수 있는 인지 부하(Cognitive Load)를 관리하는 것이다. *</em></p>
<p>이는 플랫폼 엔지니어링이 등장하게 된 직접적인 배경이 된다.</p>
<h3 id="span-stylecolor-slateblue2-1-스트림-정렬-팀stream-aligned-teams의-딜레마span"><span style="color: SlateBlue">2-1. 스트림 정렬 팀(Stream-aligned Teams)의 딜레마</span></h3>
<p><strong>스트림 정렬 팀은 비즈니스 가치 흐름에 맞춰 구성된 팀으로, 회사의 수익 창출에 가장 가까이 위치한다.</strong></p>
<p>이들은 상류 의존성은 적고 하류 의존성은 많은 특징을 가진다.</p>
<p>하지만 이 팀들이 모든 것을 다 할 수는 없다. </p>
<p><span style="color: indianred"><strong>던바의 수(Dunbar&#39;s number)에 따르면 인간이 맺을 수 있는 사회적 관계에는 한계가 있으며, 이는 팀이 감당할 수 있는 인지 부하의 총량에도 한계가 있음을 의미한다.</strong></span></p>
<p>스트림 정렬 팀이 비즈니스 로직 개발뿐만 아니라 클라우드 인프라, 네트워킹, 보안, CI/CD 등 모든 기술적 세부 사항까지 신경 써야 한다면, 그들의 인지 부하는 한계치를 초과하게 되고 결국 비즈니스 가치 전달 속도는 느려질 수밖에 없다.
<br></p>
<h3 id="span-stylecolor-slateblue2-2플랫폼-팀platform-teams-인지-부하를-줄이는-해결사span"><span style="color: SlateBlue">2-2.플랫폼 팀(Platform Teams): 인지 부하를 줄이는 해결사</span></h3>
<p><span style="color: indianred"><strong>여기서 플랫폼 팀이 등장한다.</strong></span></p>
<p><strong>플랫폼 팀의 존재 목적은 하부 인프라(클라우드, K8s, IAM, DB 등)를 담당하여 스트림 정렬 팀이 비즈니스 문제 해결에만 집중할 수 있도록 돕는 것이다.</strong></p>
<ul>
<li><p><span style="color: indianred"><strong>자동차와 타이어의 비유:</strong></span> 자동차 제조사(스트림 정렬 팀)는 타이어를 직접 만들지 않고 전문 타이어 제조사(플랫폼 팀)의 제품을 받아 조립한다. 제조사는 여전히 타이어를 차에 장착할 책임이 있지만, 고무의 배합 비율이나 트레드 패턴 제조법까지 알 필요는 없다.</p>
</li>
<li><p><span style="color: indianred"><strong>DevOps의 유지:</strong></span> 이는 Dev과 Ops을 다시 분리하는 것이 아니다. &quot;직접 만든 사람이 직접 운영한다(You build it, you run it)&quot;는 원칙은 여전히 유효하다. 다만, 운영하기 쉬운 컴포넌트를 제공받아 운영의 난이도를 낮추는 것이다.</p>
<br>

</li>
</ul>
<h3 id="span-stylecolor-slateblue2-3-플랫폼-팀이-제공하는-가치와-상호작용-모드span"><span style="color: SlateBlue">2-3. 플랫폼 팀이 제공하는 가치와 상호작용 모드</span></h3>
<p><strong>플랫폼 팀은 복잡한 기술을 추상화하여 서비스로서(As-a-Service) 제공한다.</strong></p>
<ol>
<li><p><span style="color: indianred"><strong>속도와 품질:</strong></span> 이미 검증된 상용 컴포넌트를 사용하므로 직접 구축할 필요가 없어 전달 속도가 빨라지고 품질이 보장된다.</p>
</li>
<li><p><span style="color: indianred"><strong>자율성:</strong></span> API와 문서 기반의 셀프 서비스로 제공되므로, 플랫폼 팀에 티켓을 보내거나 회의를 요청할 필요 없이 즉시 사용할 수 있다. (AWS를 쓸 때 아마존 직원에게 허락받지 않는 것과 같다.)</p>
</li>
<li><p><span style="color: indianred"><strong>조력(Facilitating):</strong></span> 서비스 제공 외에도, 플랫폼 팀의 전문가는 스트림 정렬 팀이 해당 서비스를 잘 활용할 수 있도록 코칭하고 베스트 프랙티스를 공유하는 &#39;조력자&#39; 역할을 수행한다. 이는 일시적인 상호작용이다.</p>
</li>
</ol>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine3-슬로이피케이션slow-ification과-지속적-진화span"><span style='background-color: MediumAquamarine'>3. 슬로이피케이션(Slow-ification)과 지속적 진화</span></h2>
<hr>

<p><strong>플랫폼 엔지니어링을 조직에 성공적으로 도입하기 위해서는 단순한 기술적 구현을 넘어선 전략적 접근과 리더십의 지원이 필수적이다.</strong></p>
<h3 id="span-stylecolor-slateblue3-1시작점-찾기-공통된-과제span"><span style="color: SlateBlue">3-1.시작점 찾기: 공통된 과제</span></h3>
<p>시작은 여러 팀이 공통적으로 겪고 있는 고통스러운 지점(Pain Point)을 찾는 것이다. </p>
<p>보통 기술 스택의 하단부인 컨테이너, 가상 머신(VM), 데이터베이스, IAM 등이 좋은 후보가 된다.</p>
<p><strong>적은 수의 팀이 의존하는 작은 컴포넌트부터 시작하여 성공 사례를 만들고, 이를 조직 전체로 확산시키는전략이 유효하다.</strong>
<br></p>
<h3 id="span-stylecolor-slateblue3-2핵심-전략-슬로이피케이션slow-ificationspan"><span style="color: SlateBlue">3-2.핵심 전략: 슬로이피케이션(Slow-ification)</span></h3>
<p>*<em>발표자는 책 *『Wiring the Winning Organization』</em>에서 소개된 &#39;슬로이피케이션(Slow-ification)&#39; 개념을 강조한다. **
<img src="https://velog.velcdn.com/images/taekyu_/post/7df96508-b493-44c9-8d49-4e06e4d6a69b/image.png" width="50%" height="n%"></p>
<p><strong>이는 &quot;속도를 높이기 위해 일시적으로 속도를 늦추는 것&quot;을 의미한다.</strong></p>
<ul>
<li><p><span style="color: indianred"><strong>시스템 2 사고(System 2 Thinking):</strong></span> 일상적인 업무 처리(시스템 1 사고)를 멈추고, 문제의 근본적인 해결책을 만들기 위해 깊고 창의적이며 노력이 필요한 사고(시스템 2 사고)를 해야 한다. 이는 톱질을 멈추고 톱날을 가는 시간과 같다.</p>
</li>
<li><p><span style="color: indianred"><strong>리더십의 지원:</strong></span> 이 과정은 외부에서 볼 때 &quot;당장 필요한 일을 안 하고 있는 것&quot;처럼 보일 수 있다. 따라서 매니저의 강력한 하향식(Top-down) 지원과 보호가 없으면, 팀은 압박을 이기지 못하고 다시 예전의 비효율적인 방식으로 돌아가게 된다.</p>
<br>

</li>
</ul>
<h3 id="span-stylecolor-slateblue3-3진화하는-조직과-도메인-주도-설계dddspan"><span style="color: SlateBlue">3-3.진화하는 조직과 도메인 주도 설계(DDD)</span></h3>
<p>*<em>팀 구조와 책임은 한 번 정하면 끝나는 정적인 것이 아니다. *</em></p>
<p><strong>조직이 성숙하고 시장 상황이 변함에 따라 팀 토폴로지는 계속 진화해야 한다.</strong></p>
<p>완벽한 팀 구조는 존재하지 않으며, 현실은 언제나 복잡하고 중복과 비효율이 존재한다. 중요한 것은 완벽함이 아니라 시간이 지남에 따라 흐름이 개선되는 방향성이다.</p>
<p><span style="color: indianred"><strong>조직이 커질수록 올바른 팀 경계를 찾기 위해 도메인 주도 설계(DDD)를 활용해야 한다.</strong> </span>
<img src="https://velog.velcdn.com/images/taekyu_/post/9d4b01f3-7715-4e2a-ac05-bf6829f96773/image.png" alt=""></p>
<p>특히 <strong>&#39;독립 서비스 휴리스틱(Independent Service Heuristic)&#39;</strong>을 활용해 볼 수 있다. </p>
<p>이는 &quot;이 컴포넌트나 기능을 독립적인 SaaS 서비스로 판매할 수 있는가?&quot;라고 자문해 봄으로써 팀과 도메인의 경계를 명확히 설정하는 데 도움을 준다.</p>
<p>결론적으로, 팀 토폴로지와 플랫폼 엔지니어링은 인지 부하를 관리하고 빠른 흐름을 만들어내기 위해 조직 구조와 기술 아키텍처를 일치시키는 끊임없는 여정이다.</p>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine4-결론span"><span style='background-color: MediumAquamarine'>4. 결론</span></h2>
<hr>

<p><strong>팀 토폴로지와 플랫폼 엔지니어링은 단순한 조직 개편이 아니라, 인지 부하를 관리하여 지속 가능한 빠른 흐름을 만드는 전략이다.</strong></p>
<p>완벽한 구조는 없기에, 조직은 끊임없이 진화하며 상황에 맞는 유연한 팀 구조를 찾아야 한다.</p>
<p><span style="color: indianred"></span>
<span style="color: SlateBlue"></span></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[90DaysOfDevOps (Day 90)]]></title>
            <link>https://velog.io/@taekyu_/90DaysOfDevOps-Day-90-42nkvx25</link>
            <guid>https://velog.io/@taekyu_/90DaysOfDevOps-Day-90-42nkvx25</guid>
            <pubDate>Sun, 08 Feb 2026 06:41:59 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>해당 스터디는 90DaysOfDevOps
<a href="https://github.com/MichaelCade/90DaysOfDevOps">https://github.com/MichaelCade/90DaysOfDevOps</a>
를 기반으로 진행한 내용입니다.</strong></p>
</blockquote>
<p>** Day 90 - Fighting fire with fire: Why we cannot always prevent technical issues with more tech **</p>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine1-무계획적-기술도입과-과잉-엔지니어링-span"><span style='background-color: MediumAquamarine'>1. 무계획적 기술도입과 과잉 엔지니어링 </span></h2>
<hr>

<p>새로운 기능을 개발하거나 버그를 수정해야 할 때, 우리는 종종 계획이나 문서화 단계를 건너뛰고 곧바로 코드를 짜거나 도구를 도입하려는 유혹에 빠진다. </p>
<p><strong>이러한 &#39;일단 만들자&#39; 식의 접근은 초기에는 빠르게 보일지 모르나, 장기적으로는 심각한 부작용을 초래한다.</strong></p>
<h3 id="span-stylecolor-slateblue1-1-이해할-수-없는-인프라와-전이적-의존성span"><span style="color: SlateBlue">1-1. 이해할 수 없는 인프라와 전이적 의존성</span></h3>
<p>문서화 없이 즉흥적으로(Ad-hoc) 문제를 해결하다 보면, 우리의 인프라는 마치 아이들의 장난감 블록처럼 변해버린다. </p>
<p><span style="color: indianred"><strong>여러 구성 요소가 연결은 되어 있지만, 도대체 어떻게, 왜 연결되어 있는지 아무도 명확히 설명할 수 없는 상태가 되는 것이다.</strong></span></p>
<p>이 과정에서 우리가 인지조차 하지 못하는 전이적 의존성 문제가 발생한다. 가장 대표적인 사례가 &#39;left-pad&#39; 사건이다.</p>
<ul>
<li><p><span style="color: indianred"><strong>사건 개요:</strong></span> 2016년, 한 개발자가 npm 및 &#39;Kick&#39;이라는 회사와의 이름 분쟁 끝에 홧김에 자신이 만든 패키지들을 npm에서 모두 삭제해버렸다.</p>
</li>
<li><p><span style="color: indianred"><strong>영향:</strong></span> 그중 &#39;left-pad&#39;라는 패키지는 공백을 포함해 고작 11~12줄짜리 코드에 불과했지만, 수많은 대형 프로젝트들이 이 패키지를 간접적으로 의존하고 있었기에 전 세계 인터넷 서비스들이 줄줄이 마비되는 사태가 벌어졌다.</p>
</li>
<li><p><span style="color: indianred"><strong>교훈:</strong></span> 내가 직접 사용하지 않더라도 내 프로젝트가 의존하는 도구가 또 다른 도구에 의존하고 있을 수 있다. 문서화와 파악이 되지 않은 의존성은 시한폭탄과 같다.</p>
<br>


</li>
</ul>
<h3 id="span-stylecolor-slateblue1-2-과잉-엔지니어링의-늪span"><span style="color: SlateBlue">1-2. 과잉 엔지니어링의 늪</span></h3>
<p>소프트웨어 개발 초기에는 기능적/비기능적 요구사항을 완벽히 알 수 없다. </p>
<p>문제는 원래 해결하려던 문제가 무엇이었는지에 대한 원본 기록이 없을 때 발생한다.</p>
<p>초기의 목적을 잊어버린 채 개발을 진행하다 보면, <span style="color: indianred"><strong>단순한 해결책이 존재함에도 불구하고 불필요하게 복잡하고 정교한 솔루션을 만드는 과잉 엔지니어링(Over-engineering)에 빠지게 된다.</strong></span></p>
<p><strong>이는 시스템의 복잡도를 불필요하게 높여 유지보수를 어렵게 만든다.</strong>
<br></p>
<h3 id="span-stylecolor-slateblue1-3-나한테-물어봐-문화의-위험성span"><span style="color: SlateBlue">1-3. &quot;나한테 물어봐&quot; 문화의 위험성</span></h3>
<p>*<em>문서화가 부재한 조직에서 흔히 발생하는 또 다른 문제는 구전에 의존하는 온보딩이다. *</em></p>
<p>팀장이나 시니어 엔지니어는 선의로 &quot;문서는 내 머릿속에 다 있으니 모르는 게 있으면 언제든 물어봐&quot;라고 말한다.</p>
<p><span style="color: indianred">*<em>하지만 이는 친절해 보일지 몰라도, 실제로는 주니어 엔지니어나 신규 입사자의 자기 주도성을 뺏는 행위다. *</em></span></p>
<p>스스로 정보를 찾아 해결할 수 없게 만듦으로써, 사소한 것 하나까지 질문해야 하는 의존적인 환경을 조성하고, 결국 팀 전체의 생산성을 저하시킨다.</p>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine2-문서화-주도-개발의-가치와-전략-span"><span style='background-color: MediumAquamarine'>2. 문서화 주도 개발의 가치와 전략 </span></h2>
<hr>

<p>*<em>프레젠테이션에서는 기술적 문제 해결의 대안으로 문서화 주도 소프트웨어 개발을 제안한다. *</em></p>
<p>문서화는 단순한 기록이 아니라, 비용을 절감하고 비즈니스 연속성을 보장하는 핵심 전략이다.</p>
<h3 id="span-stylecolor-slateblue2-1-문서화의-비즈니스적-가치span"><span style="color: SlateBlue">2-1. 문서화의 비즈니스적 가치</span></h3>
<p>*<em>장애는 곧 돈이다. *</em></p>
<p>2017년 영국 항공은 시스템 장애로 인해 약 8,000만 파운드(한화 약 1,300억 원 이상)의 손실을 입었다.</p>
<p><span style="color: indianred"><strong>잘 정리된 런북(Runbook)과 장애 대응 문서는 온콜(On-call) 담당자의 스트레스를 줄여주고, 대응 시간을 단축시킨다.</strong> </span></p>
<p>특히 미들 레벨 엔지니어가 야간 장애 대응 시, 언제 시니어를 호출해야 할지 명확한 기준을 제공함으로써 심리적 안정감을 주고 불필요한 호출을 줄여준다.
<br></p>
<h3 id="span-stylecolor-slateblue2-2-문서의-유형과-작성-전략span"><span style="color: SlateBlue">2-2. 문서의 유형과 작성 전략</span></h3>
<p><strong>문서는 크게 개발자 문서(Developer Documentation)와 사용자 문서(User Documentation)</strong>로 나뉜다. </p>
<p>문서를 작성할 때는 독자의 경험 수준과 문서의 목적(설치, 업그레이드, 기능 활용 등)을 반드시 고려해야 한다.</p>
<ul>
<li><p><span style="color: indianred"><strong>튜토리얼/하우투(How-to):</strong> </span> 특정 시나리오나 구현을 다루며, 수명이 짧을 수 있다.</p>
</li>
<li><p><span style="color: indianred"><strong>공식 문서:</strong> </span> 여러 유지보수자에 의해 장기간 관리되며, 보다 범용적인 설정을 다룬다.</p>
<br>

</li>
</ul>
<p><span style="color: SlateBlue"><strong>[추천 프레임워크: Diátaxis]</strong></span></p>
<p><strong>발표자는 문서 작성의 체계를 잡기 위해 Diátaxis 프레임워크를 추천한다.</strong> </p>
<p>이는 문서를 4가지로 구분하여 작성하는 방식이다.</p>
<ul>
<li><p><span style="color: indianred"><strong>튜토리얼(Tutorials):</strong> </span> 학습 지향 (직접 따라 하며 배우기)</p>
</li>
<li><p><span style="color: indianred"><strong>하우투 가이드(How-to Guides):</strong> </span> 문제 해결 지향 (특정 목표 달성)</p>
</li>
<li><p><span style="color: indianred"><strong>설명(Explanation):</strong> </span> 이해 지향 (배경 지식 및 개념 설명)</p>
</li>
<li><p><span style="color: indianred"><strong>레퍼런스(Reference):</strong> </span> 정보 지향 (API 명세 등)</p>
<br>

</li>
</ul>
<h3 id="span-stylecolor-slateblue2-3-기술을-활용한-문서화-k8sgptspan"><span style="color: SlateBlue">2-3. 기술을 활용한 문서화: K8sGPT</span></h3>
<p><strong>문서화에도 기술을 접목할 수 있다.</strong></p>
<p><img src="https://velog.velcdn.com/images/taekyu_/post/9280a6d0-db5c-4038-ba55-86c0ea08a33a/image.png" alt=""></p>
<p><strong>K8sGPT 같은 도구는 SRE의 지식을 코드로 내재화하고 AI를 활용하여 쿠버네티스 클러스터의 문제를 진단하고 설명해 준다.</strong></p>
<p>이는 마치 살아있는 문서처럼 작동하여, 주니어 엔지니어가 선배에게 묻지 않고도 에러의 원인과 해결책을 파악할 수 있게 돕는다.</p>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine3-카오스-엔지니어링-알-수-없는-것을-아는-것으로-span"><span style='background-color: MediumAquamarine'>3. 카오스 엔지니어링: 알 수 없는 것을 아는 것으로 </span></h2>
<hr>

<p>*<em>마지막으로, 문서화와 프로세스의 중요성은 카오스 엔지니어링(Chaos Engineering)에 적용될 때 더욱 빛을 발한다. *</em></p>
<p><span style="color: indianred"><strong>카오스 엔지니어링은 시스템에 의도적인 결함을 주입하여 회복 탄력성을 테스트하는 것이다.</strong></span></p>
<h3 id="span-stylecolor-slateblue3-1-지식의-4분면과-카오스-엔지니어링의-목표span"><span style="color: SlateBlue">3-1. 지식의 4분면과 카오스 엔지니어링의 목표</span></h3>
<p><strong>우리가 시스템에 대해 아는 지식은 네 가지 영역으로 나뉜다.</strong>
<img src="https://velog.velcdn.com/images/taekyu_/post/e42b2a2f-8fd0-4691-8448-115c5dfe0271/image.png" width="60%" height="n%"></p>
<ul>
<li><p><span style="color: indianred"><strong>Known Knowns (알고 있는 아는 것):</strong> </span> 우리가 인지하고 이해하는 영역. (문서화 대상)</p>
</li>
<li><p><span style="color: indianred"><strong>Known Unknowns (알고 있는 모르는 것):</strong> </span> 문제는 인지했지만 원인은 모르는 것. (예: 스토리지 레이어에 이슈가 있다는 건 알지만 정확한 원인은 모름)</p>
</li>
<li><p><span style="color: indianred"><strong>Unknown Knowns (모르고 있는 아는 것):</strong> </span> 이해는 하고 있지만 인지하지 못한 것. (직관이나 경험적으로 대처 가능하나 명시되지 않음)</p>
</li>
<li><p><span style="color: indianred"><strong>Unknown Unknowns (모르고 있는 모르는 것):</strong> </span> 가장 위험한 블랙박스 영역. 인지조차 못하고 있는 잠재적 위험.</p>
</li>
</ul>
<blockquote>
<p><strong>카오스 엔지니어링의 궁극적인 목표는 실험을 통해 Unknown Unknowns(블랙박스) 영역을 발견하고, 이를 실험을 통해 분석하여 Known Knowns(문서화된 지식) 영역으로 옮겨오는 것이다.</strong></p>
</blockquote>
<br>

<h3 id="span-stylecolor-slateblue3-2-실험의-프로세스와-사후-분석span"><span style="color: SlateBlue">3-2. 실험의 프로세스와 사후 분석</span></h3>
<p><strong>성공적인 카오스 엔지니어링을 위해서는 다음과 같은 체계적인 프로세스가 필요하다.</strong></p>
<ol>
<li><p><span style="color: indianred"><strong>매핑(Mapping):</strong> </span> 현재 인프라의 상태와 서비스 간의 내/외부 의존성을 시각화하여 파악한다.</p>
</li>
<li><p><span style="color: indianred"><strong>가설 수립 및 계획:</strong> </span> &quot;포드를 삭제하면 레플리카셋이 자동으로 복구할 것이다&quot;와 같은 가설을 세우고, 폭발 반경(Blast Radius)을 최소화하여 실험을 설계한다.</p>
</li>
<li><p><span style="color: indianred"><strong>실험 실행:</strong> </span> <code>Chaos Mesh</code>, <code>LitmusChaos</code> 등의 도구를 활용한다.</p>
</li>
<li><p><span style="color: indianred"><strong>사후 분석(Post-mortem):</strong> </span> 실험 후 무엇이 발생했고, 어떻게 대응했는지를 반드시 기록해야 한다. 이는 팀 전체의 학습 기회이자, 미래의 장애를 예방하는 자산이 된다. 
(도구: <code>incident.io</code>, <code>Rootly</code> 등 활용 가능)</p>
<br>

</li>
</ol>
<h3 id="span-stylecolor-slateblue3-3-결론-일단-적어라span"><span style="color: SlateBlue">3-3. 결론: &quot;일단 적어라&quot;</span></h3>
<p><strong>기술적 해결책을 찾기 전에 기록하는 습관을 들이라는 것이다.</strong></p>
<p>잘못된 내용을 적는 것이 아무것도 적지 않는 것보다 낫다. </p>
<p>과거에 작동했던 명령어가 지금은 작동하지 않을지라도, 그것은 미래의 팀원에게 훌륭한 단서가 된다. </p>
<p>거창한 문서가 아니더라도, 홈랩(Home lab)이나 개인 학습 노트부터 시작하여 자신이 겪은 문제와 해결 과정을 기록하고 공유하는 것이야말로 진정한 엔지니어링의 시작이다.</p>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine4-정리-및-결론-span"><span style='background-color: MediumAquamarine'>4. 정리 및 결론 </span></h2>
<hr>

<p>기술적 부채와 복잡성은 더 많은 도구가 아닌, 명확한 문서화와 체계적인 프로세스로 해결해야한다.</p>
<p><strong>&#39;일단 만들자&#39;는 유혹을 뿌리치고, 우리가 아는 것과 모르는 것을 기록하며 Unknown 영역을 줄여나가는 것이 진정한 엔지니어링이다.</strong></p>
<p>완벽한 문서를 쓰려 하기보다, 사소한 트러블슈팅 과정이라도 기록하고 공유하는 습관을 들여보자.</p>
<p><span style="color: indianred"><strong>이러한 기록들이 모여 팀의 리스크를 줄이고, 더 견고하고 회복 탄력성 있는 인프라를 만드는 가장 강력한 무기가 될 것이다.</strong></span></p>
<p><span style="color: indianred"></span>
<span style="color: SlateBlue"></span></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[90DaysOfDevOps (Day 89)]]></title>
            <link>https://velog.io/@taekyu_/90DaysOfDevOps-Day-89</link>
            <guid>https://velog.io/@taekyu_/90DaysOfDevOps-Day-89</guid>
            <pubDate>Sun, 08 Feb 2026 03:21:34 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>해당 스터디는 90DaysOfDevOps
<a href="https://github.com/MichaelCade/90DaysOfDevOps">https://github.com/MichaelCade/90DaysOfDevOps</a>
를 기반으로 진행한 내용입니다.</strong></p>
</blockquote>
<p>** Day 89 - Seeding Infrastructures: Merging Terraform with Generative AI for Effortless DevOps Gardens **</p>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine1-테라폼과-생성형-ai-결합-span"><span style='background-color: MediumAquamarine'>1. 테라폼과 생성형 AI 결합 </span></h2>
<hr>

<p><strong>기존의 Terraform 사용 방식이 인간이 코드를 한 줄씩 작성하고 검증하는 방식이었다면, 생성형 AI의 도입은 이 프로세스를 근본적으로 변화시킨다.</strong></p>
<ul>
<li><p><span style="color: indianred"><strong>코드 생성의 가속화:</strong></span> Amazon Bedrock의 Claude v2나 OpenAI의 GPT 모델들은 자연어 요구사항을 완벽한 테라폼 HCL(HashiCorp Configuration Language) 코드로 변환 가능</p>
</li>
<li><p><span style="color: indianred"><strong>단계별 추론:</strong></span> </p>
<ul>
<li><p>AI는 단순히 결과물만 내놓는 것이 아니라, &quot;먼저 VPC를 구성하고, 그 다음 서브넷을 나눈 뒤, EC2를 배치하라&quot;는 식의 순차적 사고가 가능함. </p>
</li>
<li><p>AutoGPT나 LangChain과 같은 프레임워크와 결합했을 때 더욱 강력해짐.</p>
</li>
</ul>
</li>
<li><p><span style="color: indianred"><strong><code>인간</code>-<code>AI</code>-<code>인프라</code>의 조화:</strong></span> AI가 초안을 빠르고 방대하게 작성하면, 인간은 이를 검수하고 전략적 의사결정을 내리는 구조로 업무가 재편</p>
</li>
</ul>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine2-seeding-engine이란-span"><span style='background-color: MediumAquamarine'>2. Seeding Engine이란? </span></h2>
<hr>

<p>*<em>우리가 흔히 사용하는 ChatGPT나 베드락(Bedrock) 콘솔은 기본적으로 수동적이다. *</em></p>
<p>개발자가 &quot;EC2 인스턴스 하나 만들어줘&quot;라고 입력해야만 비로소 코드를 뱉어낸다.</p>
<p><span style="color: indianred"><strong>하지만 시딩 엔진은 능동적이고 지속적이다.</strong></span></p>
<ul>
<li><p><span style="color: indianred"><strong>정의:</strong></span> 조직의 요구사항과 Best Practice를 입력받아, Terraform 코드를 생성(Seeding)할 뿐만 아니라, 배포된 인프라가 건강하게 유지되도록 지속적으로 관리하고 치유하는 통합 자동화 시스템</p>
</li>
<li><p><span style="color: indianred"><strong>비유:</strong></span> 마트에서 다 자란 화분을 사 오는 것이 아니라, 유능한 정원사(AI Engine)를 고용하여 씨앗을 심고, 물을 주고, 잡초를 뽑게 하는 것과 같다.</p>
</li>
</ul>
<p><strong>프레젠테이션에서는 해당 시스템이 단순한 질의응답 도구를 넘어선다고 강조한다.</strong></p>
<p>그 차별점은 다음 세 가지로 요약된다.</p>
<ol>
<li><p><span style="color: SlateBlue"><strong>Context을 이해하는 맞춤형 인프라 (RAG 활용)</strong></span></p>
<ul>
<li><p>일반적인 AI 모델은 인터넷에 있는 범용적인 지식으로 코드를 짠다. 하지만 시딩 엔진은 RAG(검색 증강 생성) 기술을 접목하여 조직의 특수성을 이해한다.</p>
</li>
<li><p><span style="color: indianred"><strong>일반 AI:</strong></span> &quot;보안 그룹 만들어줘&quot;라고 하면 0.0.0.0/0을 허용하는 등 범용적이지만 보안에 취약한 코드를 생성할 가능성이 있다.</p>
</li>
<li><p><span style="color: indianred"><strong>시딩 엔진:</strong></span> *<em>기업 내부의 보안 가이드라인, 기존 아키텍처 문서, 레거시 코드를 참조한다. *</em>
따라서 &quot;우리 회사 보안 정책인 22번 포트 폐쇄 및 사내 VPN 대역만 허용&quot;하는 규칙을 준수하며 코드를 생성한다. 즉, 조직의 가드레일 안에서 안전하게 작동한다.</p>
<br>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>생성(Day 1)을 넘어선 운영(Day 2)의 자동화</strong></span></p>
<ul>
<li><p>코드를 짜고 배포하는 것에서 끝나는 것이 아니라, 인프라가 배포된 이후의 삶(Day 2 Operations)까지 관여한다.</p>
</li>
<li><p><span style="color: indianred"><strong>프로액티브 관리:</strong></span> 발표된 아키텍처에서 보았듯, 시딩 엔진은 CloudWatch 및 Lambda와 유기적으로 연결되어 있다.</p>
</li>
<li><p><span style="color: indianred"><strong>작동 시나리오:</strong></span> 트래픽이 급증하여 사이트가 느려지는 상황을 가정해 보자.</p>
<ol>
<li><p>CloudWatch가 이상 징후를 감지한다.</p>
</li>
<li><p>시딩 엔진(Lambda)으로 신호를 보낸다.</p>
</li>
<li><p>엔진이 이를 분석하여 &quot;Auto Scaling Group의 Max Capacity를 늘려야 합니다&quot;라고 판단한다.</p>
</li>
<li><p>테라폼 코드를 스스로 수정하고 재배포를 자동화한다.</p>
<br>
</li>
</ol>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>인간과 AI의 협업 프로세스 내재화</strong></span></p>
<ul>
<li><p>시딩 엔진은 AI가 독단적으로 행동하지 않도록 설계된다.</p>
</li>
<li><p><span style="color: indianred"><strong>초안 작성:</strong></span> AI가 복잡한 인프라 구성의 80~90%를 순식간에 구축한다.</p>
</li>
<li><p><span style="color: indianred"><strong>인간의 검수:</strong></span> 엔지니어는 처음부터 코드를 짜는 것이 아니라, AI가 만든 구조가 전략적으로 맞는지, 보안상 치명적인 문제는 없는지 검토하는 역할로 전환된다.</p>
</li>
<li><p><span style="color: indianred"><strong>피드백 루프:</strong></span> 인간이 코드를 수정하면, 엔진은 이를 학습하여 다음 배포 때 더 정확한 코드를 생성한다.</p>
<br>


</li>
</ul>
</li>
</ol>
<p><strong>발표자는 이 개념을 실제 AWS 환경에 구현했다. 그 기술적 흐름은 다음과 같이 이루어진다.</strong>
<img src="https://velog.velcdn.com/images/taekyu_/post/e2591b15-7f89-40e6-bee2-e089cd5ddae4/image.png" width="70%" height="n%"></p>
<ol>
<li><p><span style="color: SlateBlue"><strong>입력:</strong></span> 엔지니어가 확장 가능한 웹 앱 인프라 필요라는 자연어 요구사항이나 설정 파일(JSON/YAML)을 입력한다.</p>
</li>
<li><p><span style="color: SlateBlue"><strong>생성 (Generation via Bedrock):</strong></span> EC2에 호스팅된 엔진(Python 애플리케이션)이 Amazon Bedrock(Claude v2)을 호출한다. 이때 프롬프트 엔지니어링을 통해 테라폼 HCL 문법과 사내 규칙을 준수하도록 강제한다.</p>
</li>
<li><p><span style="color: SlateBlue"><strong>검증 및 배포 :</strong></span> 생성된 코드는 S3에 저장되고, AWS CodePipeline을 통해 <code>terraform plan</code> -&gt; <code>validate</code> -&gt; <code>apply</code> 과정을 거친다.</p>
</li>
<li><p><span style="color: SlateBlue"><strong>감지 및 대응 :</strong></span> 인프라에 변경이 필요하거나 문제가 생기면, CloudWatch 알람이 다시 엔진(Lambda)을 깨워 코드를 수정하고 인프라를 치유한다.</p>
</li>
</ol>
<p><strong>발표에서 공개된 시딩 엔진의 아키텍처는 AWS의 관리형 서비스들을 유기적으로 결합하여 생성-배포-감지-대응의 완전한 파이프라인을 구축했다.</strong></p>
<ul>
<li><p><span style="color: SlateBlue"><strong>아키텍처 구성 요소 상세</strong></span></p>
<ul>
<li><p><span style="color: indianred"><strong>Amazon EC2 (Host):</strong></span> 시딩 엔진의 본체(Python 애플리케이션)가 구동되는 서버다. 전체 워크플로우를 조율하는 두뇌 역할을 한다.</p>
</li>
<li><p><span style="color: indianred"><strong>Amazon Bedrock (Generative AI):</strong></span> Anthropic Claude v2 모델을 사용하여, 보안성을 유지한 채 내부 네트워크로 AI 모델을 호출하고 테라폼 코드를 생성한다.</p>
</li>
<li><p><span style="color: indianred"><strong>Amazon S3 (Storage &amp; Trigger):</strong></span> 생성된 테라폼 템플릿(<code>.tf</code>)이 저장된다. 파일이 업로드되거나 수정되는 이벤트가 발생하면, 이를 트리거로 후속 자동화 작업이 시작된다.</p>
</li>
<li><p><span style="color: indianred"><strong>AWS CodeBuild &amp; CodePipeline (CI/CD):</strong></span> S3의 변경 사항을 감지하여 실제로 <code>terraform plan</code>, <code>terraform apply</code>를 수행하는 배포 파이프라인이다.</p>
</li>
<li><p><span style="color: indianred"><strong>Amazon CloudWatch &amp; AWS Lambda:</strong></span></p>
<ul>
<li><p>CloudWatch는 인프라의 상태를 실시간으로 감시한다.</p>
</li>
<li><p>이상이 감지되면 Lambda가 트리거되어, EC2에 있는 시딩 엔진에게 &quot;코드를 수정하라&quot;는 신호를 보내거나 즉각적인 복구 스크립트를 실행한다. </p>
</li>
</ul>
</li>
<li><p><span style="color: indianred"><strong>AWS Secrets Manager:</strong></span> Bedrock API 키나 DB 접근 정보 등 민감한 데이터를 코드에서 분리하여 안전하게 관리한다.</p>
</li>
</ul>
</li>
</ul>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine3-프롬프트-엔지니어링과-코드-구현-전략-span"><span style='background-color: MediumAquamarine'>3. 프롬프트 엔지니어링과 코드 구현 전략 </span></h2>
<hr>

<p><strong>시딩 엔진의 아키텍처를 갖췄다면, 이제는 이 엔진을 실제로 똑똑하게 움직이게 할 두뇌를 설계해야 한다.</strong></p>
<p><span style="color: indianred"><strong>프레젠테이션에서는 이 과정에서 가장 중요한 것은 AI에게 작업을 지시하는 프롬프트 엔지니어링과 결과를 검증하는 피드백 루프라고 강조한다.</strong></span></p>
<p>AI의 창의성을 기술적으로 통제하고, 결과물을 엄격하게 검증하는 과정이 없다면 자동화는 오히려 리스크가 될 수 있기 때문이다.</p>
<ul>
<li><p><span style="color: indianred"><strong>구체적 프롬프트:</strong></span> &quot;웹 앱 만들어줘&quot; 같은 추상적 지시는 지양한다. 대신 &quot;EC2, Auto Scaling Group, ELB, RDS, S3, IAM Role, VPC 등을 포함한 아키텍처&quot;와 같이 필요한 구성 요소를 명확히 나열하여 청사진을 제시해야 AI가 정확한 코드를 작성한다.</p>
</li>
<li><p><span style="color: indianred"><strong>파라미터 튜닝:</strong></span> 인프라 코드는 소설이 아니므로 창의성보다는 팩트와 정확성이 필수다. 모델의 <code>Temperature</code>와 <code>Top_P</code> 값을 0에 가깝게 설정하여, 존재하지 않는 리소스를 만들어내는 Hallucination 현상을 차단하고 일관된 결과를 얻어야 한다.</p>
</li>
<li><p><span style="color: indianred"><strong>파이썬 구현:</strong></span> <code>boto3 라이브러리</code>로 <code>Bedrock(Claude v2)</code>을 호출하고, 응답받은 JSON에서 코드를 추출해 <code>.tf</code> 파일로 저장한다. 이후 <code>subprocess</code> 모듈로 <code>terraform init</code>과 <code>apply</code>를 연쇄 실행하여 코드 작성부터 배포까지를 하나의 함수로 자동화한다.</p>
</li>
<li><p><span style="color: indianred"><strong>자동화된 테스트:</strong></span> 문법적으로 옳은 코드가 보안적으로도 안전하다는 보장은 없다. 배포 전 <code>Checkov</code>, <code>TFLint</code>, <code>Terratest</code> 같은 도구를 파이프라인에 심어 SSH 포트 개방이나 리소스 제한 같은 정책 위반을 기계적으로 걸러내야 한다.</p>
</li>
<li><p><span style="color: indianred"><strong>인간 개입:</strong></span> 기계적인 검증을 넘어 조직적인 피드백이 필요하다. 데이터 분석가나 아키텍트 등 다양한 직군의 요구사항을 반영해 프롬프트를 개선하고, 특히 민감한 보안 설정은 최종적으로 인간의 승인을 거치도록 프로세스를 설계해야 한다.</p>
</li>
</ul>
<p>이처럼 시딩 엔진은 단순히 코드를 생성하는 것을 넘어, <strong>&quot;믿어라, 하지만 검증하라(Trust, but Verify)&quot;</strong>는 원칙 아래 정교한 지시와 다층적인 검증 과정을 거쳐야 신뢰할 수 있는 시스템으로 완성된다.</p>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine4-케이스-스터디-및-결론-span"><span style='background-color: MediumAquamarine'>4. 케이스 스터디 및 결론 </span></h2>
<hr>

<p>프레젠에이션에서는 급성장하는 웹사이트 프로젝트에 이 시딩 엔진을 도입했다. </p>
<p>*<em>그 결과 트래픽 변동에 따라 인프라가 자동으로 확장되는 Adaptive Scaling 환경을 구축했으며, 다운타임과 유지보수 비용을 획기적으로 절감했다. *</em></p>
<p>엔지니어는 단순 코딩 시간은 줄이고 전략적 설계에 집중할 수 있게 되었다.</p>
<p><span style="color: SlateBlue"><strong>핵심 요약</strong></span></p>
<ul>
<li><p><span style="color: indianred"><strong>나만의 엔진 구축:</strong></span> 베드락과 같은 파운데이션 모델을 그대로 쓰지 말고, 조직의 데이터와 가이드라인을 학습시켜 최적화해야 한다.</p>
</li>
<li><p><span style="color: indianred"><strong>협업 AI :</strong></span> 미래의 데브옵스는 AI가 인간을 대체하는 것이 아니라, 인간이 AI라는 강력한 파트너를 감독하고 협업하는 형태로 진화할 것이다.</p>
</li>
<li><p><span style="color: indianred"><strong>보안 타협 금지:</strong></span> 자동화의 편리함에 취해 보안을 놓치면 안 된다. 보안 검수는 AI와 인간의 이중 레이어로 철저히 수행되어야 한다.</p>
</li>
</ul>
<p><span style="color: indianred">*<em>결론적으로, 시딩 엔진은 인프라를 심고 스스로 자라나게 관리하는 새로운 데브옵스의 지평을 열고 있다. *</em></span></p>
<p><strong>이제 엔지니어는 Coder에서 AI 엔진의 설계자(Architect)로 역할을 확장해야 할 때다.</strong></p>
<p><span style="color: indianred"></span>
<span style="color: SlateBlue"></span></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[90DaysOfDevOps (Day 88)]]></title>
            <link>https://velog.io/@taekyu_/90DaysOfDevOps-Day-88-8x1dn2jm</link>
            <guid>https://velog.io/@taekyu_/90DaysOfDevOps-Day-88-8x1dn2jm</guid>
            <pubDate>Sat, 07 Feb 2026 06:56:43 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>해당 스터디는 90DaysOfDevOps
<a href="https://github.com/MichaelCade/90DaysOfDevOps">https://github.com/MichaelCade/90DaysOfDevOps</a>
를 기반으로 진행한 내용입니다.</strong></p>
</blockquote>
<p>** Day 88 - What Developers Want from Internal Developer Portals **</p>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine1-idp의-배경-span"><span style='background-color: MediumAquamarine'>1. IDP의 배경 </span></h2>
<hr>

<p><strong>지난 5년 동안 마이크로서비스, 쿠버네티스, 클라우드 등의 기술은 조직의 효율성을 높여주었지만, 동시에 그만큼의 부작용인 복잡성을 초래했다.</strong></p>
<ul>
<li><p><span style="color: indianred"><strong>마이크로서비스와 쿠버네티스:</strong></span> 병렬 작업을 가능하게 하여 배포 속도를 높였지만, 너무 많은 서비스가 파편화되면서 소유권을 파악하고 전체 생태계를 이해하는 것이 불가능에 가까워졌다.</p>
</li>
<li><p><span style="color: indianred"><strong>클라우드 호스팅:</strong></span> 리소스 생성이 쉬워지고 비용이 저렴해졌지만, 이로 인해 정체를 알 수 없는 리소스가 방치되는 Sprawl 현상이 발생했다.</p>
</li>
<li><p><span style="color: indianred"><strong>도구의 홍수:</strong></span> 더 빠른 개발을 위해 수많은 도구를 도입했지만, 잦은 컨텍스트 스위칭과 알림 공해로 인해 오히려 개발자의 집중력을 저해하고 있다.</p>
</li>
</ul>
<br>

<p><span style="color: SlateBlue"><strong>기존 도구들의 한계: Context의 실종</strong></span></p>
<p>현재 시장의 도구들은 각자의 영역에서는 훌륭하지만, 전체를 꿰뚫는 통찰력을 제공하지 못한다.</p>
<ul>
<li><p><span style="color: indianred"><strong>APM/모니터링 (Datadog 등):</strong></span> Quality를 측정하지만, 해당 서비스가 무엇이며 왜 존재하는지에 대한 맥락은 없다.</p>
</li>
<li><p><span style="color: indianred"><strong>엔지니어링 메트릭 (DORA 등):</strong></span> 병목 현상은 알려주지만, 데이터가 정적이라 실제 Action으로 이어지기 어렵다.</p>
</li>
<li><p><span style="color: indianred"><strong>워크플로우 도구 (Git, Jira):</strong></span> 프로세스를 관리하지만, 우리가 올바른 방식으로 구축하고 있는지에 대한 가시성은 부족하다.</p>
</li>
</ul>
<p>결국 가장 큰 문제는 이 모든 파편화된 정보를 하나로 연결하여 <strong>&quot;이 서비스는 누가 만들었고, 어떤 리소스와 연결되며, 현재 상태는 어떠한가?&quot;</strong>를 보여주는 Entity Graph의 부재다. </p>
<p><span style="color: indianred"><strong>IDP는 바로 이 끊어진 연결고리를 잇는 역할을 해야 한다.</strong></span></p>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine2-개발자가-idp에서-진정으로-원하는-3가지-span"><span style='background-color: MediumAquamarine'>2. 개발자가 IDP에서 진정으로 원하는 3가지 </span></h2>
<hr>

<p><strong>Cortex가 50명의 엔지니어를 대상으로 &quot;IDP에서 무엇을 원하는가?&quot;를 설문한 결과, 개발자들의 고통과 니즈는 다음 세 가지로 명확히 요약된다.</strong></p>
<ol>
<li><p><span style="color: SlateBlue"><strong>정보 탐색의 고통</strong></span></p>
<ul>
<li><p>개발자들은 서비스, 리소스, 인프라 정보가 수십 개의 도구에 흩어져 있어 필요한 정보를 찾는 데 엄청난 시간을 낭비한다.</p>
</li>
<li><p><span style="color: indianred"><strong>온보딩의 어려움:</strong></span> 신규 입사자가 전체 시스템 구조를 파악하는 데 오랜 시간이 걸린다.</p>
</li>
<li><p><span style="color: indianred"><strong>장애 대응 지연:</strong></span> 한밤중에 모르는 서비스의 알림을 받았을 때, 소유자가 누구인지, Runbook은 어디에 있는지 찾을 수 없다.</p>
</li>
<li><p><span style="color: indianred"><strong>협업의 장벽:</strong></span> 내 기능이 다른 팀의 서비스와 상호작용할 때, 누구와 소통해야 하는지 파악하기 어렵다.</p>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue">*<em>우선순위의 불명확성 *</em></span></p>
<ul>
<li><p>보안(Snyk), 모니터링(Datadog), 기획(Jira), 코드 품질(SonarQube) 등 사방에서 알림과 요구사항이 쏟아진다.</p>
</li>
<li><p>이 소음 속에서 개발자는 <strong>&quot;지금 당장 내가 무엇을 먼저 처리해야 하는가?&quot;</strong>를 판단하기 어렵다. </p>
</li>
<li><p>개발자는 주관적인 판단이 아닌, 조직 차원의 명확한 우선순위 가이드를 원한다.</p>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue">*<em>템플릿과 셀프 서비스 *</em></span></p>
<ul>
<li><p><span style="color: indianred"><strong>개발자가 꼽은 IDP의 가장 필요한 기능 1위는 템플릿(Templates)이다.</strong></span></p>
</li>
<li><p>개발자는 새로운 프로젝트를 시작할 때마다 복잡한 초기 설정을 반복하고 싶어 하지 않는다.</p>
</li>
<li><p>조직의 Best Practice가 이미 적용된 골든 패스(Golden Path)를 통해, 버튼 클릭 몇 번으로 즉시 개발 가능한 환경을 구축하기를 원한다.</p>
</li>
</ul>
</li>
</ol>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine3-cortex의-해법-실행-가능성-중심의-기능span"><span style='background-color: MediumAquamarine'>3. Cortex의 해법: 실행 가능성 중심의 기능</span></h2>
<hr>

<p><span style="color: indianred">*<em>개발자 포털이 실패하는 가장 큰 이유는 정보의 무덤이 되기 때문이다. *</em></span></p>
<p>Cortex는 정보 제공을 넘어 <strong>그래서 지금 무엇을 해야 하는가?</strong>에 대한 답을 주고, 개발자가 즉시 행동할 수 있도록 돕는 5가지 핵심 기능을 제공한다.</p>
<ol>
<li><p><span style="color: SlateBlue"><strong>기록 시스템 (System of Record)과 자동 발견</strong></span></p>
<ul>
<li><p>많은 조직이 엑셀이나 Wiki에 서비스 목록을 수동으로 정리하지만, 이는 금방 낡은 데이터가 된다. Cortex는 이를 자동화한다.</p>
</li>
<li><p><span style="color: indianred"><strong>진실의 원천 (Source of Truth):</strong></span> Cortex는 기존 도구(Jira, GitHub, Snyk 등)를 대체하지 않는다. <strong>대신 50개 이상의 도구와 연동하여 현재 상태가 가장 정확한 데이터를 실시간으로 가져온다.</strong> 팀 정보는 HR 시스템(Workday)에서, 보안 정보는 보안 도구(Snyk)에서 가져와 하나로 합친다.</p>
</li>
<li><p><span style="color: indianred"><strong>자동 발견:</strong></span> 개발자가 일일이 &quot;이 서비스는 제가 만들었어요&quot;라고 입력할 필요가 없다. Cortex가 도구 간의 관계를 분석하여 <strong>&quot;이 GitHub 레포지토리는 저 쿠버네티스 클러스터에 배포되어 있고, 소유권은 A팀에게 있다&quot;</strong>는 의존성 그래프를 자동으로 생성하고 최신 상태로 유지한다.</p>
<br>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue">*<em>강력한 쿼리 빌더 *</em></span></p>
<ul>
<li><p>수집된 데이터가 단순히 쌓여만 있으면 의미가 없다. Cortex는 흩어진 데이터를 조합하여 복잡한 질문에 즉시 답할 수 있는 능력을 제공한다.</p>
</li>
<li><p><span style="color: indianred"><strong>복합 질문 해결:</strong></span> 과거에는 보안팀, 인프라팀, 개발팀에게 각각 물어봐야 했던 질문을 한 번에 해결한다.</p>
</li>
<li><p><span style="color: indianred"><strong>실전 예시:</strong></span></p>
<ul>
<li><p>&quot;Log4j 취약점 버전이 포함된 라이브러리를 쓰면서(보안), 최근 24시간 동안 배포되지 않은(인프라) 서비스 목록을 줘.&quot;</p>
</li>
<li><p>&quot;개인정보(PII)가 포함된 DB를 사용하는데(데이터), 백업 설정이 없는(인프라) 위험한 서비스는 어디인가?&quot;</p>
<br>
</li>
</ul>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue">*<em>스코어카드(Scorecards)와 게임화 *</em></span></p>
<ul>
<li><p>조직의 표준을 지키라고 강요하는 대신, 게임처럼 레벨을 올리도록 유도하는 기능이다. 리더십에게는 현황판이 되고, 개발자에게는 명확한 가이드가 된다.</p>
</li>
<li><p><span style="color: indianred"><strong>표준의 자동화:</strong></span> 배포 전 체크리스트 같은 문서를 자동화된 규칙으로 만든다. 사람이 검사하는 것이 아니라, 시스템이 데이터(테스트 커버리지, 보안 점수 등)를 보고 자동으로 점수를 매긴다.</p>
</li>
<li><p><span style="color: indianred"><strong>단계별 성숙도:</strong></span> 등급을 나누어 동기를 부여한다.</p>
<ul>
<li><p>🥉 <strong>브론즈 (기본):</strong> 서비스 소유자가 등록되어 있고, Readme 파일이 있는가?</p>
</li>
<li><p>🥈 <strong>실버 (중간):</strong> 유닛 테스트가 자동화되어 있고, 당번(On-call) 로테이션이 설정되어 있는가?</p>
</li>
<li><p>🥇 <strong>골드 (최상):</strong> SLO(서비스 수준 목표)를 추적하고 있으며, 치명적인 취약점이 0개인가?</p>
</li>
</ul>
</li>
<li><p><span style="color: indianred"><strong>리더십 리포팅:</strong></span> 경영진은 &quot;우리 조직의 서비스 건전성이 지난달 대비 얼마나 좋아졌는가?&quot;, &quot;어떤 팀이 리스크가 가장 높은가?&quot;를 데이터로 한눈에 파악할 수 있다.</p>
<br>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>Self-Service와 스캐폴더(Scaffolder)</strong></span></p>
<ul>
<li><p>*<em>개발자가 가장 원하는 기능 1위 *</em></p>
</li>
<li><p><strong>새로운 프로젝트를 시작할 때, 고민하지 않고 버튼 하나로 완벽한 환경을 만드는 것</strong></p>
</li>
<li><p><span style="color: indianred"><strong>스캐폴더 (Scaffolder):</strong></span> 발판이라는 뜻처럼, 프로젝트의 뼈대를 자동으로 만들어준다. 오픈 소스인 쿠키커터(Cookiecutter)를 기반으로 하여 보일러플레이트(기본 코드) 생성을 자동화한다.</p>
</li>
<li><p><span style="color: indianred"><strong>피드백 루프와 골든 패스:</strong></span> 단순히 코드만 생성하는 게 아니다. Cortex의 템플릿을 사용하면 <strong><code>Git 저장소 생성 + 기본 코드 작성 + 카탈로그 등록</code></strong>이 한 번에 끝난다.</p>
</li>
<li><p><span style="color: indianred"><strong>동기 부여:</strong></span> 개발자에게 <strong>&quot;이 템플릿을 쓰면, 스코어카드에서 자동으로 실버등급을 달성합니다&quot;</strong>라고 안내한다. 개발자는 편해서 좋고, 조직은 자연스럽게 표준을 준수시킬 수 있다.</p>
<br>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>개발자 홈페이지와 플러그인</strong></span></p>
<ul>
<li><p>개발자에게 불필요한 알림을 줄이고, 나에게 중요한 정보만 보여주는 개인화된 공간이다.</p>
</li>
<li><p><span style="color: indianred"><strong>개인화된 대시보드:</strong></span> 로그인하자마자 &quot;내가 당번인가?&quot;, &quot;내가 리뷰해야 할 코드는 무엇인가?&quot;, &quot;내 서비스 점수는 몇 점인가?&quot;를 보여준다. 또한 Slack 등으로 <strong>&quot;지금 이것부터 처리하세요&quot;</strong>라고 넛지(Nudge, 부드러운 개입)를 보내 행동을 유도한다.</p>
</li>
<li><p><span style="color: indianred"><strong>플러그인 아키텍처:</strong></span> Cortex가 기본으로 제공하지 않는 기능도 문제없다. React/TypeScript를 사용해 조직 고유의 도구를 포털 안에 심을 수 있다. (예: 사내 전용 배포 UI나 K8s 제어판을 포털 메뉴로 통합).</p>
</li>
</ul>
</li>
</ol>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine4-성공적인-idp-도입을-위한-4단계-로드맵span"><span style='background-color: MediumAquamarine'>4. 성공적인 IDP 도입을 위한 4단계 로드맵</span></h2>
<hr>

<p><span style="color: indianred">*<em>IDP 도입에 실패하는 가장 큰 이유는 데이터 없이 셀프 서비스부터 구축하려 하기 때문이다. *</em></span></p>
<p>Cortex는 다음의 순서로 도입할 것을 강력히 권장한다.</p>
<p><span style="color: SlateBlue"><strong>1단계: 정보 수집 및 집계 (Inventory &amp; Aggregation)</strong></span></p>
<ul>
<li><p>가장 먼저 <strong>무엇이 존재하는지를 파악</strong>해야 한다. </p>
</li>
<li><p>서비스, 인프라, 리소스, 소유권 정보를 긁어모아 카탈로그를 구축하라. </p>
</li>
<li><p>현재 상태를 모르면 개선할 수 없다.</p>
</li>
</ul>
<p><span style="color: SlateBlue"><strong>2단계: 평가 및 목표 설정 (Assess &amp; North Star)</strong></span></p>
<ul>
<li><p>데이터가 모였다면 <strong>우리는 어디에 있는가?를 평가</strong>해야 한다. </p>
</li>
<li><p>조직이 중요하게 생각하는 가치(신뢰성, 보안, 생산성 등)에 대한 Baseline을 설정하고, 목표를 정하라.</p>
</li>
</ul>
<p><span style="color: SlateBlue"><strong>3단계: 조치 처방 (Prescribe Action)</strong></span></p>
<ul>
<li><p>목표 대비 현재의 격차를 파악했다면, 개발자에게 무엇을 해야 하는지 알려주어야 한다. </p>
</li>
<li><p>스코어카드나 우선순위 알림을 통해 개발자가 집중해야 할 작업을 명확히 제시하라.</p>
</li>
</ul>
<p><span style="color: SlateBlue"><strong>4단계: 경험 최적화 (Optimize Experiences)</strong></span></p>
<ul>
<li><p><span style="color: indianred">*<em>마찰이 발생하는 지점이 명확해졌을 때 비로소 셀프 서비스를 도입하라. *</em></span></p>
</li>
<li><p>예를 들어, &quot;SLO 설정이 어렵다&quot;는 데이터가 나오면 그때 SLO 설정 자동화 템플릿을 제공하는 식이다.</p>
</li>
</ul>
<p><span style="color: SlateBlue"><strong>결론: 플라이휠(Flywheel) 효과</strong></span></p>
<ul>
<li><p>이 과정을 거치면 <code>측정 -&gt; 평가 -&gt; 조치 -&gt; 최적화</code>라는 피드백 루프가 형성된다. </p>
</li>
<li><p>이 루프가 반복될수록 IDP는 단순한 도구를 넘어 조직의 생산성을 지속적으로 가속화하는 플라이휠이 된다. 이것이 바로 성공적인 조직들이 IDP를 통해 가치를 창출하는 방식이다.</p>
</li>
</ul>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine5-정리-및-결론span"><span style='background-color: MediumAquamarine'>5. 정리 및 결론</span></h2>
<hr>

<p><span style="color: indianred">*<em>성공적인 내부 개발자 포털(IDP)은 플랫폼 팀의 관점이 아닌, 실제 사용자인 개발자의 핵심 니즈(정보 탐색, 우선순위 명확화, 템플릿)에서 출발해야 한다. *</em></span></p>
<p>Cortex는 단순한 정보 통합을 넘어, 스코어카드와 스캐폴딩을 통해 개발자가 데이터를 보고 즉시 행동(Action)할 수 있는 실행 가능한 환경을 제공하는 데 초점을 맞춘다. </p>
<p>조직은 무작정 기능을 도입하기보다 <span style="color: indianred"><strong><code>정보 수집 → 평가 → 조치 처방 → 경험 최적화</code></strong></span>의 단계적 접근을 통해 선순환 피드백 루프를 형성해야 한다. </p>
<p><strong>결국 IDP는 단순한 관리 도구가 아니라, 조직의 엔지니어링 문화를 성숙시키고 생산성을 지속적으로 가속화하는 강력한 플라이휠(Flywheel)이 되어야 한다.</strong></p>
<p><span style="color: indianred"></span>
<span style="color: SlateBlue"></span></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[90DaysOfDevOps (Day 87)]]></title>
            <link>https://velog.io/@taekyu_/90DaysOfDevOps-Day-87-sp3zkv76</link>
            <guid>https://velog.io/@taekyu_/90DaysOfDevOps-Day-87-sp3zkv76</guid>
            <pubDate>Sat, 07 Feb 2026 04:53:54 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>해당 스터디는 90DaysOfDevOps
<a href="https://github.com/MichaelCade/90DaysOfDevOps">https://github.com/MichaelCade/90DaysOfDevOps</a>
를 기반으로 진행한 내용입니다.</strong></p>
</blockquote>
<p>** Day 87 - Hands-on Performance Testing with k6 **</p>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine1-성능-테스트performance-testing-개요span"><span style='background-color: MediumAquamarine'>1. 성능 테스트(Performance Testing) 개요</span></h2>
<hr>

<h3 id="span-stylecolor-slateblue1-1-성능-테스트의-목적span"><span style="color: SlateBlue">1-1. 성능 테스트의 목적</span></h3>
<p><strong>성능 테스트의 궁극적인 목표는 테스트 대상 시스템의 실생활에서의 신뢰성을 검증하는 것이다.</strong></p>
<p><span style="color: indianred"><strong>단순히 기능이 작동하는지를 넘어, 실제 사용 환경과 유사한 부하 상황에서 시스템이 어떻게 반응하는지를 확인해야 한다.</strong> </span></p>
<p>이를 위해 주로 다음 세 가지 측면을 중점적으로 살펴본다.</p>
<ol>
<li><p><span style="color: SlateBlue"><strong>지연 시간 (응답 속도) :</strong></span> 시스템이 사용자 요청에 얼마나 빠르게 응답하는가? </p>
</li>
<li><p><span style="color: SlateBlue"><strong>오류 :</strong></span> 부하가 가해졌을 때 시스템이 에러를 반환하거나 내부적인 오류가 발생하지 않는가?</p>
</li>
<li><p><span style="color: SlateBlue"><strong>기능적 무결성 :</strong></span> 부하 상태에서도 통합 테스트나 End-to-End 사용자 흐름이 정상적으로 작동하는가?</p>
<ul>
<li><span style="color: indianred"><strong>중요:</strong></span> *<em>기능 테스트만으로는 부하 상황에서의 동작을 보장할 수 없다. *</em>
시스템은 사용자 10명일 때와 10,000명일 때 전혀 다르게 동작하기 때문이다.<br>

</li>
</ul>
</li>
</ol>
<h3 id="span-stylecolor-slateblue1-2-부하-테스트load-testing와-성능-테스트의-관계span"><span style="color: SlateBlue">1-2. 부하 테스트(Load Testing)와 성능 테스트의 관계</span></h3>
<p>성능 테스트와 부하 테스트는 매우 밀접한 관계가 있다. </p>
<p><strong>사실상 부하 테스트는 부하(Load)를 동반한 성능 테스트라고 정의할 수 있다.</strong></p>
<p><span style="color: indianred">*<em>부하 테스트는 크게 테스트 지속 시간(Duration)과 트래픽 부하량(Load)이라는 두 가지 변수에 따라 다음과 같이 세분화된다. *</em></span></p>
<img src="https://velog.velcdn.com/images/taekyu_/post/c381540e-52c9-47e4-b057-ba91d359e83f/image.png" width="70%" height="n%">

<ol>
<li><p><span style="color: SlateBlue"><strong>평균 부하 테스트 (Average Load Test):</strong></span> </p>
<ul>
<li><p>평소 운영 환경에서 발생하는 평균적인 트래픽 수준을 시뮬레이션</p>
</li>
<li><p>일상적인 성능 기준을 잡는 데 사용</p>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>스트레스 테스트 (Stress Test):</strong></span> </p>
<ul>
<li>시스템의 한계를 확인하기 위해 평소보다 높은 트래픽을 발생시킴.</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>스파이크 테스트 (Spike Test):</strong></span> </p>
<ul>
<li><p>특정 이벤트(예: 티켓 예매 오픈) 시점처럼, 트래픽이 매우 낮은 상태에서 갑자기 매우 높은 상태(Peak)로 급증하는 상황을 시뮬레이션</p>
</li>
<li><p>시스템의 급격한 확장에 대한 대응력을 테스트</p>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>스모크 테스트 (Smoke Test):</strong></span> </p>
<ul>
<li><p>최소한의 부하로 아주 짧은 시간 동안 수행</p>
</li>
<li><p>본격적인 테스트 전에 스크립트 오류 여부와 시스템의 기본 가용성을 빠르게 점검하는 것이 목적</p>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>소크 테스트 (Soak Test):</strong></span> </p>
<ul>
<li><p>장시간(2시간, 4시간, 혹은 그 이상) 동안 부하를 지속</p>
</li>
<li><p>메모리 누수(Memory Leak), 리소스 고갈, 디스크 공간 부족 등 장기 운영 시에만 드러나는 문제를 찾아내는 테스트</p>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>브레이크포인트 테스트 (Breakpoint Test):</strong></span> </p>
<ul>
<li><p>시스템이 과부하로 멈추거나 오류를 낼 때까지 부하를 지속적으로 증가시킴.</p>
</li>
<li><p>시스템의 물리적 한계점을 파악하여 용량 계획을 세우는 데 도움을 줌.</p>
<br>

</li>
</ul>
</li>
</ol>
<h3 id="span-stylecolor-slateblue1-3-부하를-사용하지-않는-성능-테스트span"><span style="color: SlateBlue">1-3. 부하를 사용하지 않는 성능 테스트</span></h3>
<p><strong>모든 성능 테스트가 동시 접속 부하를 필요로 하는 것은 아니다.</strong></p>
<ul>
<li><p><span style="color: indianred"><strong>프로파일링 (Profiling):</strong></span> 단일 사용자/스레드로 특정 함수나 로직의 실행 시간을 분석한다.</p>
</li>
<li><p><span style="color: indianred"><strong>브라우저 성능 테스트:</strong></span> 백엔드 부하보다는 프론트엔드 최적화(렌더링 속도, 에셋 로딩 시간 등)에 집중한다. 이 경우 백엔드에 부하를 주입할 필요가 없다.</p>
</li>
<li><p><span style="color: indianred"><strong>신세틱 모니터링 (Synthetic Monitoring):</strong></span> 운영 중인 시스템의 가용성을 확인하기 위해 주기적으로 가상의 트랜잭션을 발생시켜 모니터링한다.</p>
</li>
</ul>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine2-성능-테스트-도구-생태계span"><span style='background-color: MediumAquamarine'>2. 성능 테스트 도구 생태계</span></h2>
<hr>

<p><strong>성능 테스트 도구는 매우 다양하며, 사용 방식과 목적에 따라 크게 4가지 카테고리로 분류할 수 있다.</strong></p>
<ol>
<li><p><span style="color: SlateBlue"><strong>벤치마킹 도구</strong></span></p>
<ul>
<li><p><span style="color: indianred"><strong>대표 도구:</strong></span> <code>ab</code> (Apache Bench), <code>wrk</code></p>
</li>
<li><p><span style="color: indianred"><strong>특징:</strong></span> 단일 엔드포인트나 URL 리스트를 대상으로 단순한 부하를 발생시킨다.</p>
</li>
<li><p><span style="color: indianred"><strong>장단점:</strong></span> 사용이 매우 간편하고 결과가 터미널에 바로 출력되지만, 복잡한 시나리오 구성은 어렵다.</p>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>프로토콜 특화 도구</strong></span></p>
<ul>
<li><span style="color: indianred"><strong>특징:</strong></span> <code>gRPC</code>, <code>MQTT</code>, <code>Kafka</code> 등 특정 프로토콜 테스트에 최적화된 도구들이 존재한다.</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>GUI 기반 도구</strong></span></p>
<ul>
<li><p><span style="color: indianred"><strong>대표 도구:</strong></span> JMeter</p>
</li>
<li><p><span style="color: indianred"><strong>특징:</strong></span> 가장 오래되고 널리 쓰이는 도구 중 하나다. GUI를 통해 테스트 단계를 클릭으로 구성할 수 있다.</p>
</li>
<li><p><span style="color: indianred"><strong>장단점:</strong></span> 코딩 없이 접근 가능하고 커뮤니티가 크지만, 스크립트 관리가 어렵고 리소스를 많이 차지할 수 있다.</p>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>코드 기반(Scripting) 도구</strong></span></p>
<ul>
<li><p><span style="color: indianred"><strong>대표 도구:</strong></span> k6 (JavaScript/Go), Locust (Python), Gatling (Scala/Java)</p>
</li>
<li><p><span style="color: indianred"><strong>특징:</strong></span> 개발자 친화적이며, 코드로 테스트 시나리오를 작성하므로 버전 관리(Git)가 용이하고 유연성이 매우 높다.</p>
</li>
<li><p><span style="color: indianred"><strong>참고:</strong></span> Artillery와 같이 YAML 설정을 사용하는 도구도 있지만, 스크립팅 언어만큼의 완벽한 유연성을 제공하지는 못할 수 있다.</p>
</li>
</ul>
</li>
</ol>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine3-k6span"><span style='background-color: MediumAquamarine'>3. K6</span></h2>
<hr>

<p><strong>k6는 개발자 중심의 오픈 소스 부하 테스트 도구다.</strong></p>
<p>k6는 단순히 부하를 일으키는 도구를 넘어, 개발자 경험(DX, Developer Experience)을 최우선으로 설계된 오픈 소스 성능 테스트 프레임워크이며, Grafana Labs에 인수된 이후, 관측성(Observability) 생태계와 결합하며 더욱 강력해졌다.</p>
<p><img src="https://velog.velcdn.com/images/taekyu_/post/e142e33f-1466-41d3-8287-1d22fd46d2f6/image.png" alt=""></p>
<p><span style="color: indianred"><strong>k6의 가장 큰 기술적 특징은 &quot;작성은 쉬운 JavaScript로, 실행은 강력한 Go로&quot; 수행한다는 점이다.</strong></span></p>
<ul>
<li><p><span style="color: SlateBlue"><strong>스크립팅의 용이성:</strong></span> </p>
<ul>
<li><p>개발자에게 익숙한 ES6 자바스크립트 문법을 사용하여 테스트 시나리오를 작성한다. </p>
</li>
<li><p>덕분에 별도의 도구 사용법을 익힐 필요 없이, 복잡한 비즈니스 로직을 코드로 유연하게 구현할 수 있다.</p>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>고성능 실행 엔진:</strong></span> </p>
<ul>
<li><p>*<em>작성된 스크립트는 내부적으로 내장된 Go 기반의 JS 인터프리터(goja)를 통해 실행된다. *</em></p>
</li>
<li><p>이는 Node.js나 브라우저 엔진 위에서 구동되는 것이 아니기 때문에 오버헤드가 극도로 낮다.</p>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>스레드 대신 가상 사용자(VU):</strong></span></p>
<ul>
<li><p>기존의 JMeter가 OS Thread를 사용하여 메모리 소비가 컸던 반면, k6는 Go의 Goroutine을 활용하여 가상 사용자(Virtual Users)를 구현한다. </p>
</li>
<li><p>덕분에 단일 인스턴스에서 수만 명의 동시 접속자를 시뮬레이션하더라도 메모리 사용량이 현저히 적다.</p>
</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/taekyu_/post/ef4e6712-1d64-4de7-aede-3eddd3eb54e7/image.png" alt=""></p>
<p><strong>첨부된 이미지가 보여주듯, k6는 소프트웨어 개발 수명 주기(SDLC) 전반에 걸쳐 성능을 관리할 수 있도록 설계되었다.</strong></p>
<ul>
<li><p><span style="color: SlateBlue"><strong>Pre-production (Proactive):</strong></span> 배포 전 단계에서 가상 사용자 트래픽(Virtual User Traffic)을 통해 잠재적인 병목 구간을 사전에 발견하고 해결한다.</p>
</li>
<li><p><span style="color: SlateBlue"><strong>Production (Reactive):</strong></span> 실제 운영 환경의 모니터링 데이터(Real User Traffic)와 테스트 결과를 비교 분석한다.</p>
</li>
<li><p><span style="color: SlateBlue"><strong>Grafana와의 결합:</strong></span> </p>
<ul>
<li>*<em>k6는 테스트 결과를 단순히 콘솔에 찍는 것에 그치지 않고, Grafana 플랫폼으로 전송하여 메트릭(Metrics), 로그(Logs), 트레이스(Traces)와 함께 통합 분석할 수 있게 해준다. *</em></li>
</ul>
</li>
</ul>
<br>


<p><span style="color: indianred"><strong>또한, k6의 가장 강력한 장점은 하나의 테스트 스크립트를 수정 없이 다양한 환경에서 실행할 수 있다는 점이다.</strong></span></p>
<ul>
<li><p><span style="color: SlateBlue"><strong>Local (로컬):</strong></span> 개발자 개인 PC나 단일 서버에서 실행한다. k6 run 명령어를 사용한다.</p>
</li>
<li><p><span style="color: SlateBlue"><strong>Distributed (분산):</strong></span> Kubernetes 클러스터 등을 활용하여 여러 파드(Pod)에 부하를 분산시켜 대규모 테스트를 수행한다.</p>
</li>
<li><p><span style="color: SlateBlue"><strong>Cloud (클라우드):</strong></span> k6의 상용 클라우드 서비스(Grafana Cloud k6)를 이용하여 인프라 관리 없이 대규모 테스트를 수행하고 결과를 저장/분석한다.</p>
</li>
</ul>
<p><strong>이는 로컬 개발부터 대규모 프로덕션 테스트까지 매끄러운 확장을 가능하게 한다.</strong>
<br></p>
<p><span style="color: indianred"><strong>추가적으로, k6를 사용할 때 반드시 이해해야 할 점은 k6는 브라우저가 아니라는 것이다.</strong></span></p>
<p>k6는 프로토콜 레벨(HTTP 등)에서 요청을 보내고 응답을 측정하는 도구다. </p>
<p><strong>웹 페이지의 HTML을 가져오지만, 브라우저처럼 화면을 렌더링하거나 페이지 내의 JavaScript를 실행하지는 않는다.</strong></p>
<p><span style="color: indianred">*<em>따라서 정확한 페이지 로딩 속도(렌더링 포함)를 측정하고 싶다면, 최근 k6에 실험적으로 추가된 k6 Browser 모듈(Chrome DevTools Protocol 기반)을 활용하거나 다른 도구를 병행해야 한다. *</em></span></p>
<blockquote>
<p><strong>하지만 백엔드 API의 성능을 극한으로 테스트하는 목적이라면 k6의 기본 모드가 가장 효율적이고 강력한 선택지가 된다.</strong></p>
</blockquote>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine4-k6-실전-데모span"><span style='background-color: MediumAquamarine'>4. K6 실전 데모</span></h2>
<hr>


<p>해당 프레젠테이션의 데모는 피자 주문 및 추천 서비스인 &#39;Quick Pizza&#39; 애플리케이션을 대상으로 진행된다. </p>
<p>Docker Compose를 사용하여 애플리케이션, Grafana, Prometheus를 로컬 환경에 구성했다.</p>
<h3 id="span-stylecolor-slateblue4-1-기본-테스트-스크립트-구조-span"><span style="color: SlateBlue">4-1. 기본 테스트 스크립트 구조 </span></h3>
<p><strong>k6 스크립트는 자바스크립트(ES6) 기반이며, 크게 Imports, Options, Default Function 세 부분으로 구성된다.</strong></p>
<ul>
<li><p><span style="color: indianred"><strong>Imports:</strong></span> <code>k6/http</code>와 같은 내장 모듈이나 외부 라이브러리를 불러온다.</p>
</li>
<li><p><span style="color: indianred"><strong>Options:</strong></span> 가상 사용자 수(VUs), 지속 시간(Duration) 등 테스트 실행 설정을 정의한다.</p>
</li>
<li><p><span style="color: indianred"><strong>Default Function:</strong></span> 가상 사용자가 반복해서 수행할 실제 비즈니스 로직을 작성한다.</p>
</li>
</ul>
<pre><code class="language-javascript">import http from &#39;k6/http&#39;;
import { sleep, check } from &#39;k6&#39;;

// 1. 설정 (Options): 부하 수준 정의
export const options = {
  vus: 5,           // 가상 사용자 5명
  duration: &#39;10s&#39;,  // 10초 동안 실행
};

// 2. 메인 로직 (Default Function): VU가 반복 실행할 시나리오
export default function () {
  const res = http.post(&#39;http://localhost:3333/pizza&#39;); // HTTP 요청 (POST)

  // 응답 확인 및 로깅 (선택 사항)
  console.log(`Response status: ${res.status}`);

  sleep(1); // 1초 대기 (Think Time)
}</code></pre>
<br>

<h3 id="span-stylecolor-slateblue4-2-부하-모델링-심화-span"><span style="color: SlateBlue">4-2. 부하 모델링 심화 </span></h3>
<p><strong>k6는 매우 정교한 부하 제어 기능을 제공한다. 상황에 따라 다양한 옵션을 적용할 수 있다.</strong></p>
<ul>
<li><p><span style="color: indianred"><strong>A. Iterations 기반 실행</strong></span></p>
<ul>
<li><p>기본적으로 시간(Duration) 기반으로 실행하지만, iterations 옵션을 사용하여 총 실행 횟수를 지정할 수도 있다. CLI에서 플래그로 덮어쓰는 것도 가능하다.</p>
<pre><code class="language-bash"># 5명의 VU가 협력하여 총 20번의 시나리오를 수행하고 종료
k6 run --iterations 20 --vus 5 script.js</code></pre>
<br>


</li>
</ul>
</li>
</ul>
<ul>
<li><p><span style="color: indianred"><strong>B. 스테이지(Stages)를 이용한 램핑(Ramping)</strong></span></p>
<ul>
<li><p>실제 트래픽처럼 부하를 서서히 올리고(Ramp-up) 내리는(Ramp-down) 패턴을 만든다. </p>
</li>
<li><p>options 객체 내 stages 배열을 사용한다.</p>
<pre><code class="language-javascript">export const options = {
 stages: [
   { duration: &#39;5s&#39;, target: 5 },  // 0명에서 5명으로 5초 동안 증가 (Ramp-up)
   { duration: &#39;10s&#39;, target: 5 }, // 5명 유지 (Steady State - 안정성 확인)
   { duration: &#39;5s&#39;, target: 0 },  // 5명에서 0명으로 감소 (Ramp-down)
 ],
};</code></pre>
<br>


</li>
</ul>
</li>
</ul>
<ul>
<li><p><span style="color: indianred"><strong>C. 초당 요청 수(RPS) 제어: Constant Arrival Rate</strong></span></p>
<ul>
<li><p>일반적인 방식으로는 함수 실행 시간(응답 속도)에 따라 반복 횟수가 달라지므로 정확한 RPS(Requests Per Second)를 맞추기 어렵다. </p>
</li>
<li><p><strong>이를 위해 <code>scenarios</code>의 <code>constant-arrival-rate 실행기</code>를 사용한다.</strong></p>
<pre><code class="language-javascript">export const options = {
scenarios: {
  constant_request_rate: {
    executor: &#39;constant-arrival-rate&#39;,
    rate: 30,             // 초당 30회 반복 목표
    timeUnit: &#39;1s&#39;,       // 시간 단위
    duration: &#39;30s&#39;,      // 30초 동안 실행
    preAllocatedVUs: 50,  // 미리 할당할 VU 수
    maxVUs: 100,          // 최대 허용 VU 수
  },
},
};</code></pre>
</li>
<li><p><span style="color: indianred"><strong>주의:</strong></span> <strong>k6는 엄밀히 말해 초당 반복(Iteration) 수를 제어한다.</strong> 
시나리오 내에 요청이 1개라면 반복 수 = RPS가 되지만, 요청이 여러 개라면 계산이 필요하다.</p>
<br>

</li>
</ul>
</li>
</ul>
<h3 id="span-stylecolor-slateblue4-3-메트릭의-이해-span"><span style="color: SlateBlue">4-3. 메트릭의 이해 </span></h3>
<p><strong>k6는 테스트 중 발생하는 데이터를 4가지 유형의 메트릭으로 수집한다.</strong></p>
<ol>
<li><p><span style="color: indianred"><strong>Counter:</strong></span> 누적 합계 (예: <code>http_reqs</code>)</p>
</li>
<li><p><span style="color: indianred"><strong>Gauge:</strong></span> 특정 시점의 값 (예: <code>vus</code>)</p>
</li>
<li><p><span style="color: indianred"><strong>Rate:</strong></span> 성공/실패 비율 (예: <code>checks</code>, <code>http_req_failed</code>)</p>
</li>
<li><p><span style="color: indianred"><strong>Trend:</strong></span> 통계적 분포 (예: <code>http_req_duration</code> - p95, p99 등)</p>
</li>
</ol>
<p><span style="color: indianred"><strong>커스텀 메트릭 (Custom Metrics) 이란?</strong></span></p>
<p><strong>추가적으로, 기본 메트릭 외에 비즈니스 로직에 맞는 데이터를 수집할 수 있다.</strong></p>
<pre><code class="language-javascript">import http from &#39;k6/http&#39;;
import { Trend, Counter } from &#39;k6/metrics&#39;;

// 커스텀 메트릭 정의
const ingredientsTrend = new Trend(&#39;quickpizza_ingredients&#39;);
const pizzaCounter = new Counter(&#39;quickpizza_number_of_pizzas&#39;);

export default function () {
  const res = http.get(&#39;http://localhost:3333/pizza&#39;);

  // 응답받은 JSON 데이터 파싱
  const pizza = res.json();

  // 메트릭에 데이터 추가
  ingredientsTrend.add(pizza.ingredients.length); // 재료 개수 통계
  pizzaCounter.add(1);                            // 피자 개수 카운트
}</code></pre>
<br>

<h3 id="span-stylecolor-slateblue4-4-결과-출력과-시각화-span"><span style="color: SlateBlue">4-4. 결과 출력과 시각화 </span></h3>
<ol>
<li><p><span style="color: indianred"><strong>터미널 요약 및 파일 내보내기</strong></span></p>
<ul>
<li><p>테스트 종료 후 터미널에 출력되는 요약 리포트는 집계된 데이터다.</p>
</li>
<li><p>상세 분석을 위해 <code>handleSummary()</code> 함수를 이용해 JSON 파일로 내보낼 수 있다.</p>
</li>
</ul>
</li>
<li><p><span style="color: indianred"><strong>실시간 데이터 스트리밍</strong></span></p>
<ul>
<li><p>가장 강력한 기능은 <code>--out</code> 플래그를 사용하여 Raw Data를 시계열 데이터베이스로 실시간 전송하는 것이다.</p>
<pre><code class="language-bash"># Prometheus로 데이터 실시간 전송 (Remote Write 기능 사용)
 k6 run --out experimental-prometheus-rw script.js</code></pre>
</li>
<li><p>*<em>위 명령어를 실행하면 k6가 데이터를 Prometheus로 전송하고, 이를 Grafana 대시보드에서 실시간 그래프로 확인할 수 있다. *</em></p>
</li>
<li><p>스파이크 발생 지점이나 지연 시간 변화 추이를 시각적으로 파악하는 데 필수적이다.</p>
<br>

</li>
</ul>
</li>
</ol>
<h3 id="span-stylecolor-slateblue4-5-검증-checks와-thresholds-span"><span style="color: SlateBlue">4-5. 검증: Checks와 Thresholds </span></h3>
<p><strong>k6는 테스트 성공 여부를 판단하고 검증하기 위해 두 가지 방법을 제공한다.</strong></p>
<p><span style="color: indianred">*<em>1. Checks *</em></span>
단순 확인용(Boolean) 검증으로, 실패해도 테스트가 중단되거나 실패로 기록되지 않는다.</p>
<pre><code class="language-javascript">import { check } from &#39;k6&#39;;

export default function (res) {
  // 응답 코드가 200인지 확인 (실패해도 테스트는 계속 진행됨)
  check(res, { &#39;is status 200&#39;: (r) =&gt; r.status === 200 });
}</code></pre>
<p><span style="color: indianred">*<em>2. Thresholds (임계값) *</em></span>
테스트의 성공/실패 기준을 정의하며, 이를 위반하면 k6는 실패(Non-zero) 종료 코드를 반환하므로 CI/CD 파이프라인에서 매우 중요하다.</p>
<pre><code class="language-javascript">export const options = {
  thresholds: {
    // 에러율(http_req_failed)이 1% 미만이어야 함
    &#39;http_req_failed&#39;: [&#39;rate&lt;0.01&#39;], 

    // 응답 시간(http_req_duration)의 95%가 500ms 이내여야 함
    &#39;http_req_duration&#39;: [&#39;p95&lt;500&#39;],

    // 커스텀 메트릭 평균이 2 미만이어야 함
    &#39;quickpizza_ingredients&#39;: [&#39;avg&lt;2&#39;], 
  },
};</code></pre>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine5-결론span"><span style='background-color: MediumAquamarine'>5. 결론</span></h2>
<hr>

<p>성능 테스트는 시스템의 신뢰성을 보장하기 위한 선택이 아닌 필수 과정이다. </p>
<p><strong>k6는 강력한 스크립팅 기능과 확장성, 그리고 개발자 친화적인 경험(DX)을 제공하여 이를 효율적으로 지원한다.</strong></p>
<p><span style="color: indianred"></span>
<span style="color: SlateBlue"></span></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[90DaysOfDevOps (Day 86)]]></title>
            <link>https://velog.io/@taekyu_/90DaysOfDevOps-Day-86-78f3qstq</link>
            <guid>https://velog.io/@taekyu_/90DaysOfDevOps-Day-86-78f3qstq</guid>
            <pubDate>Sat, 07 Feb 2026 03:15:31 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>해당 스터디는 90DaysOfDevOps
<a href="https://github.com/MichaelCade/90DaysOfDevOps">https://github.com/MichaelCade/90DaysOfDevOps</a>
를 기반으로 진행한 내용입니다.</strong></p>
</blockquote>
<p>** Day 86 - Tools To Make Your Terminal DevOps and Kubernetes Friendly **</p>
<p><strong>프레젠테이션에서는 엔지니어에게 터미널은 하루의 대부분을 보내는 집과 같은 곳이기때문에,  이 공간을 더 효율적이고 예쁘게 만드는 것은 생산성과 직결된다고 한다.</strong></p>
<p><span style="color: indianred"><strong>따라서, Zsh, Terraform, Git, 그리고 Kubernetes 환경에서 사용할 수 있는 유용한 오픈 소스 및 상용 도구들을 제시한다.</strong></span></p>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine1-zsh-z-shell-관련-도구span"><span style='background-color: MediumAquamarine'>1. Zsh (Z Shell) 관련 도구</span></h2>
<hr>

<p><strong>Zsh는 유닉스 기반의 쉘로, Bash와 유사하지만 훨씬 강력한 기능과 생산성 향상 도구를 제공하여 최근 개발자들 사이에서 인기가 높다.</strong></p>
<p><img src="https://velog.velcdn.com/images/taekyu_/post/2a454b39-abba-4d3d-abab-7c91d1d0e0dc/image.png" alt=""></p>
<ul>
<li><p><span style="color: SlateBlue"><strong>Oh My Zsh</strong></span></p>
<ul>
<li><p><strong>Zsh 구성을 관리하기 위한 커뮤니티 기반 오픈 소스 프레임워크</strong></p>
</li>
<li><p><span style="color: indianred"><strong>특징:</strong></span> 수많은 테마와 플러그인을 제공하여 사용자 경험을 극대화</p>
</li>
<li><p><span style="color: indianred"><strong>설치:</strong></span> Zsh, curl, git이 사전에 설치되어 있어야 하며 <code>curl</code>, <code>wget</code>, <code>fetch</code> 등을 통해 설치 가능</p>
</li>
<li><p><span style="color: indianred"><strong>사용법:</strong></span> 홈 디렉토리의 <code>.zshrc</code> 파일을 수정하여 플러그인(예: git)을 추가하거나 테마를 변경할 수 있다. 다양한 테마의 스크린샷과 색상 정보를 확인하고 선택하는 것을 추천한다.</p>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>zsh-syntax-highlighting</strong></span></p>
<ul>
<li><p><strong>명령어를 입력하는 동안 실시간으로 구문을 강조해 주는 플러그인</strong></p>
</li>
<li><p><span style="color: indianred"><strong>기능:</strong></span> 명령어, 옵션, 인수, 변수 등을 시각적으로 구분해 준다.</p>
</li>
<li><p><span style="color: indianred"><strong>장점:</strong></span> 오타나 문법 오류를 입력 단계에서 즉시 파악할 수 있어 명령어 구조를 이해하는 데 도움을 준다.</p>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>zsh-autosuggestions</strong></span></p>
<ul>
<li><p><strong>사용자의 명령어 히스토리를 기반으로 지능적인 자동 완성을 제안하는 플러그인</strong></p>
</li>
<li><p><span style="color: indianred"><strong>기능:</strong></span> 이전에 사용했던 명령어를 기억하여, 앞부분만 입력해도 회색 텍스트로 전체 명령어를 제안한다.</p>
</li>
<li><p><span style="color: indianred"><strong>장점:</strong></span>  긴 명령어를 반복적으로 입력해야 할 때 Tab 키만 누르면 완성되므로 작업 속도가 빨라진다.</p>
</li>
</ul>
</li>
</ul>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine2-terraform-관련-도구span"><span style='background-color: MediumAquamarine'>2. Terraform 관련 도구</span></h2>
<hr>

<p><strong>Terraform은 HashiCorp의 IaC(Infrastructure as Code) 도구이며, Terragrunt는 Terraform 모듈을 DRY(Don&#39;t Repeat Yourself)하게 관리해 주는 래퍼 도구다.</strong></p>
<ul>
<li><p><span style="color: SlateBlue"><strong>tfswitch &amp; tgswitch</strong></span></p>
<ul>
<li><p><strong>다양한 프로젝트나 환경에 따라 서로 다른 버전의 Terraform이나 Terragrunt를 사용해야 할 때 유용</strong></p>
</li>
<li><p><span style="color: indianred"><strong>기능:</strong></span> 시스템에 설치된 여러 버전 중 원하는 버전을 손쉽게 전환할 수 있게 해준다.</p>
<br>


</li>
</ul>
</li>
</ul>
<ul>
<li><p><span style="color: SlateBlue"><strong>Infracost</strong></span></p>
<ul>
<li><p><strong>IaC 코드의 비용을 추정하고 추적하는 도구</strong></p>
</li>
<li><img src="https://velog.velcdn.com/images/taekyu_/post/93cb17f7-360c-4d15-81b0-d523454d0e84/image.png" width="60%" height="n%">
</li>
<li><p><span style="color: indianred"><strong>기능:</strong></span> 구성 파일을 분석하여 실시간 클라우드 비용 견적을 제공한다.</p>
</li>
<li><p><span style="color: indianred"><strong>활용:</strong></span> VS Code 확장 프로그램으로도 제공되며, 코드 작성 단계에서 예산을 고려한 의사결정을 돕는다.</p>
<br>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>Trivy (구 tfsec 통합)</strong></span></p>
<ul>
<li><strong>보안 스캔 도구로, 기존의 tfsec이 Trivy로 통합</strong></li>
</ul>
</li>
</ul>
<ul>
<li><img src="https://velog.velcdn.com/images/taekyu_/post/6b6903c4-91cd-4d98-816c-f48d95ed4302/image.png" width="50%" height="n%">
</li>
<li><p><span style="color: indianred"><strong>변화:</strong></span> tfsec 제작사는 도구 통합으로 인해 Trivy로의 마이그레이션을 권장한다.</p>
</li>
<li><p><span style="color: indianred"><strong>기능:</strong></span> OS 패키지, 소프트웨어 의존성, CVE(알려진 취약점), IaC(기존 tfsec 기능), 민감 정보(Secret), 라이선스 등을 포괄적으로 스캔한다.</p>
</li>
<li><p><span style="color: indianred"><strong>장점:</strong></span> 코드의 잠재적 취약점과 모범 사례 위반을 식별하고 개선 방안을 제안한다.</p>
<br>

</li>
</ul>
<ul>
<li><p><span style="color: SlateBlue"><strong>terraform-docs</strong></span></p>
<ul>
<li><p><strong>Terraform 코드를 기반으로 문서 생성을 자동화해 주는 CLI 유틸리티</strong></p>
</li>
<li><p><span style="color: indianred"><strong>기능:</strong></span> 구성 파일에서 정보(<code>Requirements, Providers, Inputs, Outputs</code>)를 추출하여 마크다운 테이블 등 다양한 형식의 깔끔한 문서를 만들어준다.</p>
</li>
</ul>
</li>
</ul>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine3-git-관련-도구span"><span style='background-color: MediumAquamarine'>3. git 관련 도구</span></h2>
<hr>

<p><strong>버전 관리를 위한 Git 사용 시 생산성을 높여주는 도구들이다.</strong></p>
<ul>
<li><p><span style="color: SlateBlue"><strong>Git Aliases (별칭)</strong></span></p>
<ul>
<li><p><strong>자주 사용하는 긴 명령어를 짧은 단축어로 정의하여 사용</strong></p>
</li>
<li><p><span style="color: indianred"><strong>예시:</strong></span> git status 대신 gs를 입력하도록 설정하여 타이핑 수고를 덜고 속도를 높인다.</p>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>GitLens</strong></span></p>
<ul>
<li><p><strong>VS Code용 확장 프로그램으로 코드의 히스토리를 추적하는 데 최적화</strong></p>
</li>
<li><p><span style="color: indianred"><strong>기능:</strong></span> 코드 에디터 내에서 각 라인을 누가, 언제 수정했는지(Blame 기능) 바로 보여준다.</p>
</li>
<li><p><span style="color: indianred"><strong>상세:</strong></span> 커밋 메시지와 작성자 정보를 시각적으로 표시하며, 마우스 오버 시 해당 히스토리 링크로 연결되어 변경 이력을 쉽게 파악할 수 있다.</p>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>Git Graph</strong></span></p>
<ul>
<li><p><strong>VS Code용 확장 프로그램으로, Git 히스토리를 그래프 형태로 시각화</strong></p>
</li>
<li><p><span style="color: indianred"><strong>기능:</strong></span> 복잡한 브랜치 구조와 커밋 흐름을 시각적으로 표현해 준다.</p>
</li>
<li><p><span style="color: indianred"><strong>장점:</strong></span> CLI만으로는 히스토리 파악이 어려운 초심자에게 현재 브랜치 위치와 흐름을 이해하는 데 큰 도움을 준다.</p>
</li>
</ul>
</li>
</ul>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine4-kubernetes-관련-도구span"><span style='background-color: MediumAquamarine'>4. Kubernetes 관련 도구</span></h2>
<hr>

<p><strong>복잡한 쿠버네티스 시스템을 효율적으로 관리하기 위해 개발된 다양한 도구들이다.</strong></p>
<ul>
<li><p><span style="color: SlateBlue"><strong>Kubernetes Aliases</strong></span></p>
<ul>
<li><p><strong>kubectl 명령어를 매번 입력하는 번거로움을 줄이기 위해 사용</strong></p>
</li>
<li><pre><code class="language-bash">alias k=&#39;kubectl&#39;
 alias kpod=&#39;kubectl get pods -A&#39;
 alias knode=&#39;kubectl get nodes&#39;
 alias kdesp=&#39;kubectl describe pod&#39;
 alias kdp=&#39;kubectl delete pod&#39;
 alias=&#39;kubectl get deployments&#39;</code></pre>
</li>
<li><p><span style="color: indianred"><strong>활용:</strong></span> kubectl을 k와 같은 한 글자 별칭으로 설정하여 명령어 입력 속도를 비약적으로 높인다.</p>
<br>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>kube-ps1</strong></span></p>
<ul>
<li><p><strong>현재 사용 중인 클러스터 컨텍스트와 네임스페이스를 프롬프트에 시각적으로 표시</strong></p>
</li>
<li><p><span style="color: indianred"><strong>필요성:</strong></span> 여러 클러스터를 관리할 때, 실수로 엉뚱한 클러스터(예: 프로덕션)에 명령을 내리는 치명적인 실수를 방지해 준다.</p>
</li>
<li><p><span style="color: indianred"><strong>기능:</strong></span> 터미널 프롬프트에 현재 컨텍스트와   - 네임스페이스 정보를 색상과 함께 보여주어 직관적인 확인이 가능하다.</p>
<br>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>kubecolor</strong></span></p>
<ul>
<li><p><strong>kubectl 명령어의 출력 결과에 색상을 입혀 가독성을 높인다.</strong></p>
</li>
<li><p><span style="color: indianred"><strong>기능:</strong></span> 밋밋한 텍스트 출력 대신 중요 정보를 색상으로 구분하여, 원하는 정보를 빠르게 식별할 수 있게 돕는다.</p>
<br>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>kubectx &amp; kubens</strong></span></p>
<ul>
<li><p><strong>컨텍스트와 네임스페이스 전환을 획기적으로 간편하게 만들어주는 도구</strong></p>
</li>
<li><p><span style="color: indianred"><strong>kubectx:</strong></span> 복잡한 명령어 없이 kubectx &lt;컨텍스트명&gt; 입력만으로 클러스터 간 전환이 가능하다.</p>
</li>
<li><p><span style="color: indianred"><strong>kubens:</strong></span> kubens &lt;네임스페이스명&gt; 입력만으로 네임스페이스를 즉시 변경할 수 있다.</p>
<br>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>K9s</strong></span></p>
<ul>
<li><p>터미널 기반의 UI(TUI)를 제공하는 쿠버네티스 관리 대시보드다.</p>
</li>
<li><p><span style="color: indianred"><strong>기능:</strong></span> CLI 환경에서도 시각적인 인터페이스를 통해 클러스터 상태를 모니터링하고 리소스를 관리할 수 있다.</p>
<br>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>Lens</strong></span></p>
<ul>
<li><p><strong>쿠버네티스 관리를 위한 데스크톱 GUI 애플리케이션</strong></p>
</li>
<li><p><span style="color: indianred"><strong>기능:</strong></span> 노드, 파드 등 모든 리소스를 그래픽 인터페이스로 보여주며, 마우스 클릭만으로 상세 정보를 확인하고 관리할 수 있는 강력한 도구다.</p>
<br>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>Popeye</strong></span></p>
<ul>
<li><p><strong>쿠버네티스 클러스터 분석 및 살균(Sanitizer) 도구</strong></p>
</li>
<li><p><span style="color: indianred"><strong>기능:</strong></span> 클러스터 전체를 스캔하여 구성 오류, 리소스 비효율성, 보안 위협, 모범 사례 위반 사항 등을 찾아내고 보고한다.</p>
<br>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>kube-capacity</strong></span></p>
<ul>
<li><p><strong>클러스터 리소스 사용량과 용량을 분석하는 도구</strong></p>
</li>
<li><p><span style="color: indianred"><strong>기능:</strong></span> CPU와 메모리의 요청(Requests) 및 제한(Limits) 설정값과 실제 사용량을 비교하여 보여주며, 노드 및 파드 단위의 용량 정보를 제공한다.</p>
<br>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>kube-shell</strong></span></p>
<ul>
<li><p><strong>쿠버네티스 CLI를 위한 통합 쉘</strong></p>
</li>
<li><p><span style="color: indianred"><strong>기능:</strong></span> 명령어 자동 완성 및 제안 기능을 제공하여, 사용 가능한 명령어를 쉽게 찾고 실행할 수 있도록 돕는다.</p>
</li>
</ul>
</li>
</ul>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine5-결론span"><span style='background-color: MediumAquamarine'>5. 결론</span></h2>
<hr>

<p>*<em>이미 시중에는 데브옵스 여정을 돕고 생산성을 높여줄 수 있는 수많은 도구가 존재한다. *</em></p>
<p>이러한 도구들을 적극적으로 활용하여 불필요한 반복 작업을 줄이고, 더 중요하고 가치 있는 일에 집중하며, 결과적으로 엔지니어로서의 삶을 더 편안하게 만드는 것이 중요하다.</p>
<p><span style="color: indianred"></span>
<span style="color: SlateBlue"></span></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[90DaysOfDevOps (Day 85)]]></title>
            <link>https://velog.io/@taekyu_/90DaysOfDevOps-Day-85-4srzfbxp</link>
            <guid>https://velog.io/@taekyu_/90DaysOfDevOps-Day-85-4srzfbxp</guid>
            <pubDate>Sun, 01 Feb 2026 05:59:36 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>해당 스터디는 90DaysOfDevOps
<a href="https://github.com/MichaelCade/90DaysOfDevOps">https://github.com/MichaelCade/90DaysOfDevOps</a>
를 기반으로 진행한 내용입니다.</strong></p>
</blockquote>
<p>** Day 85 - Reuse, Don&#39;t Repeat - Creating an Infrastructure as Code Module Library **</p>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine1-왜-인프라-코드를-모듈화해야-하는가-span"><span style='background-color: MediumAquamarine'>1. 왜 인프라 코드를 모듈화해야 하는가 </span></h2>
<hr>

<p>IaC를 작성하다 보면 VM, 스토리지 계정 등 동일한 리소스를 반복적으로 정의하게 된다.</p>
<p><strong>매번 코드를 복사해서 붙여넣는 방식은 다음과 같은 문제를 야기한다.</strong></p>
<ul>
<li><p><span style="color: indianred"><strong>시간 낭비:</strong></span> 동일한 구성을 매번 새로 작성해야 한다.</p>
</li>
<li><p><span style="color: indianred"><strong>일관성 결여:</strong></span> 시간이 지남에 따라 초기에 작성한 코드와 나중에 작성한 코드가 달라져 관리 포인트가 늘어난다.</p>
</li>
</ul>
<hr>
<h3 id="span-stylecolor-slateblue1-1-모듈화의-4가지-핵심-이점span"><span style="color: SlateBlue"><strong>1-1. 모듈화의 4가지 핵심 이점</strong></span></h3>
<ul>
<li><p><span style="color: indianred"><strong>재사용성:</strong></span> 한 번 잘 만들어진 모듈을 여러 프로젝트에서 Parameter만 바꿔가며 반복 사용할 수 있다.</p>
</li>
<li><p><span style="color: indianred"><strong>복잡성 추상화:</strong></span> </p>
<ul>
<li><p>클라우드 리소스의 복잡한 설정(<strong><code>네트워크 피어링, 암호화 세팅 등</code></strong>)을 모듈 내부로 숨기고, 사용자에게는 이름과 위치 같은 단순한 인터페이스만 제공할 수 있다.</p>
</li>
<li><p>이를 통해 클라우드 전문 지식이 없는 팀원도 손쉽게 인프라를 배포할 수 있다.</p>
</li>
</ul>
</li>
<li><p><span style="color: indianred"><strong>표준 준수:</strong></span> 회사의 보안 정책(예: HTTPS 필수, 퍼블릭 액세스 차단)을 모듈 내부에 하드코딩함으로써, 사용자가 모듈을 쓰기만 해도 자동으로 규정을 준수하도록 강제할 수 있다.</p>
</li>
<li><p><span style="color: indianred"><strong>지식 공유:</strong></span> 인프라 아키텍트의 노하우와 모범 사례를 모듈에 담아 조직 전체에 배포할 수 있다.</p>
</li>
</ul>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine2-도구별-모듈-구현-방법span"><span style='background-color: MediumAquamarine'>2. 도구별 모듈 구현 방법</span></h2>
<hr>

<p><strong>대부분의 IaC 도구는 이미 모듈화 기능을 제공한다. 세션에서는 Bicep, Terraform, Pulumi를 예시로 들었다.</strong></p>
<h3 id="span-stylecolor-slateblue2-1-azure-bicepspan"><span style="color: SlateBlue">2-1. Azure Bicep</span></h3>
<ul>
<li><p><span style="color: indianred"><strong>구현:</strong></span> 일반적인 <code>.bicep</code> 파일이 곧 모듈이 된다.</p>
</li>
<li><p><span style="color: indianred"><strong>인터페이스 설계:</strong></span> <code>param</code>으로 입력을 받고 output으로 결과를 내보낸다.</p>
</li>
<li><p><span style="color: indianred"><strong>내부 로직:</strong></span> 리소스 생성 시 <code>uniqueString()</code> 함수 등을 사용해 네이밍 규칙을 자동화하거나, 특정 속성(예: <code>supportsHttpsTrafficOnly: true</code>)을 강제하여 사용자에게 보이지 않게 처리한다.</p>
<br>


</li>
</ul>
<ul>
<li><span style="color: indianred"><strong>소비:</strong></span> <code>module</code> 키워드를 사용하여 해당 bicep 파일을 참조하고 파라미터를 전달한다.</li>
</ul>
<h3 id="span-stylecolor-slateblue2-2-terraformspan"><span style="color: SlateBlue">2-2. Terraform</span></h3>
<ul>
<li><p><span style="color: indianred"><strong>구조:</strong></span> 일반적으로 <code>main.tf</code> (리소스 로직), <code>variables.tf</code> (입력 변수), <code>outputs.tf</code> (출력값)로 파일을 분리하여 관리한다.</p>
</li>
<li><p><span style="color: indianred"><strong>소비:</strong></span> <code>module</code> 블록을 선언하고 source 속성에 모듈이 위치한 경로(로컬 또는 원격)를 지정하여 사용한다.</p>
<br>

</li>
</ul>
<h3 id="span-stylecolor-slateblue2-3-pulumispan"><span style="color: SlateBlue">2-3. Pulumi</span></h3>
<ul>
<li><p><span style="color: indianred"><strong>특징:</strong></span> Python, C# 등 범용 프로그래밍 언어를 사용하므로, 해당 언어의 클래스나 함수 구조를 그대로 활용한다.</p>
</li>
<li><p><span style="color: indianred"><strong>구현:</strong></span> <code>&#39;Component Resource&#39;</code> 클래스를 정의하여 리소스 생성 로직을 캡슐화한다.</p>
</li>
<li><p><span style="color: indianred"><strong>소비:</strong></span> 메인 코드에서 해당 클래스의 인스턴스를 생성하는 방식으로 모듈을 호출한다.</p>
</li>
</ul>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine3-좋은-모듈을-만드는-7원칙span"><span style='background-color: MediumAquamarine'>3. 좋은 모듈을 만드는 7원칙</span></h2>
<hr>

<p><strong>단순히 코드를 분리한다고 좋은 모듈이 되는 것은 아니다. 지속 가능한 라이브러리를 구축하기 위해 다음 원칙을 따라야 한다.</strong></p>
<p><img src="https://velog.velcdn.com/images/taekyu_/post/4d3b8986-002f-4b04-92db-e0ea45a54ec6/image.png" alt=""></p>
<ol>
<li><p><span style="color: SlateBlue"><strong>단일 책임 원칙:</strong></span></p>
<ul>
<li><p><strong>슈퍼 모듈을 피해야 한다.</strong> 스토리지 모듈은 스토리지 생성에만 집중해야 한다.</p>
</li>
<li><p><span style="color: indianred"><strong>예외:</strong></span> Kubernetes 클러스터처럼 그 자체로 복합적인 리소스는 묶어서 배포하되, 네트워크처럼 외부 의존성이 있는 리소스는 분리하여 주입받는 것이 좋다.</p>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>단순한 인터페이스:</strong></span></p>
<ul>
<li><p>모든 속성을 파라미터로 노출하지 말아야 한다. <strong>모듈의 목적은 복잡성 은폐이다.</strong></p>
</li>
<li><p>사용자가 고민할 필요가 없는 설정(예: 보안 표준)은 내부적으로 고정하고, 꼭 필요한 값만 입력받는다.</p>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>가치 창출:</strong></span></p>
<ul>
<li><p>단순히 리소스 그룹처럼 옵션이 거의 없는 리소스를 감싸는 Wrapper 모듈은 의미가 없다. </p>
</li>
<li><p><strong>복잡성을 줄이거나 표준을 강제하는 가치가 있어야 한다.</strong></p>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>버전 관리:</strong></span></p>
<ul>
<li><p>모듈 코드를 수정했을 때 기존 사용자의 배포가 깨지면 안 된다. </p>
</li>
<li><p>시맨틱 버저닝을 도입하여 사용자가 업그레이드 시점을 선택할 수 있게 해야 한다.</p>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>접근성:</strong></span></p>
<ul>
<li>사용자가 모듈을 쉽게 가져다 쓸 수 있어야 한다. </li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>유지보수:</strong></span></p>
<ul>
<li><p>클라우드 공급자의 신규 기능이나 변경 사항을 제때 반영해야 한다. </p>
</li>
<li><p>방치된 모듈은 결국 버려진다.</p>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>문서화 및 홍보:</strong></span></p>
<ul>
<li><p>사용법이 문서화되지 않은 모듈은 아무도 쓰지 않는다. </p>
</li>
<li><p>또한, 모듈의 존재와 사용 이점을 조직 내에 적극적으로 알려야 한다.</p>
</li>
</ul>
</li>
</ol>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine4-모듈-배포-및-관리-전략span"><span style='background-color: MediumAquamarine'>4. 모듈 배포 및 관리 전략</span></h2>
<hr>

<p>*<em>로컬 경로(<code>./modules/storage</code>)를 참조하는 방식은 협업 환경에서 확장성이 없다. *</em></p>
<p><span style="color: indianred"><strong>각 도구별로 제공하는 중앙 저장소 기능을 활용하여 단일 진실 공급원을 구축해야 한다.</strong></span></p>
<ul>
<li><p><span style="color: SlateBlue"><strong>Azure (Bicep/ARM):</strong></span></p>
<ul>
<li><p><span style="color: indianred"><strong>Template Specs:</strong></span> Azure 리소스로 템플릿을 저장하고 버전 관리할 수 있다.</p>
</li>
<li><p><span style="color: indianred"><strong>Bicep Registry:</strong></span> Azure Container Registry(ACR)를 OCI 호환 저장소로 활용하여 모듈을 배포할 수 있다.</p>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>Terraform:</strong></span></p>
<ul>
<li>Git 리포지토리를 직접 참조하거나, Terraform Registry (Terraform Cloud/Enterprise)를 사용한다.</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>Pulumi:</strong></span></p>
<ul>
<li>프로그래밍 언어 기반이므로 npm (Node.js), PyPI (Python), NuGet (.NET) 등 언어별 패키지 매니저를 통해 배포하고 설치한다. </li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>AWS CloudFormation:</strong></span></p>
<ul>
<li>CloudFormation Registry를 통해 모듈을 등록하고 관리한다.</li>
</ul>
</li>
</ul>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine5-정리span"><span style='background-color: MediumAquamarine'>5. 정리</span></h2>
<hr>

<p>*<em>인프라 코드 모듈화는 단순한 코드 정리를 넘어, 조직의 인프라 거버넌스를 기술적으로 구현하는 핵심 전략이다. *</em></p>
<p><span style="color: indianred"></span>
<span style="color: SlateBlue"></span></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[90DaysOfDevOps (Day 84)]]></title>
            <link>https://velog.io/@taekyu_/90DaysOfDevOps-Day-84-ttzx8w7x</link>
            <guid>https://velog.io/@taekyu_/90DaysOfDevOps-Day-84-ttzx8w7x</guid>
            <pubDate>Sun, 01 Feb 2026 03:44:16 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>해당 스터디는 90DaysOfDevOps
<a href="https://github.com/MichaelCade/90DaysOfDevOps">https://github.com/MichaelCade/90DaysOfDevOps</a>
를 기반으로 진행한 내용입니다.</strong></p>
</blockquote>
<p>** Day 84 - Hacking Kubernetes For Beginners **</p>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine1-쿠버네티스-해킹span"><span style='background-color: MediumAquamarine'>1. 쿠버네티스 해킹</span></h2>
<hr>

<p>*<em>해킹이란 마법이 아니라, 설계자가 의도하지 않았던 무언가를 활용하는 창의적 접근이다. *</em></p>
<p>해당 프레젠테이션은 쿠버네티스 클러스터를 공격하는 5가지 주요 시나리오를 통해 공격자의 관점과 방어자의 대응 전략을 살펴본다.</p>
<p><img src="https://velog.velcdn.com/images/taekyu_/post/c06ee6c8-923d-4c75-a3f8-49ff1d003e8b/image.png" alt=""></p>
<ul>
<li><p><span style="color: indianred"><strong>시나리오1:</strong></span> <strong>Kubelet 해킹</strong></p>
</li>
<li><p><span style="color: indianred"><strong>시나리오2:</strong></span> <strong>서비스 및 웹 애플리케이션 해킹</strong></p>
</li>
<li><p><span style="color: indianred"><strong>시나리오3:</strong></span> 컨테이너 탈출</p>
</li>
<li><p><span style="color: indianred"><strong>시나리오4:</strong></span> 이미지 레지스트리 오염</p>
</li>
<li><p><span style="color: indianred"><strong>시나리오5:</strong></span> 악의적인 관리자와 특권 파드</p>
</li>
</ul>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine2-시나리오1-kubelet-해킹span"><span style='background-color: MediumAquamarine'>2. 시나리오1: Kubelet 해킹</span></h2>
<hr>

<h3 id="span-stylecolor-slateblue2-1-정상적인-흐름span"><span style="color: SlateBlue">2-1. 정상적인 흐름</span></h3>
<p>관리자가 kubectl을 사용하여 파드에 접속하려 할 때, 요청은 
<span style="color: indianred"><strong><code>API Server -&gt; etcd(검증) -&gt; Kubelet(노드)</code></strong></span> 순으로 전달된다. </p>
<p><strong>Kubelet은 각 워커 노드의 문지기 역할을 하며 파드와 컨테이너를 관리한다.</strong>
<br></p>
<h3 id="span-stylecolor-slateblue2-2-red-team-공격-방법span"><span style="color: SlateBlue">2-2. Red Team: 공격 방법</span></h3>
<p>공격자는 API 서버를 거치지 않고, 워커 노드의 <strong>Kubelet 포트(기본 10250)</strong>로 직접 통신을 시도한다.</p>
<ul>
<li><p><span style="color: indianred"><strong>공격 기법:</strong></span> <strong><code>curl -k https://&lt;node-ip&gt;:10250/pods</code></strong> 등과 같이 비인증 요청을 보낸다.</p>
</li>
<li><p><span style="color: indianred"><strong>결과:</strong></span> Kubelet이 적절히 보호되지 않은 경우, 공격자는 인증 없이 파드 목록을 조회하거나 exec API를 통해 컨테이너 내부로 진입하여 명령어를 실행할 수 있다.</p>
<br>

</li>
</ul>
<h3 id="span-stylecolor-slateblue2-3-blue-team-방어-및-조치-전략span"><span style="color: SlateBlue">2-3. Blue Team: 방어 및 조치 전략</span></h3>
<p>강연에서는 보안 담당자가 파라미터를 설정했다고 언급했다. </p>
<p><strong>이를 구체적으로 구현하기 위해서는 Kubelet 설정 파일(<code>/var/lib/kubelet/config.yaml</code>)을 다음과 같이 수정해야 한다.</strong></p>
<ol>
<li><p><span style="color: indianred"><strong>익명 인증 비활성화:</strong></span> 누구나 접근하지 못하도록 설정</p>
<ul>
<li><code>authentication.anonymous.enabled: false</code></li>
</ul>
</li>
<li><p><span style="color: indianred"><strong>Kubelet 권한 부여 모드 설정:</strong></span> 모든 요청이 API 서버를 통해 권한 검사를 받도록 설정</p>
<ul>
<li><code>authorization.mode: Webhook</code></li>
</ul>
</li>
<li><p><span style="color: indianred"><strong>인증서 기반 접근 제어:</strong></span> 클라이언트 인증서(x509)가 있는 요청만 수락하도록 설정한다.</p>
</li>
<li><p><span style="color: indianred"><strong>네트워크 정책 (NetworkPolicy):</strong></span> 워커 노드의 10250 포트에 대한 접근을 API 서버 등 신뢰할 수 있는 소스로만 제한하는 방화벽 규칙을 적용한다.</p>
</li>
</ol>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine3-시나리오2-서비스-및-웹-애플리케이션-해킹span"><span style='background-color: MediumAquamarine'>3. 시나리오2: 서비스 및 웹 애플리케이션 해킹</span></h2>
<hr>

<h3 id="span-stylecolor-slateblue3-1-정상적인-흐름span"><span style="color: SlateBlue">3-1. 정상적인 흐름</span></h3>
<p>사용자가 웹사이트에 접속하면 
<span style="color: indianred"><strong><code>Ingress -&gt; Service -&gt; Pod(Frontend)</code></strong></span> 순으로 트래픽이 전달된다. </p>
<p>프론트엔드에서 User ID를 입력하면 백엔드 DB와 통신하여 인증을 수행한다.
<br></p>
<h3 id="span-stylecolor-slateblue3-2-red-team-공격-방법span"><span style="color: SlateBlue">3-2. Red Team: 공격 방법</span></h3>
<p>공격자는 웹 애플리케이션의 입력 필드(User ID 창)에 정상적인 ID 대신 악의적인 명령어를 주입한다.</p>
<ul>
<li><p><span style="color: indianred"><strong>공격 기법:</strong></span> SQL Injection 또는 Command Injection </p>
<ul>
<li><code>; cat /etc/passwd</code> 또는 MySQL 제어 명령</li>
</ul>
</li>
<li><p><span style="color: indianred"><strong>결과:</strong></span> 애플리케이션의 취약점을 통해 백엔드 데이터베이스를 탈취하거나, Reverse Shell을 실행하여 컨테이너 내부 쉘 권한을 획득한다.</p>
<br>

</li>
</ul>
<h3 id="span-stylecolor-slateblue3-3-blue-team-방어-및-조치-전략span"><span style="color: SlateBlue">3-3. Blue Team: 방어 및 조치 전략</span></h3>
<p>강연에서는 코드를 수정하고 출력 제어를 추가했다고 했다. </p>
<p><strong>이는 애플리케이션 레벨과 인프라 레벨의 보안이 모두 필요하다.</strong></p>
<ol>
<li><p><span style="color: indianred"><strong>입력 값 검증:</strong></span> 애플리케이션 코드 단계에서 사용자 입력값에 대한 엄격한 타입 체크와 특수문자 필터링을 수행한다. (Secure Coding)</p>
</li>
<li><p><span style="color: indianred"><strong>WAF (Web Application Firewall):</strong></span> Ingress 단계에서 ModSecurity나 AWS WAF 등을 연동하여 SQL Injection 등의 잘 알려진 공격 패턴을 차단한다.</p>
</li>
<li><p><span style="color: indianred"><strong>최소 권한 원칙:</strong></span> 만약 뚫리더라도 피해를 최소화하기 위해 컨테이너를 Non-Root 사용자로 실행하고, 파일 시스템을 Read-Only로 설정한다.</p>
</li>
</ol>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine4-시나리오3-컨테이너-탈출span"><span style='background-color: MediumAquamarine'>4. 시나리오3: 컨테이너 탈출</span></h2>
<hr>

<h3 id="span-stylecolor-slateblue4-1-정상적인-흐름span"><span style="color: SlateBlue">4-1. 정상적인 흐름</span></h3>
<p><strong>공격자가 시나리오 2를 통해 컨테이너 내부 쉘을 획득했다고 가정한다.</strong>
<br></p>
<h3 id="span-stylecolor-slateblue4-2-red-team-공격-방법span"><span style="color: SlateBlue">4-2. Red Team: 공격 방법</span></h3>
<p><strong>공격자는 먼저 정찰을 수행한다. <code>id</code> 명령어로 루트 권한인지 확인하고, <code>ls /</code> 등을 통해 도커 환경임을 파악한다.</strong></p>
<ul>
<li><p><span style="color: indianred"><strong>공격 기법:</strong></span> 컨테이너가 과도한 권한을 가지고 있거나 커널 취약점이 있는 경우, 특수 제작된 스크립트를 실행하여 컨테이너 격리를 뚫고 호스트 또는 워커 노드의 쉘을 획득한다.</p>
</li>
<li><p><span style="color: indianred"><strong>결과:</strong></span> 워커 노드의 루트 권한을 장악하여 해당 노드의 모든 컨테이너를 제어한다.</p>
<br>

</li>
</ul>
<h3 id="span-stylecolor-slateblue4-3-blue-team-방어-및-조치-전략span"><span style="color: SlateBlue">4-3. Blue Team: 방어 및 조치 전략</span></h3>
<p>강연에서는 컨테이너 보안 파라미터를 설정했다고 했다. <strong>이는 SecurityContext와 런타임 보안을 의미한다.</strong></p>
<ol>
<li><p><span style="color: indianred"><strong>SecurityContext 강화:</strong></span> 파드 배포 시 다음 설정을 강제한다.</p>
<ul>
<li><p><code>allowPrivilegeEscalation: false</code> (권한 상승 방지)</p>
</li>
<li><p><code>privileged: false</code> (특권 모드 금지)</p>
</li>
<li><p><code>runAsNonRoot: true</code> (루트 사용자 실행 금지)</p>
</li>
</ul>
</li>
<li><p><span style="color: indianred"><strong>Linux Capabilities 제한:</strong></span> 컨테이너에 불필요한 리눅스 커널 권한을 제거한다. (<code>drop: [&quot;ALL&quot;]</code>)</p>
</li>
<li><p><span style="color: indianred"><strong>Seccomp 및 AppArmor 프로파일 적용:</strong></span> 컨테이너가 호스트 커널에 요청할 수 있는 System Call을 제한하여 탈출 가능성을 차단한다.</p>
</li>
<li><p><span style="color: indianred"><strong>Sandbox 컨테이너:</strong></span> gVisor나 Kata Containers와 같은 샌드박스 기술을 사용하여 커널 레벨의 격리를 강화한다.</p>
</li>
</ol>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine5-시나리오4-이미지-레지스트리-오염span"><span style='background-color: MediumAquamarine'>5. 시나리오4: 이미지 레지스트리 오염</span></h2>
<hr>

<h3 id="span-stylecolor-slateblue5-1-정상적인-흐름span"><span style="color: SlateBlue">5-1. 정상적인 흐름</span></h3>
<p><strong>Kubelet은 파드를 생성할 때 지정된 레지스트리에서 이미지를 Pull하여 컨테이너를 실행한다.</strong>
<br></p>
<h3 id="span-stylecolor-slateblue5-2-red-team-공격-방법span"><span style="color: SlateBlue">5-2. Red Team: 공격 방법</span></h3>
<p><strong>공격자가 레지스트리 접근 권한을 탈취하여 정상 이미지를 악성 코드가 심어진 이미지로 교체한다.</strong></p>
<ul>
<li><p><span style="color: indianred"><strong>공격 기법:</strong></span> 이미지 내부에 백도어나 리버스 쉘 코드를 삽입하여 기존 태그로 덮어쓰기한다.</p>
</li>
<li><p><span style="color: indianred"><strong>결과:</strong></span> 관리자가 정상적인 절차로 파드를 생성하더라도, 실행되는 컨테이너는 이미 오염된 상태이므로 공격자가 즉시 접속할 수 있다.</p>
<br>

</li>
</ul>
<h3 id="span-stylecolor-slateblue5-3-blue-team-방어-및-조치-전략span"><span style="color: SlateBlue">5-3. Blue Team: 방어 및 조치 전략</span></h3>
<p>강연에서는 이미지 스캔 및 해시 키 비교를 언급했다. 이를 자동화된 파이프라인으로 구축해야 한다.</p>
<ul>
<li><p><span style="color: indianred"><strong>이미지 서명 및 검증:</strong></span> </p>
<ul>
<li><p>Cosign이나 Notary를 사용하여 이미지를 서명한다. </p>
</li>
<li><p>배포 시 Admission Controller(Kyverno, OPA Gatekeeper)가 서명이 유효한 이미지만 실행되도록 강제한다.</p>
</li>
</ul>
</li>
<li><p><span style="color: indianred"><strong>이미지 취약점 스캔:</strong></span> CI/CD 파이프라인 및 레지스트리(Harbor 등) 단계에서 Trivy, Clair 등을 사용해 이미지를 주기적으로 스캔한다.</p>
</li>
<li><p><span style="color: indianred"><strong>불변 태그 사용:</strong></span> 레지스트리 설정에서 한 번 푸시된 태그(예: v1.0)를 덮어쓰지 못하도록 설정하거나, 이미지 태그 대신 고유한 해시값(sha256:abcd...)을 사용하여 배포한다.</p>
</li>
</ul>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine6-시나리오5-악의적인-관리자와-특권-파드span"><span style='background-color: MediumAquamarine'>6. 시나리오5: 악의적인 관리자와 특권 파드</span></h2>
<hr>

<h3 id="span-stylecolor-slateblue6-1-정상적인-흐름span"><span style="color: SlateBlue">6-1. 정상적인 흐름</span></h3>
<p><strong>쿠버네티스 관리자 권한을 가진 사용자(혹은 탈취된 계정)가 파드를 생성한다.</strong>
<br></p>
<h3 id="span-stylecolor-slateblue6-2-red-team-공격-방법span"><span style="color: SlateBlue">6-2. Red Team: 공격 방법</span></h3>
<p>관리자 계정이라도 호스트 서버(마스터/워커 노드)의 루트 파일 시스템에는 직접 접근할 수 없다. 하지만 관리자는 파드를 생성할 권한이 있다.</p>
<ul>
<li><span style="color: indianred"><strong>공격 기법:</strong></span> 호스트의 루트 디렉토리(<code>/</code>)를 파드 내부의 볼륨으로 마운트(hostPath 방식 이용)하는 특권 파드를 생성한다.</li>
<li><pre><code class="language-yaml">volumes:
- name: host-root
  hostPath:
    path: /</code></pre>
</li>
<li><span style="color: indianred"><strong>결과:</strong></span> 파드 내부로 진입(<code>exec</code>)하면 마운트된 볼륨을 통해 호스트의 모든 파일(Shadow 파일, SSH 키 등)을 읽고 수정할 수 있어 호스트를 완전히 장악한다.</li>
</ul>
<br>

<h3 id="span-stylecolor-slateblue6-2-red-team-공격-방법span-1"><span style="color: SlateBlue">6-2. Red Team: 공격 방법</span></h3>
<p>강연에서는 관리자 권한 제한 및 모니터링을 언급했다. </p>
<p><strong>이는 50:50의 싸움이라고 했지만, 기술적으로 통제 가능하다.</strong></p>
<ul>
<li><p><span style="color: indianred"><strong>Pod Security Admission (PSA) 적용:</strong></span> 네임스페이스 수준에서 <code>Restricted</code> 또는 <code>Baseline</code> 정책을 적용하여 <strong>hostPath 사용이나 privileged 모드를 원천 차단한다.</strong></p>
</li>
<li><p><span style="color: indianred"><strong>정책 엔진 도입 (Policy-as-Code):</strong></span> OPA Gatekeeper나 Kyverno를 사용하여 &quot;특정 그룹을 제외하고는 hostPath 마운트 금지&quot;와 같은 세밀한 정책을 강제한다.</p>
</li>
<li><p><span style="color: indianred"><strong>RBAC 최소화:</strong></span> </p>
<ul>
<li><p>파드 생성 권한은 생각보다 강력한 권한이다. </p>
</li>
<li><p>개발자에게는 파드 생성 권한 대신, 제한된 범위의 권한만 부여하거나 ArgoCD와 같은 GitOps 도구를 통해서만 배포하도록 통제한다.</p>
</li>
</ul>
</li>
<li><p><span style="color: indianred"><strong>Audit Logging:</strong></span> 쿠버네티스 Audit Log를 활성화하고, SIEM 시스템(Falcosecurity 등)과 연동하여 특권 파드 생성이 시도될 때 즉시 알람을 발생시킨다.</p>
</li>
</ul>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine7-정리-span"><span style='background-color: MediumAquamarine'>7. 정리 </span></h2>
<hr>

<p>*<em>방어자의 업무는 매우 어렵다. *</em></p>
<p><strong>공격자는 수많은 취약점 중 단 하나만 성공시키면 클러스터를 장악할 수 있지만, 방어자는 모든 구멍을 막아야 하기 때문이다.</strong></p>
<p>오늘 살펴본 5가지 시나리오는 빙산의 일각이며, 쿠버네티스 보안을 강화하기 위해서는 &#39;Hacking Kubernetes&#39;, &#39;Container Security&#39;와 같은 전문 서적을 참고하고, 지속적으로 클러스터의 보안 태세를 점검하는 것이 필수적이다.</p>
<p><span style="color: indianred"></span>
<span style="color: SlateBlue"></span></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[90DaysOfDevOps (Day 83)]]></title>
            <link>https://velog.io/@taekyu_/90DaysOfDevOps-Day-83-8dcir6g6</link>
            <guid>https://velog.io/@taekyu_/90DaysOfDevOps-Day-83-8dcir6g6</guid>
            <pubDate>Sun, 01 Feb 2026 02:46:50 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>해당 스터디는 90DaysOfDevOps
<a href="https://github.com/MichaelCade/90DaysOfDevOps">https://github.com/MichaelCade/90DaysOfDevOps</a>
를 기반으로 진행한 내용입니다.</strong></p>
</blockquote>
<p>** Day 83 - Saving Cloud Costs Using Existing Prometheus Metrics **</p>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine1-krr-kubernetes-resource-recommender-란span"><span style='background-color: MediumAquamarine'>1. KRR (Kubernetes Resource Recommender) 란?</span></h2>
<hr>

<p>최근 1~2년 사이 많은 기업들이 클라우드 비용 절감을 위해 온프레미스로 회귀하거나 하이브리드 클라우드 전략을 채택하고 있다. </p>
<p><span style="color: indianred"><strong>하지만 온프레미스는 확장성과 유지보수 측면에서 명확한 한계가 있다. 클라우드의 이점을 유지하면서 비용을 줄이는 방법은 없을까?</strong></span></p>
<p>연구에 따르면, 쿠버네티스 클러스터 비용의 69% 이상이 리소스 과다 할당으로 인해 낭비되고 있다고 한다. </p>
<p><span style="color: indianred"><strong>즉, 애플리케이션에 적절한 리소스(Request/Limit)만 할당해도 막대한 비용을 절감할 수 있다는 것이다.</strong></span></p>
<p>따라서 프레젠테이션에서는 기존 Prometheus 데이터를 활용하여 데이터 기반의 리소스 최적화 권장 사항을 제공하는 오픈 소스 도구, <strong>KRR(Kubernetes Resource Recommender)</strong>에 대해 제시한다.</p>
<hr>
<p><strong>KRR (Kubernetes Resource Recommender)이란, Robusta에서 개발한 KRR은 쿠버네티스 리소스(CPU/Memory)의 Request과 Limit 값을 최적화할 수 있도록 도와주는 오픈 소스 CLI 도구이다.</strong></p>
<p><img src="https://velog.velcdn.com/images/taekyu_/post/95f63414-1184-45d0-8af9-a60d36eb28cf/image.png" alt=""></p>
<ul>
<li><p><span style="color: indianred"><strong>에이전트리스 (No Agent):</strong></span> 클러스터에 별도의 에이전트를 지속적으로 실행할 필요가 없다.</p>
</li>
<li><p><span style="color: indianred"><strong>Prometheus 통합:</strong></span> 이미 수집된 Prometheus의 히스토리 데이터를 활용한다. 
즉, 추측이 아닌 실제 내 애플리케이션의 데이터를 기반으로 분석한다.</p>
</li>
<li><p><span style="color: indianred"><strong>즉시 실행:</strong></span> 한 번의 CLI 실행으로 즉각적인 결과를 얻을 수 있다.</p>
</li>
<li><p><span style="color: indianred"><strong>확장성:</strong></span> Python 기반으로 작성되어 있어 알고리즘을 사용자가 직접 커스터마이징할 수 있다.</p>
</li>
</ul>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine2-설치-및-실행-방법span"><span style='background-color: MediumAquamarine'>2. 설치 및 실행 방법</span></h2>
<hr>

<h3 id="span-stylecolor-slateblue2-1-사전-요구-사항span"><span style="color: SlateBlue">2-1. 사전 요구 사항</span></h3>
<ul>
<li><p><span style="color: indianred"><strong>Prometheus:</strong></span> 클러스터 메트릭을 수집 중이어야 한다.</p>
</li>
<li><p><span style="color: indianred"><strong>kube-state-metrics:</strong></span> KRR이 분석에 필요한 메트릭을 제공한다.</p>
<ul>
<li><strong>참고:</strong> <code>kube-prometheus-stack</code>을 사용 중이라면 이미 포함되어 있어 별도 설정이 필요 없다.<br>


</li>
</ul>
</li>
</ul>
<h3 id="span-stylecolor-slateblue2-2-실행-및-결과-분석span"><span style="color: SlateBlue">2-2. 실행 및 결과 분석</span></h3>
<p>KRR을 실행하면 지난 14일간의 데이터를 분석하여 다음과 같은 권장 사항 테이블을 출력한다.
<img src="https://velog.velcdn.com/images/taekyu_/post/0b1d577b-e28b-4d57-9af2-df88d1a87497/image.png" alt=""></p>
<ul>
<li><p><span style="color: indianred"><strong>Pods/Old Pods:</strong></span> 현재 실행 중인 파드와 과거 파드 수.</p>
</li>
<li><p><span style="color: indianred"><strong>Container:</strong></span> 파드 내 각 컨테이너별로 분석 결과를 제공한다.</p>
</li>
<li><p><span style="color: indianred"><strong>Recommended Request/Limit:</strong></span> 데이터 기반으로 산출된 최적의 CPU/Memory 값.</p>
</li>
<li><p><span style="color: indianred"><strong>Diff:</strong></span> 현재 설정값과 권장 값의 차이를 보여준다. (예: +251m은 추가 필요, -925Mi는 절감 가능)</p>
</li>
</ul>
<p><strong>이 결과를 통해 사용자는 어떤 서비스가 과다 할당되었는지, 혹은 리소스 부족 위험이 있는지 한눈에 파악할 수 있다.</strong></p>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine3-krr에서는-왜-cpu-limit을-설정하지-말아야-하는가span"><span style='background-color: MediumAquamarine'>3. KRR에서는 왜 CPU Limit을 설정하지 말아야 하는가</span></h2>
<hr>

<p><strong>KRR을 실행해보면 대부분의 권장 사항이 CPU Limit을 설정 해제(Unset)하라는 내용임을 알게 된다.</strong> </p>
<p>이는 많은 엔지니어들이 의아해하는 부분이지만, 첨부된 이미지를 통해 그 이유를 명확히 이해할 수 있다.
<img src="https://velog.velcdn.com/images/taekyu_/post/06178703-3630-4b25-aa97-80c51d318761/image.png" width="50%" height="n%"></p>
<p><strong>해당 이미지는 CPU Request와 Limit 설정 조합에 따른 파드의 동작 방식을 4분면으로 나누어 설명한다.</strong></p>
<ol>
<li><p><span style="color: SlateBlue"><strong>CPU Requests + CPU Limits (주황색 - 좌상단)</strong></span></p>
<ul>
<li><p><span style="color: indianred"><strong>상태:</strong></span> Request와 Limit을 모두 설정한 경우.</p>
</li>
<li><p><span style="color: indianred"><strong>동작:</strong></span> Request만큼의 CPU는 보장받는다. 하지만 Limit을 초과하는 CPU 사용은 불가능하다.</p>
</li>
<li><p><span style="color: indianred"><strong>문제점:</strong></span> 노드에 유휴 CPU 자원이 남더라도, 파드는 Limit에 막혀 이를 사용할 수 없다. 이는 CPU Throttling을 유발하여 애플리케이션의 성능 저하(Latency 증가)로 이어진다.</p>
<br>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>CPU Requests + No CPU Limits (초록색 - 우상단, 권장)</strong></span></p>
<ul>
<li><p><span style="color: indianred"><strong>상태:</strong></span> Request는 설정하고, Limit은 설정하지 않은 경우.</p>
</li>
<li><p><span style="color: indianred"><strong>동작:</strong></span> Request만큼의 CPU 자원은 확실히 보장받는다.</p>
</li>
<li><p><span style="color: indianred"><strong>장점:</strong></span> 노드에 남는 CPU 자원이 있다면, 파드는 필요한 만큼 이를 가져다 쓸 수 있다.</p>
</li>
<li><p><span style="color: indianred"><strong>결론:</strong></span> *<em>CPU는 압축 가능한 자원이다. *</em>
즉, 시스템이 바쁠 때는 조금 느려질 뿐 죽지는 않는다. 따라서 Limit을 없애 유휴 자원을 최대한 활용하여 성능을 높이는 것이 효율적이다. KRR이 이 방식을 권장하는 이유다.</p>
<br>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>No CPU Requests (하단 영역)</strong></span></p>
<ul>
<li><p><span style="color: indianred"><strong>No Requests + Limits (주황색):</strong></span> 쿠버네티스가 자동으로 Request를 Limit과 동일하게 설정한다. Limit만큼 보장되지만 그 이상은 사용 불가하다.</p>
</li>
<li><p><span style="color: indianred"><strong>No Requests + No Limits (빨간색 - 우하단):</strong></span> 아무런 자원 보장도 받지 못한다. 노드 자원이 부족하면 가장 먼저 성능이 저하되거나 죽을 수 있다. 절대 권장하지 않는다.</p>
<br>

</li>
</ul>
</li>
</ol>
<blockquote>
<ul>
<li><span style="color: SlateBlue"><strong>주의:</strong></span> <strong>위 내용은 CPU에만 해당된다. Memory는 압축 불가능한 자원이므로, Limit을 초과하면 OOM Kill이 발생한다. 따라서 메모리는 Limit 설정이 필수적이다.</strong></li>
</ul>
</blockquote>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine4-krr-vs-vpa-vertical-pod-autoscalerspan"><span style='background-color: MediumAquamarine'>4. KRR vs VPA (Vertical Pod Autoscaler)</span></h2>
<hr>

<p><strong>KRR과 유사한 기능을 하는 쿠버네티스 네이티브 도구인 VPA와의 차이점은 다음과 같다.</strong></p>
<table>
<thead>
<tr>
<th>특징</th>
<th align="left">KRR (Robusta)</th>
<th align="left">VPA (Kubernetes Native)</th>
</tr>
</thead>
<tbody><tr>
<td>실행 방식</td>
<td align="left">CLI 도구 (필요할 때 실행)</td>
<td align="left">클러스터 내 상시 실행 데몬</td>
</tr>
<tr>
<td>결과 도출</td>
<td align="left">즉시 (기존 Prometheus 데이터 활용)</td>
<td align="left">일정 기간 데이터 수집 필요 (Warm-up)</td>
</tr>
<tr>
<td>적용 방식</td>
<td align="left">권장 사항 리포트 제공 (사람이 판단)</td>
<td align="left">파드 설정을 직접/자동으로 수정</td>
</tr>
<tr>
<td>커스텀</td>
<td align="left">알고리즘 확장 및 수정 용이</td>
<td align="left">설정이 제한적</td>
</tr>
</tbody></table>
<p>KRR은 즉각적인 가시성을 제공하고, 변경 사항을 적용하기 전 엔지니어가 검토할 수 있다는 점에서 운영 안정성이 높다.</p>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine5-추가-기능-및-활용span"><span style='background-color: MediumAquamarine'>5. 추가 기능 및 활용</span></h2>
<hr>

<p>KRR은 단순 CLI를 넘어 다양한 방식으로 활용 가능하다.</p>
<ul>
<li><p><span style="color: indianred"><strong>Slack 통합:</strong></span> Robusta와 연동하여 주기적으로 리소스 최적화 리포트를 슬랙으로 받아볼 수 있다.</p>
</li>
<li><p><span style="color: indianred"><strong>상세 분석:</strong></span> Robusta UI를 통해 특정 권장 사항이 도출된 근거(히스토리 그래프 등)를 시각적으로 확인할 수 있다.</p>
</li>
<li><p><span style="color: indianred"><strong>K9s 플러그인:</strong></span> 터미널 UI 도구인 K9s에 플러그인으로 설치하여, 실시간으로 파드 리스트 옆에서 권장 값을 확인할 수 있다.</p>
</li>
</ul>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine6-정리span"><span style='background-color: MediumAquamarine'>6. 정리</span></h2>
<hr>

<ol>
<li><p><span style="color: indianred"><strong>리소스의 Request/Limit 최적화만으로도 상당한 비용을 아낄 수 있다.</strong></span></p>
</li>
<li><p><strong>새로운 데이터 수집 도구 필요 없이, 기존 Prometheus 데이터를 활용하면 된다.</strong></p>
</li>
<li><p><strong>KRR을 사용하면 별도의 에이전트 없이 즉각적인 최적화 권고안을 얻을 수 있다.</strong></p>
</li>
<li><p><strong>CPU Limit을 제거하고 Request를 적절히 설정하는 것이 리소스 효율성과 성능 면에서 가장 유리하다.</strong></p>
</li>
</ol>
<p><span style="color: indianred"></span>
<span style="color: SlateBlue"></span></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[90DaysOfDevOps (Day 82)]]></title>
            <link>https://velog.io/@taekyu_/90DaysOfDevOps-Day-82-mgpnhtb6</link>
            <guid>https://velog.io/@taekyu_/90DaysOfDevOps-Day-82-mgpnhtb6</guid>
            <pubDate>Sat, 31 Jan 2026 17:21:43 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>해당 스터디는 90DaysOfDevOps
<a href="https://github.com/MichaelCade/90DaysOfDevOps">https://github.com/MichaelCade/90DaysOfDevOps</a>
를 기반으로 진행한 내용입니다.</strong></p>
</blockquote>
<p>** Day 82 - Dev Containers in VS Code **</p>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine1-dev-containers의-본질과-도입-필요성-span"><span style='background-color: MediumAquamarine'>1. Dev Containers의 본질과 도입 필요성 </span></h2>
<hr>

<h3 id="span-stylecolor-slateblue1-1-단순한-docker가-아닌-환경-사양-specspan"><span style="color: SlateBlue">1-1. 단순한 Docker가 아닌 환경 사양 (Spec)</span></h3>
<p><strong>많은 개발자가 Dev Containers를 단순히 Docker 이미지를 띄우는 것으로 오해하곤 한다.</strong></p>
<p><span style="color: indianred"><strong>하지만 Dev Containers는 커뮤니티가 채택한 오픈 소스 사양(Specification)이다.</strong></span></p>
<ul>
<li><p><span style="color: indianred"><strong>정의:</strong></span> 단순한 OS 뿐만 아니라 개발에 필요한 도구, 런타임, Extensions, 설정, 파일 시스템 마운트 등을 코드인 devcontainer.json로 정의한 집합체다.
<img src="https://velog.velcdn.com/images/taekyu_/post/990fda0b-8eed-4b6e-8966-1b6a21b106c0/image.png" alt=""></p>
</li>
<li><p><span style="color: indianred"><strong>아키텍처:</strong></span> </p>
<ul>
<li><p>로컬 VS Code가 컨테이너 내부의 VS Code Server와 연결되는 구조다. </p>
</li>
<li><p>소스 코드는 마운트되어 격리된 환경에서 실행되지만, 개발자는 로컬 테마와 단축키를 그대로 사용하는 Inner Loop(내부 개발 루프)를 경험할 수 있다.</p>
</li>
</ul>
</li>
</ul>
<br>


<h3 id="span-stylecolor-slateblue1-2-왜-도입해야-하는가-span"><span style="color: SlateBlue">1-2. 왜 도입해야 하는가? </span></h3>
<p>개발 현장에서 겪는 세 가지 주요 고통을 해결한다.</p>
<ul>
<li><p><span style="color: indianred"><strong>고통스러운 온보딩:</strong></span> </p>
<ul>
<li>신규 프로젝트 투입 시 하드웨어 세팅, 라이선스 설정, 특정 경로 파일 복사 등 수작업으로 인해 며칠씩 소요되는 시간을 단축한다.</li>
</ul>
</li>
<li><p><span style="color: indianred"><strong>버전 호환성 문제:</strong></span> </p>
<ul>
<li><p>&quot;팀원 A는 Node 14를 쓰고 나는 Node 12를 써서 코드가 깨지는&quot; 상황을 방지한다. </p>
</li>
<li><p>컨설팅 업무 시 고객사마다 다른 언어 버전(.NET, Java 등)을 요구해도, 로컬 머신의 오염 없이 프로젝트별로 격리된 환경을 사용할 수 있다.</p>
</li>
</ul>
</li>
<li><p><span style="color: indianred"><strong>문서화와 실행의 괴리:</strong></span> </p>
<ul>
<li><p>README에 &quot;시작 전 1, 2, 3단계를 수행하시오&quot;라고 적어도 누락하기 쉽다. </p>
</li>
<li><p>Dev Containers는 <code>post-create-command</code> 등을 통해 초기화 작업을 자동화한다.</p>
</li>
</ul>
</li>
</ul>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine2-환경-구축-실습-span"><span style='background-color: MediumAquamarine'>2. 환경 구축 실습 </span></h2>
<hr>


<p><strong>Dev Containers의 가장 큰 장점은 로컬(Docker Desktop)과 클라우드(GitHub Codespaces)를 동일한 설정으로 오갈 수 있다는 유연성이다.</strong></p>
<h3 id="span-stylecolor-slateblue2-1-로컬-vs-code에서의-구축-span"><span style="color: SlateBlue">2-1. 로컬 VS Code에서의 구축 </span></h3>
<p><strong>프레젠테이션에서는 VS Code와 Docker Desktop(WSL 2)을 사용한 데모를 통해 다음 과정을 시연했다.</strong></p>
<ul>
<li><p><span style="color: indianred"><strong>필수 도구:</strong></span> &#39;Dev Containers&#39; 확장 프로그램과 &#39;GitHub Codespaces&#39; 확장이 필요하다.</p>
</li>
<li><p><span style="color: indianred"><strong>설정 생성:</strong></span> 명령 팔레트(F1)에서 <code>Add Dev Container Configuration Files</code>를 실행하여 템플릿을 선택한다. Alpine, Debian 같은 OS 베이스나 Go, Rust 같은 언어 베이스 템플릿을 제공한다.</p>
</li>
<li><p><span style="color: indianred"><strong>기능 활용:</strong></span> 복잡한 Dockerfile 스크립트 작성 없이, &#39;Features&#39; 메뉴에서 Azure CLI, Terraform, Kubectl 등을 체크박스 선택만으로 컨테이너에 주입할 수 있다.</p>
</li>
<li><p><span style="color: indianred"><strong>결과물:</strong></span> </p>
<ul>
<li><p><code>.devcontainer</code> 폴더 내에 <code>devcontainer.json(메인 설정)</code>, <code>Dockerfile(빌드 정의)</code>, <code>dependabot.yml(버전 관리)</code> 등이 생성된다.</p>
</li>
<li><p>이를 실행(&quot;Reopen in Container&quot;)하면 로컬에는 없는 도구들이 설치된 완벽한 개발 환경이 뚝딱 만들어진다.</p>
<br>


</li>
</ul>
</li>
</ul>
<h3 id="span-stylecolor-slateblue2-2-github-codespaces를-활용한-클라우드-개발span"><span style="color: SlateBlue">2-2. GitHub Codespaces를 활용한 클라우드 개발</span></h3>
<p>고사양 PC가 없거나 Docker 라이선스 문제가 있다면 GitHub Codespaces가 대안이 된다.</p>
<ul>
<li><p><span style="color: indianred"><strong>브라우저 모드:</strong></span> GitHub 리포지토리에서 버튼 하나로 실행되며, 별도 설치 없이 브라우저 내에서 VS Code 환경을 제공한다. .NET 8, GitHub CLI 등 설정된 도구가 즉시 가용 상태가 된다.</p>
</li>
<li><p><span style="color: indianred"><strong>하이브리드 모드 (Open in VS Code):</strong></span> 브라우저가 어색하다면, 로컬 VS Code를 인터페이스로 사용하고 컴퓨팅 자원만 클라우드(Codespace)를 사용할 수 있다. 로컬의 편안함과 클라우드의 성능을 동시에 누리는 방식이다.</p>
</li>
<li><p><span style="color: indianred"><strong>관리 기능:</strong></span> Dotfiles(개인 설정) 자동 적용, Secrets(API 키) 관리, 데이터 주권을 위한 리전 선택 등을 지원한다.</p>
</li>
<li><p><span style="color: indianred"><strong><code>containers.dev</code> 문서: **</span> **<a href="https://containers.dev/features">https://containers.dev/features</a></strong></p>
</li>
</ul>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine3-디버깅-및-네트워크-통합-span"><span style='background-color: MediumAquamarine'>3. 디버깅 및 네트워크 통합 </span></h2>
<hr>

<p><strong>Dev Containers는 환경만 격리할 뿐, 개발자가 누려야 할 생산성 도구(디버거, 네트워크 등)는 로컬 환경처럼 투명하게 연결해 준다.</strong></p>
<h3 id="span-stylecolor-slateblue3-1-로컬과-동일한-원격-디버깅span"><span style="color: SlateBlue">3-1. 로컬과 동일한 원격 디버깅</span></h3>
<p>프레젠테이션에서는 Rust와 Go 언어 샘플을 통해 디버깅 과정을 시연했다.</p>
<ul>
<li><p>코드는 컨테이너(또는 클라우드) 내부에서 돌지만, 개발자는 로컬 VS Code에서 중단점(Breakpoint)을 설정한다.</p>
</li>
<li><p>F5를 눌러 실행하면 정확히 중단점에서 멈추고, 변수 값 조사(Inspect)나 스택 추적을 로컬 개발과 똑같이 수행할 수 있다.</p>
<br>

</li>
</ul>
<h3 id="span-stylecolor-slateblue3-2-포트-포워딩span"><span style="color: SlateBlue">3-2. 포트 포워딩</span></h3>
<p>웹 애플리케이션 개발 시 네트워크 연결도 자동으로 처리된다.</p>
<ul>
<li><p><span style="color: indianred"><strong>시나리오:</strong></span> 클라우드 Codespace 내부에서 웹 서버를 9000번 포트로 실행했다.</p>
</li>
<li><p><span style="color: indianred"><strong>자동 연결:</strong></span> VS Code는 이를 감지하고 내 로컬 머신의 <code>localhost:9000</code>으로 자동 포트 포워딩을 수행한다.</p>
</li>
<li><p><span style="color: indianred"><strong>결과:</strong></span>  개발자는 자신의 로컬 브라우저(Chrome, Edge 등)를 열어 localhost:9000에 접속하면, 클라우드에 있는 서버와 연결된다. 심지어 이 요청에 대해서도 실시간 디버깅이 작동한다.</p>
</li>
</ul>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine4-정리-span"><span style='background-color: MediumAquamarine'>4. 정리 </span></h2>
<hr>

<p>*<em>Dev Containers는 단순한 도구가 아니라 개발 환경의 표준화를 위한 솔루션이다. *</em></p>
<p><span style="color: indianred">*<em>프로젝트에 <code>.devcontainer</code> 폴더를 추가하는 것만으로, 팀 전체가 버전 의존성에서 벗어나고 온보딩 시간을 획기적으로 단축할 수 있다. *</em></span></p>
<p><span style="color: indianred"></span>
<span style="color: SlateBlue"></span></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[90DaysOfDevOps (Day 81)]]></title>
            <link>https://velog.io/@taekyu_/90DaysOfDevOps-Day-81-yqv0c0pr</link>
            <guid>https://velog.io/@taekyu_/90DaysOfDevOps-Day-81-yqv0c0pr</guid>
            <pubDate>Fri, 30 Jan 2026 17:43:18 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>해당 스터디는 90DaysOfDevOps
<a href="https://github.com/MichaelCade/90DaysOfDevOps">https://github.com/MichaelCade/90DaysOfDevOps</a>
를 기반으로 진행한 내용입니다.</strong></p>
</blockquote>
<p>** Day 81 - Leveraging Kubernetes to build a better Cloud Native Development Experience **</p>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine1-okteto에-대한-발전-배경-문제-제기span"><span style='background-color: MediumAquamarine'>1. Okteto에 대한 발전 배경 (문제 제기)</span></h2>
<hr>

<h3 id="span-stylecolor-slateblue1-1-배포에서-개발로의-관점-이동span"><span style="color: SlateBlue">1-1. 배포에서 개발로의 관점 이동</span></h3>
<p><strong>2014년 쿠버네티스 초기 시절, 업계의 주된 관심사는 워크로드를 어떻게 쿠버네티스에 배포할 것인가였다.</strong></p>
<p>당시에는 배포 자체가 난제였기에 &#39;Kubernetes the Hard Way&#39;와 같은 학습 자료나 Rancher Desktop 같은 솔루션들이 등장하며 배포의 복잡성을 해결하려 했다.</p>
<p>하지만 시간이 흐르며 상황은 변했다. </p>
<p><span style="color: indianred"><strong>개발자의 본질은 인프라 배포가 아닌 코드 작성에 있다.</strong></span> </p>
<p><strong>개발자는 불필요한 배포에 시간을 쏟기보다 비즈니스 로직 구현에 집중하기를 원한다.</strong>
<br></p>
<h3 id="span-stylecolor-slateblue1-2-전통적인-개발-루프의-고통-span"><span style="color: SlateBlue">1-2. 전통적인 개발 루프의 고통 </span></h3>
<p>일반적인 클라우드 네이티브 애플리케이션 개발 프로세스이다.</p>
<ol>
<li><p><span style="color: indianred"><strong>SRS(요구사항) 분석 및 코딩:</strong></span> 개발팀이 기능을 구현한다.</p>
</li>
<li><p><span style="color: indianred"><strong>컨테이너화:</strong></span> Dockerfile을 작성하고 이미지를 빌드한다.</p>
</li>
<li><p><span style="color: indianred"><strong>레지스트리 Push:</strong></span> 빌드된 이미지를 컨테이너 레지스트리에 업로드한다.</p>
</li>
<li><p><span style="color: indianred"><strong>Pull 및 배포:</strong></span> 쿠버네티스 클러스터에서 이미지를 받아(Pull) 배포한다.</p>
<br>

</li>
</ol>
<p>문제는 기능 추가나 버그 수정이 필요할 때마다 이 과정을 무한 반복해야 한다는 점이다.</p>
<ul>
<li><p><span style="color: indianred"><strong>시나리오:</strong></span> 로컬에서 코드를 수정했다. 이 변경 사항이 운영 환경과 유사한 쿠버네티스 환경에서 어떻게 동작할지 확인해야 한다.</p>
</li>
<li><p><span style="color: indianred"><strong>비효율:</strong></span> 코드를 한 줄 고칠 때마다 <strong><code>이미지 Build -&gt; Push -&gt; Pull -&gt; 배포</code></strong> 과정을 거쳐야 한다.</p>
</li>
<li><p><span style="color: indianred"><strong>리스크:</strong></span> 로컬에서는 잘 작동하던 코드가 실제 클러스터에 배포되었을 때 의존성 문제 등으로 터질 수 있다. &quot;내 컴퓨터에서는 되는데?&quot;라는 상황이 발생한다.</p>
<br>

</li>
</ul>
<h3 id="span-stylecolor-slateblue1-3-제1원칙에-입각한-해결책span"><span style="color: SlateBlue">1-3. 제1원칙에 입각한 해결책</span></h3>
<p><strong>이 문제의 핵심은 피드백 루프가 너무 길고, 운영 환경과의 괴리가 크다는 것이다.</strong></p>
<p>이를 해결하기 위한 이상적인 솔루션은 다음과 같다.</p>
<p><span style="color: indianred"><strong>&quot;이미지를 매번 빌드하지 않고, 로컬 머신의 변경 사항이 쿠버네티스 클러스터 내부의 애플리케이션과 즉시 동기화되어 Preview 환경에서 바로 확인할 수 있다면 어떨까?&quot;</strong></span></p>
<p>이것이 바로 Okteto가 해결하고자 하는 지점이다.</p>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine2-솔루션-okteto-the-solutionspan"><span style='background-color: MediumAquamarine'>2. 솔루션: Okteto (The Solution)</span></h2>
<hr>

<p>*<em>Okteto의 핵심 기능은 로컬 개발 환경과 클러스터 환경의 실시간 동기화다. *</em></p>
<p><span style="color: indianred"><strong>이를 통해 개발자는 매번 이미지를 빌드/배포하는 과정 없이, 로컬에서 코드를 저장하는 즉시 클러스터에 반영된 결과를 확인할 수 있다.</strong></span></p>
<p><img src="https://velog.velcdn.com/images/taekyu_/post/4866145d-7af1-428f-8a19-4780e439edd7/image.png" alt=""></p>
<ul>
<li><p><span style="color: indianred"><strong>Okteto CLI &amp; Cloud:</strong></span> CLI와 관리형 클라우드 서비스를 모두 제공한다.</p>
</li>
<li><p><span style="color: indianred"><strong>Preview 환경:</strong></span> PR 단계에서 변경 사항이 적용된 라이브 프리뷰를 자동으로 생성할 수 있다.</p>
</li>
<li><p><span style="color: indianred"><strong>동기화 메커니즘:</strong></span> 로컬 파일 시스템의 변경 사항을 컨테이너 내부로 즉시 전송한다.</p>
<br>

</li>
</ul>
<h3 id="span-stylecolor-slateblue-21-핵심-아키텍처-및-작동-원리span"><span style="color: SlateBlue"> 2.1. 핵심 아키텍처 및 작동 원리</span></h3>
<p>Okteto은 단순한 파일 복사가 아니다. </p>
<p><strong>기존에 배포된 애플리케이션의 컨테이너를 개발용 컨테이너로 교체하는 기술이 핵심이다.</strong></p>
<ul>
<li><p><span style="color: indianred"><strong>배포 교체:</strong></span></p>
<ul>
<li><p><code>okteto up</code>을 실행하면, Okteto는 기존의 운영용 Pod를 내리고 개발 도구(컴파일러, 디버거 등)가 포함된 Dev Container로 교체하여 재실행한다. </p>
</li>
<li><p>개발이 끝나면 원래 설정으로 자동 복구된다.</p>
</li>
</ul>
</li>
<li><p><span style="color: indianred"><strong>양방향 파일 동기화:</strong></span></p>
<ul>
<li><p>로컬 PC의 소스 코드 디렉토리와 클러스터 내 컨테이너를 네트워크로 연결한다. </p>
</li>
<li><p><span style="color: indianred"><strong>로컬에서 파일을 저장하는 순간, 변경된 파일만 즉시 컨테이너로 전송</strong></span>되며, 컨테이너 내부의 Hot Reload 도구가 이를 감지해 프로세스를 재시작한다. (소요 시간: 0.5초~2초)</p>
</li>
</ul>
</li>
<li><p><span style="color: indianred"><strong>자동 포트 포워딩:</strong></span></p>
<ul>
<li>별도의 Ingress 설정이나 kubectl port-forward 없이도, 로컬호스트(localhost:8080)로 요청을 보내면 터널링을 통해 클러스터 내부의 컨테이너로 안전하게 전달된다.<br>

</li>
</ul>
</li>
</ul>
<h3 id="span-stylecolor-slateblue-2-2-주요-기능-상세span"><span style="color: SlateBlue"> 2-2. 주요 기능 상세</span></h3>
<ul>
<li><p><span style="color: indianred"><strong>Okteto Manifest (okteto.yml)</strong></span></p>
<ul>
<li><p>Okteto가 어떻게 동작해야 하는지 정의하는 설정 파일이다. </p>
</li>
<li><p>Dockerfile만 있어도 자동 추론하지만, 정교한 제어를 위해 작성한다.</p>
</li>
<li><pre><code class="language-yaml"># okteto.yml 예시
name: my-api
image: okteto/node:18  # 개발에 사용할 도구가 포함된 이미지
command: [&quot;bash&quot;]      # 컨테이너 시작 시 실행할 셸
sync:
  - .:/usr/src/app     # 로컬의 현재 폴더(.)를 컨테이너의 /usr/src/app과 동기화
forward:
  - 8080:8080          # 포트 포워딩 설정
  - 9229:9229          # 디버거 포트 연결 (원격 디버깅 가능)</code></pre>
</li>
<li><p>이 설정을 통해 어떤 이미지로 교체할지, 어떤 폴더를 동기화할지를 지정한다.</p>
<br>
</li>
</ul>
</li>
<li><p><span style="color: indianred"><strong>Preview 환경</strong></span></p>
<ul>
<li><p>GitHub/GitLab과 연동하여 PR가 생성될 때마다 격리된 네임스페이스에 해당 코드를 배포한다.</p>
</li>
<li><p><strong>Before:</strong> &quot;내 로컬에서 돌려봤는데 잘 돼. 머지해줘.&quot; (검증 불가)</p>
</li>
<li><p><strong>After:</strong> &quot;PR 34번 프리뷰 링크 생성됐어. 거기서 직접 눌러봐.&quot; (확실한 검증)</p>
</li>
<li><p>DB, Redis 등 연관된 모든 서비스를 포함한 전체 스택을 띄워주므로 통합 테스트에 유리하다.</p>
</li>
<li><p>PR이 닫히거나 머지되면 해당 환경(네임스페이스)은 자동으로 삭제되어 리소스 낭비를 막는다.</p>
<br>
</li>
</ul>
</li>
<li><p><span style="color: indianred"><strong>원격 디버거 연결</strong></span></p>
<ul>
<li><p>파일 동기화뿐만 아니라 디버깅 포트도 연결된다. </p>
</li>
<li><p>로컬 IDE에서 중단점을 찍으면, 쿠버네티스 클러스터에서 실행 중인 코드가 멈추고 변수 상태를 검사할 수 있다.</p>
</li>
</ul>
</li>
</ul>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine3-데모-시연-및-동작-원리span"><span style='background-color: MediumAquamarine'>3. 데모 시연 및 동작 원리</span></h2>
<hr>

<p><strong>발표에서는 &#39;Movies with Compose&#39;라는 React, Node.js, MongoDB, Nginx로 구성된 마이크로서비스 애플리케이션을 통해 Okteto의 장점을 어필했다.</strong></p>
<h3 id="span-stylecolor-slateblue3-1-초기-설정-및-배포-okteto-upspan"><span style="color: SlateBlue">3-1. 초기 설정 및 배포 (okteto up)</span></h3>
<ul>
<li><p><span style="color: indianred"><strong>애플리케이션 준비:</strong></span> docker-compose.yml 또는 Dockerfile이 있는 프로젝트를 준비한다. 쿠버네티스 매니페스트가 없어도 된다.</p>
</li>
<li><p><span style="color: indianred"><strong>명령어 실행:</strong></span> <code>okteto context</code>로 클러스터를 지정하고 <code>okteto up</code>을 실행한다.</p>
</li>
<li><p><span style="color: indianred"><strong>자동화된 프로세스:</strong></span></p>
<ul>
<li><p>Okteto는 소스 코드를 분석하여 필요한 이미지를 빌드하고 Okteto Cloud 혹은 지정된 클러스터에 배포한다.</p>
</li>
<li><p>각 서비스(API, Frontend, DB 등)와 외부 접속을 위한 엔드포인트(URL)를 자동으로 생성한다.</p>
<br>

</li>
</ul>
</li>
</ul>
<h3 id="span-stylecolor-slateblue3-2-개발-컨테이너-활성화span"><span style="color: SlateBlue">3-2. 개발 컨테이너 활성화</span></h3>
<p>배포가 완료되면 Okteto는 사용자에게 <strong>&quot;어떤 서비스를 개발 모드로 전환할 것인가?&quot;</strong>를 묻는다.</p>
<ul>
<li><p>사용자가 특정 서비스(예: API)를 선택하면, Okteto는 해당 서비스의 기존 운영 컨테이너를 개발 컨테이너로 교체한다.</p>
</li>
<li><p>해당 개발 컨테이너는 로컬 머신의 소스 코드 디렉토리와 볼륨 동기화가 설정되어 있다.</p>
</li>
<li><p>터미널은 해당 컨테이너의 Shell로 바로 연결된다.</p>
<br>


</li>
</ul>
<h3 id="span-stylecolor-slateblue3-3-실시간-코드-수정-및-반영span"><span style="color: SlateBlue">3-3. 실시간 코드 수정 및 반영</span></h3>
<p>시연에서는 영화 목록이 중복해서 출력되는 버그를 수정하는 과정을 보여주었다.</p>
<ol>
<li><p><span style="color: indianred"><strong>버그 확인:</strong></span> 생성된 프리뷰 URL로 접속하여 버그를 확인한다.</p>
</li>
<li><p><span style="color: indianred"><strong>코드 수정:</strong></span> 로컬 IDE에서 server.js 파일을 열어 db.collection(&#39;movies&#39;)를 올바른 컬렉션으로 수정하고 저장한다.</p>
</li>
<li><p><span style="color: indianred"><strong>즉시 반영:</strong></span> 별도의 docker build나 kubectl apply 명령어가 필요 없다. 저장하는 순간 Okteto가 변경된 파일을 컨테이너로 동기화한다.</p>
</li>
<li><p><span style="color: indianred"><strong>결과 확인:</strong></span> 브라우저를 새로고침하면 수정된 코드가 즉시 반영되어 버그가 해결된 것을 볼 수 있다.</p>
<br>


</li>
</ol>
<h3 id="span-stylecolor-slateblue3-4-dockerfile만으로-충분하다span"><span style="color: SlateBlue">3-4. Dockerfile만으로 충분하다</span></h3>
<p>가장 강력한 장점 중 하나는 복잡한 쿠버네티스 지식이 없어도 된다는 점이다.</p>
<p><img src="https://velog.velcdn.com/images/taekyu_/post/efe54292-91ac-49b0-af1a-95e8440ddfa5/image.png" alt=""></p>
<p><strong>Dockerfile이나 docker-compose.yml만 있다면, Okteto가 이를 기반으로 쿠버네티스 배포를 자동으로 처리하고 프리뷰 환경을 구축해준다.</strong></p>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine4-결론span"><span style='background-color: MediumAquamarine'>4. 결론</span></h2>
<hr>

<p>*<em>과거에는 배포 자체가 목적이었다면, 지금은 얼마나 빠르고 효율적으로 개발하고 검증할 수 있는가가 핵심이다. *</em></p>
<p>따라서 프레젠테이션은 Okteto가 다음과 같은 가치를 제공한다고 주장한다. </p>
<ul>
<li><p><span style="color: indianred"><strong>Inner Loop 단축:</strong></span> 코드 수정부터 확인까지의 시간을 획기적으로 줄여준다.</p>
</li>
<li><p><span style="color: indianred"><strong>Prod-like Dev:</strong></span>  로컬(Docker Desktop 등)이 아닌 실제 쿠버네티스 클러스터 위에서 개발하므로, 배포 시 발생할 수 있는 환경 차이 문제를 사전에 방지한다.</p>
</li>
<li><p><span style="color: indianred"><strong>오픈 소스:</strong></span>  Okteto CLI는 오픈 소스이며 활발한 커뮤니티 지원을 받고 있다.</p>
</li>
</ul>
<p><span style="color: indianred"></span>
<span style="color: SlateBlue"></span></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[90DaysOfDevOps (Day 80)]]></title>
            <link>https://velog.io/@taekyu_/90DaysOfDevOps-Day-80-eo2jwsv9</link>
            <guid>https://velog.io/@taekyu_/90DaysOfDevOps-Day-80-eo2jwsv9</guid>
            <pubDate>Sat, 24 Jan 2026 11:31:41 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>해당 스터디는 90DaysOfDevOps
<a href="https://github.com/MichaelCade/90DaysOfDevOps">https://github.com/MichaelCade/90DaysOfDevOps</a>
를 기반으로 진행한 내용입니다.</strong></p>
</blockquote>
<p>** Day 80 - Unlocking K8s Troubleshooting Best Practices with Botkube **</p>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine1-쿠버네티스-트러블슈팅span"><span style='background-color: MediumAquamarine'>1. 쿠버네티스 트러블슈팅</span></h2>
<hr>

<p>*<em>쿠버네티스 생태계는 거대하고 복잡하다. *</em></p>
<p>네트워킹, 컨테이너, 배포 전략 등 알아야 할 지식의 양이 방대하여 진입 장벽이 높을 뿐만 아니라, 수많은 CNCF 도구들과 함께 사용되기 때문에 이들을 통합 관리하는 것은 엔지니어에게 큰 부담이다.</p>
<p><span style="color: indianred"><strong>특히 팀이 지리적으로 분산된 하이브리드 근무 환경에서 장애가 발생했을 때, Slack이나 Teams 같은 메신저로 파편화된 정보를 공유하며 문제를 해결하는 것은 Context Switching 비용을 발생시키고 대응 속도를 늦춘다.</strong></span></p>
<hr>
<p><strong>쿠버네티스 트러블슈팅은 공식적으로 클러스터 내의 문제를 식별하고 해결하는 과정이다.</strong></p>
<p>하지만 이를 좀 더 실천적인 관점에서 정의하자면 <span style="color: indianred"><strong>&quot;모니터링 + 행동 또는 반응의 결합&quot;</strong></span>이라 할 수 있다.</p>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine2-기존-트러블슈팅의-문제점span"><span style='background-color: MediumAquamarine'>2. 기존 트러블슈팅의 문제점</span></h2>
<hr>

<p>가장 흔한 에러 중 하나인 OOMKilled(Out Of Memory) 상황을 가정해보자. 전통적인 해결 방식은 다음 5단계를 거친다.</p>
<ol>
<li><p><span style="color: SlateBlue"><strong>종료된 Pod 식별</strong></span></p>
</li>
<li><p><span style="color: SlateBlue"><strong>메모리 사용량 확인</strong></span></p>
</li>
<li><p><span style="color: SlateBlue"><strong>로그 내 에러 확인</strong></span></p>
</li>
<li><p><span style="color: SlateBlue"><strong>이미지 업데이트</strong></span></p>
</li>
<li><p><span style="color: SlateBlue"><strong>메모리 Limit 증설</strong></span></p>
</li>
</ol>
<p>이 5단계는 간단해 보이지만, 20개 이상의 클러스터를 운영하거나 업무 시간 외에 발생할 경우, 해결까지 몇 분에서 며칠이 소요될 수 있다.
<br></p>
<p>또한, 일반적인 조직에서는 <span style="color: indianred"><strong><code>[개발자 장애 발견 → 티켓 생성 → DevOps 팀 알림 → DevOps 환경 진단 → SRE 팀 호출 → 트러블슈팅 → 상태 업데이트 → 팀 전파]</code></strong></span>라는 복잡한 과정을 거친다. 이 과정에서 너무 많은 사람과 단계가 개입된다.</p>
<ul>
<li><p><span style="color: indianred"><strong>DevOps 팀:</strong></span> 인력 부족과 업무 과다에 시달리며, 개발과 운영 사이에서 끊임없는 문맥 전환으로 인한 피로감을 느낀다.</p>
</li>
<li><p><span style="color: indianred"><strong>개발자:</strong></span> 앱의 상태만 확인하고 싶은데, 쿠버네티스 심층 지식까지 강요받는 부담을 느낀다.</p>
</li>
<li><p><span style="color: indianred"><strong>운영 팀:</strong></span> 보안 리스크와 비용 효율성 때문에 시스템 신뢰성 유지가 최우선 과제라 압박감이 크다.</p>
</li>
</ul>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine3-쿠버네티스-트러블슈팅-모범-사례-5가지span"><span style='background-color: MediumAquamarine'>3. 쿠버네티스 트러블슈팅 모범 사례 5가지</span></h2>
<hr>

<p>이러한 문제를 해결하기 위한 5가지 핵심 전략은 다음과 같다.</p>
<ul>
<li><p><span style="color: indianred"><strong>모니터링과 관측성(Observability) 중앙화:</strong></span> 흩어진 정보를 한곳으로 모은다.</p>
</li>
<li><p><span style="color: indianred"><strong>인시던트 대응과 협업 강화:</strong></span> 팀 간 소통을 효율화한다.</p>
</li>
<li><p><span style="color: indianred"><strong>피드백 루프 구축:</strong></span> 과거 데이터를 통해 학습하고 개선한다.</p>
</li>
<li><p><span style="color: indianred"><strong>Command Execution 간소화:</strong></span> 복잡한 터미널 작업을 줄인다.</p>
</li>
<li><p><span style="color: indianred"><strong>관측성 및 전달 프로세스 자동화:</strong></span> 수동 작업을 최소화한다.</p>
</li>
</ul>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine4-솔루션-botkube를-활용한-chatops-구현span"><span style='background-color: MediumAquamarine'>4. 솔루션: Botkube를 활용한 ChatOps 구현</span></h2>
<hr>

<p><strong>Botkube는 협업 중심의 쿠버네티스 트러블슈팅 도구로, 메신저(Slack, Teams, Discord, Mattermost)와 쿠버네티스 클러스터 사이를 연결하는 양방향 에이전트다.</strong> </p>
<p><span style="color: indianred"><strong>단순 알림 수신을 넘어, 메신저에서 직접 클러스터를 제어하는 것이 특징이다.</strong></span>
<img src="https://velog.velcdn.com/images/taekyu_/post/6c0e6031-e85f-4fb6-a181-d1607187b519/image.png" width="70%" height="n%"></p>
<h3 id="span-stylecolor-slateblue4-1-관측성-강화-observabilityspan"><span style="color: SlateBlue">4-1. 관측성 강화 (Observability)</span></h3>
<p><strong>모니터링은 단순한 데이터 수신이 아니라 문맥(Context)을 파악하는 것이다.</strong></p>
<ul>
<li><p><span style="color: indianred"><strong>Watchdog 역할:</strong></span> 클러스터 변경 사항을 실시간으로 감지하여 알린다.</p>
</li>
<li><p><span style="color: indianred"><strong>채널별 격리:</strong></span> 개발팀은 개발 관련 알림만, 플랫폼 팀은 인프라 알림만 받도록 채널을 분리하여 피로도를 줄인다.</p>
</li>
<li><p><span style="color: indianred"><strong>직접 해결:</strong></span> 알림을 받고 터미널을 켜는 것이 아니라, 슬랙에서 버튼을 누르거나 명령어를 입력해 즉시 문제를 해결한다. 이는 문맥 전환 비용을 획기적으로 줄여준다.</p>
<img src="https://velog.velcdn.com/images/taekyu_/post/a42a5817-1e5d-4652-acd1-7205952ccb93/image.png" width="70%" height="n%">

</li>
</ul>
<br>


<h3 id="span-stylecolor-slateblue4-2-협업과-피드백-루프-collaboration--feedback-loopspan"><span style="color: SlateBlue">4-2. 협업과 피드백 루프 (Collaboration &amp; Feedback Loop)</span></h3>
<ul>
<li><p><span style="color: indianred"><strong>정보 공유:</strong></span> 공유된 채널에서 트러블슈팅이 이루어지므로, 별도의 보고 절차 없이 팀 전체가 상황을 파악할 수 있다.</p>
</li>
<li><p><span style="color: indianred"><strong>Audit Logs:</strong></span> 누가 어떤 명령어를 실행했는지 기록된다. 예를 들어 주니어 엔지니어가 반복적인 실수를 한다면, 로그를 통해 근본 원인을 파악하고 교육하여 팀 역량을 높일 수 있다.</p>
</li>
<li><p><span style="color: indianred"><strong>반응형 → 주도형:</strong></span> 과거 인시던트 이력을 바탕으로 장애의 전조 증상을 파악하고 사전 대응이 가능해진다.</p>
</li>
</ul>
<h3 id="span-stylecolor-slateblue4-3-개발자-셀프-서비스와-명령어-실행-간소화span"><span style="color: SlateBlue">4-3. 개발자 셀프 서비스와 명령어 실행 간소화</span></h3>
<ul>
<li><p><span style="color: indianred"><strong>비전문가를 위한 접근성:</strong></span> 쿠버네티스 전문가가 아니더라도, Botkube가 제공하는 드래그 앤 드롭 UI나 간소화된 명령어를 통해 필요한 조치를 취할 수 있다.</p>
</li>
<li><p><span style="color: indianred"><strong>명령어 실행 속도 향상:</strong></span> 복잡한 kubectl 명령어를 일일이 기억할 필요 없이, 채팅창에서 빠르게 실행 가능하다.</p>
</li>
</ul>
<h3 id="span-stylecolor-slateblue4-4-자동화-automationspan"><span style="color: SlateBlue">4-4. 자동화 (Automation)</span></h3>
<p><strong>가장 강력한 기능은 트러블슈팅 단계의 자동화다. 앞서 언급한 OOMKilled 5단계를 Botkube는 2단계로 단축시킨다.</strong></p>
<ul>
<li><p><span style="color: indianred"><strong>기존 5단계:</strong></span> 식별 → 확인 → 로그 확인 → 업데이트 → 메모리 증설</p>
</li>
<li><p><span style="color: indianred"><strong>Botkube 자동화:</strong></span></p>
<ul>
<li><p>Botkube가 자동으로 파드를 식별하고, 로그와 메모리 사용량을 분석하여 에러 원인을 채팅창에 띄워준다 (1~3단계 자동 수행).</p>
</li>
<li><p><strong>엔지니어는 제공된 정보를 바탕으로 이미지 업데이트 및 메모리 증설(4~5단계)만 수행하면 된다.</strong></p>
</li>
</ul>
</li>
</ul>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine5-도입-효과-및-실제-사례span"><span style='background-color: MediumAquamarine'>5. 도입 효과 및 실제 사례</span></h2>
<hr>


<h3 id="span-stylecolor-slateblue5-1-정량적-기대-효과span"><span style="color: SlateBlue">5-1. 정량적 기대 효과</span></h3>
<ul>
<li><p><span style="color: indianred"><strong>MTTR(평균 복구 시간) 단축:</strong></span> 커뮤니케이션 지연을 제거하여 빠른 복구 가능.</p>
</li>
<li><p><span style="color: indianred"><strong>운영 효율성 증대:</strong></span> 단일 플랫폼에서 정보 확인 및 조치 가능.</p>
</li>
<li><p><span style="color: indianred"><strong>팀 번아웃 감소:</strong></span> 불필요한 문맥 전환과 전문가에 대한 과도한 의존 제거.</p>
</li>
<li><p><span style="color: indianred"><strong>장애 감소:</strong></span> 사전 대응을 통해 작은 이슈가 대형 장애로 번지는 것을 방지.</p>
<br>

</li>
</ul>
<h3 id="span-stylecolor-slateblue5-2-고객-사례-해운-회사span"><span style="color: SlateBlue">5-2. 고객 사례 (해운 회사)</span></h3>
<p>운영(Prod)과 스테이징(Staging) 클러스터를 운영하는 한 고객사는 Botkube의 RBAC(역할 기반 접근 제어) 기능을 활용했다. </p>
<p><strong>슬랙 채널별로 권한을 매핑하여, 특정 채널에서는 조회만 가능하고 비공개 채널에서는 명령 실행이 가능하도록 설정함으로써 보안과 신뢰성을 동시에 확보했다.</strong></p>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine6-정리span"><span style='background-color: MediumAquamarine'>6. 정리</span></h2>
<hr>

<p><strong>쿠버네티스 트러블슈팅에서 가장 중요한 것은 반응적(Reactive) 태도를 버리고 전략적(Strategic)으로 접근하는 것이다.</strong></p>
<p><span style="color: indianred"><strong>팀의 리소스와 히스토리를 바탕으로 트러블슈팅 과정을 중앙화하고 자동화해야 한다.</strong></span></p>
<p>Botkube와 같은 도구는 복잡한 하이브리드 환경에서 팀의 협업 능력을 극대화하고, 더욱 회복탄력성있는 조직을 만드는 데 핵심적인 역할을 한다.</p>
<p><span style="color: indianred"></span>
<span style="color: SlateBlue"></span></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[90DaysOfDevOps (Day 79)]]></title>
            <link>https://velog.io/@taekyu_/90DaysOfDevOps-Day-79-gvg8o01o</link>
            <guid>https://velog.io/@taekyu_/90DaysOfDevOps-Day-79-gvg8o01o</guid>
            <pubDate>Sat, 24 Jan 2026 09:18:40 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>해당 스터디는 90DaysOfDevOps
<a href="https://github.com/MichaelCade/90DaysOfDevOps">https://github.com/MichaelCade/90DaysOfDevOps</a>
를 기반으로 진행한 내용입니다.</strong></p>
</blockquote>
<p>** Day 79 - DevEdOps **</p>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine1-devedops란span"><span style='background-color: MediumAquamarine'>1. DevEdOps란?</span></h2>
<hr>

<p><strong>DevEdOps는 Development(개발), Education(교육), Operations(운영)의 합성어로, 데브옵스의 세 가지 방법을 교육 및 학습 과정에 적용하여, 자동화되고 피드백이 빠른 학습 환경을 구축하는 것으로 정의할 수 있다.</strong></p>
<p><span style="color: indianred"><strong>기존의 정적인 학습에서 벗어나, 학습자가 실제 환경과 유사한 샌드박스에서 반복적인 의도적 연습을 수행하고, 시스템으로부터 즉각적인 피드백을 받으며 기술을 체화하는 방법론이다.</strong></span></p>
<hr>
<p><strong>기술을 배운다는 것은 무엇인가?</strong></p>
<p>Adam Leskis는 인지 심리학을 바탕으로 학습의 본질이 <span style="color: indianred"><strong>반복적인 의도적 연습</strong></span>에 있다고 설명한다.</p>
<p>숙련된 체스 선수가 말의 위치를 개별적으로 외우는 것이 아니라 특정 패턴을 하나의 덩어리(Chunk)로 인식하여 장기 기억에 저장하듯, <strong>개발자 또한 복잡한 시스템을 다루기 위해서는 지식의 청킹(Chunking) 과정이 필수적이다.</strong></p>
<p>DevEdOps는 학습자가 안전한 환경에서 반복 연습을 통해 이러한 패턴을 뇌에 각인시킬 수 있도록 돕는 환경을 제공한다.</p>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine2-devops의-세가지-방법을-통한-학습-설계span"><span style='background-color: MediumAquamarine'>2. DevOps의 세가지 방법을 통한 학습 설계</span></h2>
<hr>

<p><strong>DevEdOps는 데브옵스의 The Three Ways를 학습 프로세스에 그대로 이식한다.</strong></p>
<ul>
<li><p><span style="color: indianred"><strong>첫 번째 방법 (흐름):</strong></span> 학습 목표를 아주 작은 단위(Batch Size)로 쪼개고, 학습자가 실습 환경에 접속하자마자 즉시 연습을 시작할 수 있도록 Lead Time을 0으로 단축한다.</p>
</li>
<li><p><span style="color: indianred"><strong>두 번째 방법 (피드백):</strong></span> 학습자의 행동(코드 작성, 설정 변경 등)에 대해 시스템이 자동화된 검증을 수행하여, 맞았는지 틀렸는지 즉각적인 피드백을 제공한다.</p>
</li>
<li><p><span style="color: indianred"><strong>세 번째 방법 (지속적 학습):</strong></span> 최고의 학습은 가르치는 것이다. 학습자가 직접 가르치기 위한 도구를 개발하고 공유함으로써 로컬의 지식을 전역으로 확장한다.</p>
</li>
</ul>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine3-devedops의-미래-자동-생성되는-샌드박스-환경span"><span style='background-color: MediumAquamarine'>3. DevEdOps의 미래: 자동 생성되는 샌드박스 환경</span></h2>
<hr>

<p><strong>실전에서의 DevEdOps는 &#39;MongoDB 복제 세트 업그레이드&#39;와 같이 운영 환경에서 수행하기 위험한 작업을, 로컬의 격리된 Sandbox 환경에서 안전하게 연습하는 형태로 구현된다.</strong></p>
<p><span style="color: indianred"><strong>실패해도 리스크가 없기 때문에 엔지니어는 두려움 없이 실험할 수 있다.</strong></span></p>
<p>더 나아가 DevEdOps의 미래는 자동 생성 학습 환경에 있다. </p>
<blockquote>
<p><strong>엔지니어가 배우고 싶은 기술 스택을 입력하면 LLM 에이전트가 맞춤형 실습 환경을 즉시 배포하고, 카오스 엔지니어링을 통해 무작위 장애 시나리오를 주입하여 복구 훈련을 돕는 형태로 진화할 것이다.</strong></p>
</blockquote>
<p><span style="color: indianred"></span>
<span style="color: SlateBlue"></span></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[90DaysOfDevOps (Day 78)]]></title>
            <link>https://velog.io/@taekyu_/90DaysOfDevOps-Day-78</link>
            <guid>https://velog.io/@taekyu_/90DaysOfDevOps-Day-78</guid>
            <pubDate>Sat, 24 Jan 2026 06:40:55 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>해당 스터디는 90DaysOfDevOps
<a href="https://github.com/MichaelCade/90DaysOfDevOps">https://github.com/MichaelCade/90DaysOfDevOps</a>
를 기반으로 진행한 내용입니다.</strong></p>
</blockquote>
<p>** Day 78 - Scaling Terraform Deployments with GitHub Actions: Essential Configurations **</p>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine1-안정적인-협업을-위한-저장소-설정-및-보안-전략span"><span style='background-color: MediumAquamarine'>1. 안정적인 협업을 위한 저장소 설정 및 보안 전략</span></h2>
<hr>

<p>*<em>성공적인 인프라 관리(IaC)의 시작은 코드를 담는 그릇인 Repository의 정책을 올바르게 수립하는 것에서부터 출발한다. *</em></p>
<p>이는 단순한 권장 사항이 아니라, 사고를 예방하고 협업의 품질을 높이는 강제적 제어 장치이다.</p>
<h3 id="span-stylecolor-slateblue1-1-브랜치-정책과-보호span"><span style="color: SlateBlue">1-1. 브랜치 정책과 보호</span></h3>
<p><strong>운영 환경의 안정성을 위해 main 브랜치에 대한 직접적인 커밋을 차단하는 브랜치 보호 규칙 설정은 필수적이다.</strong></p>
<ul>
<li><p><span style="color: indianred"><strong>사고 방지:</strong></span> 개발자가 실수로 운영 코드를 변경하거나 삭제하는 것을 시스템 레벨에서 차단한다.</p>
</li>
<li><p><span style="color: indianred"><strong>제어된 Workflows:</strong></span> 모든 변경 사항은 검증된 절차를 거쳐야만 병합될 수 있도록 강제하여, 인프라의 무결성을 유지한다.</p>
<br>

</li>
</ul>
<h3 id="span-stylecolor-slateblue1-2-풀-리퀘스트pull-request-중심의-개발-수명주기span"><span style="color: SlateBlue">1-2. 풀 리퀘스트(Pull Request) 중심의 개발 수명주기</span></h3>
<p><strong>코드 병합 전에 반드시 Pull Request를 생성하도록 요구하는 것은 DevOps 문화의 핵심이다.</strong></p>
<ul>
<li><p><span style="color: indianred"><strong>코드 리뷰의 제도화:</strong></span> PR은 팀원들이 변경 사항을 검토하고 피드백을 주고받는 공식적인 공간이 된다.</p>
</li>
<li><p><span style="color: indianred"><strong>자동화된 검증:</strong></span> </p>
<ul>
<li><p>PR이 생성되는 즉시 CI 파이프라인을 트리거하여, 코드가 병합되기 전에 문법 오류나 잠재적 문제를 사전에 탐지할 수 있다. </p>
</li>
<li><p>이는 배포 후 발생할 수 있는 회귀 오류를 최소화하는 가장 확실한 방법이다.</p>
<br>

</li>
</ul>
</li>
</ul>
<h3 id="span-stylecolor-slateblue1-3-환경별-secrets-및-변수-관리span"><span style="color: SlateBlue">1-3. 환경별 Secrets 및 변수 관리</span></h3>
<p><strong>보안과 유연성을 동시에 확보하기 위해 GitHub의 <code>Environment Secrets</code> 기능을 적극 활용해야 한다.</strong></p>
<ul>
<li><p><span style="color: indianred"><strong>민감 정보 격리:</strong></span> </p>
<ul>
<li><p>Client ID, Secret, Subscription ID와 같은 민감한 정보는 절대 평문으로 코드에 포함되어서는 안 된다. </p>
</li>
<li><p><strong>이를 GitHub Secrets에 암호화하여 저장하고 파이프라인 실행 시에만 주입받아 사용한다.</strong></p>
</li>
</ul>
</li>
<li><p><span style="color: indianred"><strong>환경별 분리 전략:</strong></span> </p>
<ul>
<li><p>개발과 운영 환경은 서로 다른 자격 증명(<code>Credential</code>)을 사용해야 한다. </p>
</li>
<li><p>GitHub Environments 기능을 통해 동일한 변수명을 사용하더라도, 배포되는 환경 컨텍스트에 따라 자동으로 다른 비밀 키 값을 매핑함으로써 보안 사고를 예방한다.</p>
</li>
</ul>
</li>
</ul>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine2-테라폼-저장소-구조화span"><span style='background-color: MediumAquamarine'>2. 테라폼 저장소 구조화</span></h2>
<hr>

<p><strong>테라폼 코드베이스의 유지보수성과 확장성은 폴더 구조를 어떻게 설계하느냐에 달려 있다.</strong></p>
<p>단일 파일 관리가 아닌, 기능과 역할에 따른 명확한 디렉터리 분리 전략이 필요하다.</p>
<h3 id="span-stylecolor-slateblue2-1-논리적-폴더-구조-설계span"><span style="color: SlateBlue">2-1. 논리적 폴더 구조 설계</span></h3>
<p>프레젠테이션에서는 다음과 같은 계층적 구조를 제안한다.</p>
<ul>
<li><p><span style="color: indianred"><strong><code>.github/workflows</code></strong></span>: CI/CD 파이프라인 정의 파일(.yml)과 재사용 가능한 Template workflows가 위치</p>
</li>
<li><p><span style="color: indianred"><strong><code>environments</code></strong></span>: 환경별 설정 값을 관리한다.</p>
<ul>
<li>development, production 폴더로 나누고 각 폴더 내에 terraform.tfvars 파일을 두어, 환경마다 달라지는 값(예: IP 대역, 리소스 이름 접두사 등)을 정의</li>
</ul>
</li>
<li><p><span style="color: indianred"><strong><code>modules</code></strong></span>: 재사용 가능한 테라폼 모듈을 관리한다. </p>
<ul>
<li>조직의 규모에 따라 별도 리포지토리로 분리할 수도 있지만, 관리의 편의성을 위해 단일 리포지토리 내에 구성할 수도 있다. (예: Private DNS Zone 모듈 등)</li>
</ul>
</li>
<li><p><span style="color: indianred"><strong><code>platform</code></strong></span>: 인프라를 구성하는 실제 리소스들을 기능 단위로 쪼개어 관리하는 디렉토리</p>
</li>
</ul>
<pre><code class="language-bash">.
├── .github
│   └── workflows
│       ├── deploy.yml          # 메인 워크플로 (트리거 정의)
│       └── templates           # 재사용 가능한 템플릿 (CI, Apply 로직 등)
├── environments
│   ├── dev
│   │   └── terraform.tfvars    # 개발 환경 전용 변수 (IP 대역, 이름 등)
│   └── prod
│       └── terraform.tfvars    # 운영 환경 전용 변수
├── modules                     # 재사용 가능한 테라폼 모듈 (예: DNS, VM)
└── platform                    # 실제 인프라 구성 요소 (기능 단위 분리)
    ├── core                    # 리소스 그룹 등 기초 자원
    ├── network                 # VNet, Subnet 등
    └── logging                 # 모니터링 및 로깅 자원</code></pre>
<br>


<h3 id="span-stylecolor-slateblue2-2-플랫폼-구성-요소-분리-전략span"><span style="color: SlateBlue">2-2. 플랫폼 구성 요소 분리 전략</span></h3>
<p><strong>거대한 하나의 main.tf 파일은 관리가 불가능하다. 인프라를 플랫폼 구성 요소 단위로 나누어야 한다.</strong></p>
<ul>
<li><p><span style="color: indianred"><strong>구성 요소 예시:</strong></span></p>
<ul>
<li><p><code>Core</code>: 리소스 그룹 등 가장 기초가 되는 자원</p>
</li>
<li><p><code>Network</code>: VNet, Subnet 등 네트워킹 자원</p>
</li>
<li><p><code>Logging</code>: Log Analytics Workspace 등 모니터링 자원</p>
</li>
</ul>
</li>
<li><p><span style="color: indianred"><strong>의존성 관리:</strong></span></p>
<ul>
<li><p>이러한 분리는 인프라 배포의 순서를 명확히 한다. </p>
</li>
<li><p>예를 들어, VM을 배포하기 전에 Network가 존재해야 하고, 네트워크 전에 리소스 그룹인 Core가 있어야 한다. 폴더를 분리함으로써 &#39;왼쪽에서 오른쪽으로&#39; 흐르는 배포 파이프라인을 설계할 수 있다.</p>
</li>
</ul>
</li>
</ul>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine3-github-actions-구성span"><span style='background-color: MediumAquamarine'>3. GitHub Actions 구성</span></h2>
<hr>

<p><strong>단순한 스크립트 실행을 넘어, GitHub Actions의 고급 기능을 활용하여 중복을 줄이고 배포 속도를 높이는 전략이다.</strong></p>
<h3 id="span-stylecolor-slateblue3-1-템플릿templating을-통한-표준화span"><span style="color: SlateBlue">3-1. 템플릿(Templating)을 통한 표준화</span></h3>
<p><strong>DRY(Don&#39;t Repeat Yourself) 원칙을 CI/CD 파이프라인에도 적용해야 한다.</strong></p>
<ul>
<li><p><span style="color: indianred"><strong>재사용 가능한 워크플로:</strong></span> <code>terraform init</code>, <code>plan</code>, <code>apply</code>와 같은 공통적인 작업 절차를 별도의 YAML 템플릿 파일로 정의한다.</p>
</li>
<li><p><span style="color: indianred"><strong>효과:</strong></span> </p>
<ul>
<li><p>메인 워크플로에서는 이 템플릿을 호출하고 필요한 Input만 전달하면 된다. </p>
</li>
<li><p>이를 통해 모든 프로젝트와 환경에서 일관된 배포 프로세스를 보장하고, 로직 수정 시 템플릿 파일 하나만 수정하면 되므로 유지보수가 용이해진다.</p>
</li>
</ul>
<pre><code class="language-yaml">#.github/workflows/templates/terraform-template.yml
name: &quot;Reusable Terraform Workflow&quot;

on:
  workflow_call: # 다른 워크플로에서 호출 가능하도록 설정
    inputs:
      environment: { required: true, type: string }
      path: { required: true, type: string }
    secrets:
      AZURE_CREDENTIALS: { required: true }

jobs:
  terraform:
    runs-on: ubuntu-latest
    steps:
      - uses: hashicorp/setup-terraform@v2

      # 1. 초기화 (공통 로직)
      - run: terraform init
        working-directory: ${{ inputs.path }}

      # 2. 적용 (환경 변수 동적 할당)
      - run: terraform apply -auto-approve -var-file=../../environments/${{ inputs.environment }}.tfvars
        working-directory: ${{ inputs.path }}</code></pre>
<br>

</li>
</ul>
<h3 id="span-stylecolor-slateblue3-2-매트릭스-전략을-이용한-병렬-배포span"><span style="color: SlateBlue">3-2. 매트릭스 전략을 이용한 병렬 배포</span></h3>
<p><strong>대규모 배포 시 Matrix Strategy를 도입한다.</strong></p>
<ul>
<li><p><span style="color: indianred"><strong>문제 상황:</strong></span> 개발/운영 2개의 환경에 Core, Network, Logging 3개의 구성 요소를 배포하려면 총 6번의 배포 스크립트를 작성해야 하는 비효율이 발생한다.</p>
</li>
<li><p><span style="color: indianred"><strong>해결책:</strong></span> GitHub Actions의 Matrix 기능을 사용하여 환경 목록(<code>[dev, prod]</code>)과 구성 요소 목록(<code>[core, network, logging]</code>)을 정의한다.</p>
</li>
<li><p><span style="color: indianred"><strong>동작 방식:</strong></span> </p>
<ul>
<li><p>파이프라인이 실행되면 정의된 조합(2 x 3 = 6개)에 따라 6개의 Job이 자동으로 생성되어 병렬로 실행된다. </p>
</li>
<li><p>코드는 단 한 번만 작성하지만, 실행은 N번 이루어지므로 작성량이 획기적으로 줄어들고 배포 속도는 빨라진다.</p>
</li>
</ul>
</li>
<li><p><span style="color: indianred"><strong>구현 코드 예시:</strong></span></p>
<ul>
<li>아래와 같이 strategy 블록 내에 matrix를 정의하면, 단 한 번의 코드 작성으로 다중 환경 및 다중 컴포넌트 배포를 처리할 수 있다.<pre><code class="language-yaml">jobs:
terraform-deploy:
  strategy:
    matrix:
      environment: [dev, prod]           # 배포할 환경 목록
      component: [core, network, logging] # 배포할 플랫폼 구성 요소 목록
  steps:
    - name: Deploy ${{ matrix.component }} to ${{ matrix.environment }}
      # working-directory를 동적으로 변경하여 해당 컴포넌트 폴더에서 실행
      working-directory: platform/${{ matrix.component }}
      # 해당 환경에 맞는 tfvars 파일을 동적으로 주입
      run: |
        terraform init
        terraform apply -var-file=&quot;../../environments/${{ matrix.environment }}/terraform.tfvars&quot;</code></pre>
</li>
</ul>
</li>
</ul>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine4-실전-데모-워크플로-분석-및-운영-최적화-span"><span style='background-color: MediumAquamarine'>4. 실전 데모 워크플로 분석 및 운영 최적화 </span></h2>
<hr>

<p><strong>실제 데모 시연을 통해 확인된 파이프라인의 구체적인 동작 방식과, 지속적인 개선을 위한 운영 도구 활용법이다.</strong></p>
<h3 id="span-stylecolor-slateblue4-1-ci-파이프라인-pr-단계span"><span style="color: SlateBlue">4-1. CI 파이프라인 (PR 단계)</span></h3>
<p><strong>PR이 생성되면 Terraform CI 작업이 실행된다.</strong></p>
<ul>
<li><p><span style="color: indianred"><strong>자동 포맷팅:</strong></span> </p>
<ul>
<li><p>개발자가 <code>terraform fmt</code>를 수행하지 않고 코드를 올렸을 경우(들여쓰기 오류 등), CI 파이프라인이 이를 감지하여 자동으로 포맷팅을 수정하고 해당 브랜치에 커밋한다.</p>
</li>
<li><p>사소한 스타일 문제로 리뷰 시간을 낭비하는 것을 방지한다.</p>
</li>
</ul>
</li>
<li><p><span style="color: indianred"><strong>피드백 루프 자동화:</strong></span> </p>
<ul>
<li><p><code>terraform plan</code>의 실행 결과가 GitHub Actions 로그에만 남는 것이 아니라, PR의 코멘트로 자동 등록된다. </p>
</li>
<li><p>리뷰어는 파이프라인 로그를 찾아 헤맬 필요 없이, PR 페이지에서 즉시 변경 예정 사항인Plan을 확인하고 승인 여부를 결정할 수 있다.</p>
</li>
</ul>
<pre><code class="language-yaml">name: &quot;Terraform CI&quot;

on:
  pull_request:
    branches: [ main ]

permissions:
  contents: write      # 포맷팅 수정 후 커밋을 위해 쓰기 권한 필요
  pull-requests: write # PR 코멘트 작성을 위해 쓰기 권한 필요

jobs:
  terraform-ci:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Code
        uses: actions/checkout@v3
        with:
          ref: ${{ github.head_ref }}

      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v2

      # 1. 자동 포맷팅 및 커밋 (Auto-Formatting)
      - name: Terraform Format
        id: fmt
        run: terraform fmt -recursive

      - name: Commit Formatting Changes
        if: steps.fmt.outputs.exitcode != 0 # 변경사항이 있을 경우에만 실행
        uses: stefanzweifel/git-auto-commit-action@v4
        with:
          commit_message: &quot;style: Apply terraform fmt changes&quot;

      # 2. Terraform Init &amp; Validate
      - name: Terraform Init
        run: terraform init

      - name: Terraform Validate
        run: terraform validate

      # 3. Plan 실행 및 결과 저장
      - name: Terraform Plan
        id: plan
        run: terraform plan -no-color
        continue-on-error: true # Plan 실패 시에도 코멘트는 남기도록 설정

      # 4. PR에 코멘트로 Plan 결과 등록 (Feedback Loop)
      - name: Update PR with Plan
        uses: actions/github-script@v6
        if: github.event_name == &#39;pull_request&#39;
        env:
          PLAN: &quot;terraform\n${{ steps.plan.outputs.stdout }}&quot;
        with:
          script: |
            const output = `#### Terraform Format and Style 🖌\`${{ steps.fmt.outcome }}\`
            #### Terraform Initialization ⚙️\`${{ steps.init.outcome }}\`
            #### Terraform Plan 📖\`${{ steps.plan.outcome }}\`

            &lt;details&gt;&lt;summary&gt;Show Plan&lt;/summary&gt;

            \`\`\`\n
           ${process.env.PLAN}
            \`\`\`

            &lt;/details&gt;`;

            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: output
            })</code></pre>
<br>

</li>
</ul>
<h3 id="span-stylecolor-slateblue4-2-cd-파이프라인-merge-및-배포-단계span"><span style="color: SlateBlue">4-2. CD 파이프라인 (Merge 및 배포 단계)</span></h3>
<p><strong>PR이 승인되어 main 브랜치에 병합되면 실제 배포 파이프라인이 트리거 된다.</strong></p>
<ul>
<li><p><span style="color: indianred"><strong>조건부 실행:</strong></span> if 문을 사용하여 main 브랜치일 경우에만 <code>terraform apply</code>가 실행되도록 제어한다.</p>
</li>
<li><p><span style="color: indianred"><strong>매트릭스 기반 배포:</strong></span> 앞서 설계한 매트릭스 전략에 따라 개발 및 운영 환경의 각 구성 요소들이 의존성에 맞춰 배포된다. 데모에서는 Azure Tag가 업데이트되는 과정을 통해 실시간 반영을 확인했다.</p>
<pre><code class="language-yaml">name: &quot;Terraform CD (Deploy)&quot;

on:
  push:
    branches: [ main ]

jobs:
  deploy:
    name: Deploy ${{ matrix.component }} to ${{ matrix.environment }}
    runs-on: ubuntu-latest

    # Matrix 전략 정의: 환경(2개) * 컴포넌트(3개) = 총 6개의 병렬 Job 실행
    strategy:
      matrix:
        environment: [dev, prod]
        component: [core, network, logging]
      fail-fast: false # 하나의 Job이 실패해도 나머지는 계속 진행

    # 환경별 Secret 분리를 위해 GitHub Environment 기능 사용
    environment: ${{ matrix.environment }}

    steps:
      - name: Checkout Code
        uses: actions/checkout@v3

      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v2

      # Azure 로그인 (OIDC 사용 시)
      - name: Azure Login
        uses: azure/login@v1
        with:
          client-id: ${{ secrets.AZURE_CLIENT_ID }}
          tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

      # Matrix 변수를 활용한 동적 경로 설정 및 배포
      - name: Terraform Init &amp; Apply
        # 실제 테라폼 코드가 있는 폴더로 이동 (예: platform/core)
        working-directory: platform/${{ matrix.component }}
        run: |
          terraform init

          # 환경별 tfvars 파일을 참조하여 Apply 실행
          # (예: environments/dev/terraform.tfvars)
          terraform apply -auto-approve \
            -var-file=&quot;../../environments/${{ matrix.environment }}/terraform.tfvars&quot;</code></pre>
</li>
</ul>
<br>

<h3 id="span-stylecolor-slateblue4-3-지속적인-관리-도구-renovate--dependabotspan"><span style="color: SlateBlue">4-3. 지속적인 관리 도구 (Renovate &amp; Dependabot)</span></h3>
<p><strong>인프라 코드는 한 번 작성하고 끝나는 것이 아니다. 지속적인 최신 상태 유지가 필요하다.</strong></p>
<ul>
<li><p><span style="color: indianred"><strong>Renovate/Dependabot 도입:</strong></span> Terraform 모듈 버전, Provider 버전, GitHub Actions 템플릿 버전 등을 모니터링하는 도구를 설정한다.</p>
</li>
<li><p><span style="color: indianred"><strong>종속성 대시보드:</strong></span> 업데이트가 필요한 항목을 대시보드 형태로 시각화해 주며, 새 버전이 나올 경우 자동으로 PR을 생성해 준다. 이를 통해 엔지니어는 수동으로 버전을 확인하는 수고를 덜고, 보안 취약점이 패치된 최신 버전을 손쉽게 유지할 수 있다.</p>
</li>
</ul>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine5-정리-span"><span style='background-color: MediumAquamarine'>5. 정리 </span></h2>
<hr>

<p><span style="color: indianred"><strong>대규모 테라폼 운영을 위해서는 환경과 플랫폼 구성 요소를 분리한 모듈식 저장소 구조와 Matrix Strategy를 결합하여 코드 중복 없이 다중 환경 병렬 배포를 구현해야 한다.</strong></span></p>
<p>이 과정에서 브랜치 보호 규칙과 PR 기반의 자동화된 CI 검증을 통해 인프라의 무결성을 확보하고, GitHub Environment Secrets를 활용하여 보안성을 강화한다. </p>
<p>최종적으로 Renovate와 같은 종속성 관리 도구를 통합함으로써, 확장 가능하고 유지보수가 용이한 IaC 아키텍처를 완성할 수 있다.</p>
<p><span style="color: indianred"></span>
<span style="color: SlateBlue"></span></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[90DaysOfDevOps (Day 77)]]></title>
            <link>https://velog.io/@taekyu_/90DaysOfDevOps-Day-77-gy84bjg5</link>
            <guid>https://velog.io/@taekyu_/90DaysOfDevOps-Day-77-gy84bjg5</guid>
            <pubDate>Sat, 24 Jan 2026 03:38:05 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>해당 스터디는 90DaysOfDevOps
<a href="https://github.com/MichaelCade/90DaysOfDevOps">https://github.com/MichaelCade/90DaysOfDevOps</a>
를 기반으로 진행한 내용입니다.</strong></p>
</blockquote>
<p>** Day 77 - Connect to Microsoft APIs in Azure DevOps Pipelines using Workload Identity Federation **</p>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine1-workload-identity-federation이란span"><span style='background-color: MediumAquamarine'>1. Workload Identity Federation이란?</span></h2>
<hr>

<p>DevOps 환경을 구축하다 보면 GitHub Actions나 Azure DevOps와 같은 외부 서비스에서 Azure 리소스에 접근해야 할 일이 빈번하다. </p>
<p><strong>기존에는 이를 위해 클라이언트 Secret을 생성하고 관리해야 했지만, 이는 보안상 취약점이 될 수 있고 만료 주기마다 갱신해야 하는 번거로움이 있었다.</strong></p>
<p><img src="https://velog.velcdn.com/images/taekyu_/post/488f8888-ba9e-4227-af50-e7fd672787af/image.png" alt=""></p>
<p><span style="color: indianred"><strong>Workload Identity Federation은 GitHub, Azure DevOps 등과 같은 외부 워크로드의 ID를 Microsoft Entra ID의 ID와 연동하여, 별도의 암호나 액세스 키를 관리할 필요 없이 Azure 리소스에 접근할 수 있게 해주는 기능이다.</strong></span></p>
<blockquote>
<p><strong><span style="color: SlateBlue">Workload Identity Federation:</span> 앱 등록이나 사용자 할당 관리 ID를 생성한 후, OpenID Connect를 통해 신뢰 관계를 설정함으로써 외부 파이프라인이 Azure 리소스에 액세스하도록 허용하는 방식</strong></p>
</blockquote>
<p>*<em>Workload Identity Federation은 OIDC(OpenID Connect) 프로토콜을 사용한다. *</em></p>
<p><span style="color: indianred">*<em>Azure AD는 외부 자격 증명 공급자(예: GitHub, Azure DevOps)가 발급한 토큰을 신뢰하도록 설정된다. *</em></span></p>
<p>즉, &quot;비밀번호를 가져와&quot;가 아니라, &quot;내가 신뢰하는 시스템(Azure DevOps)이 증명한 사용자니까 통과시켜&quot;라는 방식이다. 이로 인해 시크릿 관리가 필요 없어지는 Secret-less 인증이 가능해진다.</p>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine2-oidc란span"><span style='background-color: MediumAquamarine'>2. OIDC란?</span></h2>
<hr>

<p>Workload Identity Federation은 OIDC(OpenID Connect) 프로토콜을 사용한다.</p>
<p><strong>그렇다면 OIDC는 무엇이며, 해당 시나리오에서 어떻게 작동하는 것일까?</strong></p>
<h3 id="span-stylecolor-slateblue2-1-oidc-openid-connect의-개념span"><span style="color: SlateBlue">2-1. OIDC (OpenID Connect)의 개념</span></h3>
<p><img src="https://velog.velcdn.com/images/taekyu_/post/ce1154f2-d26f-4d88-9628-1254b3e09840/image.png" alt=""></p>
<ul>
<li><span style="color: indianred"><strong>정의:</strong></span> OAuth 2.0 프로토콜 위에 구축된 인증(Authentication) 레이어이다.</li>
</ul>
<ul>
<li><p><span style="color: indianred"><strong>차이점:</strong></span></p>
<ul>
<li><p><code>OAuth 2.0</code>: &quot;이 사용자가 내 사진첩에 접근해도 될까?&quot; (권한 부여: Authorization)에 초점</p>
</li>
<li><p><code>OIDC</code>: &quot;이 사용자가 누구인가?&quot; (신원 확인: Authentication)에 초점</p>
</li>
</ul>
</li>
</ul>
<p>OAuth 2.0이 호텔의 객실 카드키를 발급해 주는 절차라면, OIDC는 그 카드키를 발급받기 위해 프론트 데스크에서 신분증을 확인하는 과정과 유사하다.
<br></p>
<h3 id="span-stylecolor-slateblue2-2-wif에서-oidc의-작동-원리-토큰-교환-과정span"><span style="color: SlateBlue">2-2. WIF에서 OIDC의 작동 원리 (토큰 교환 과정)</span></h3>
<p><strong>Workload Identity Federation 환경에서 Azure Entra ID와 외부 공급자인 Azure DevOps/GitHub는 다음과 같은 방식으로 신뢰를 구축한다.</strong></p>
<p><img src="https://velog.velcdn.com/images/taekyu_/post/363ba26c-e635-4336-9b97-ac33a46b752e/image.png" alt=""></p>
<ol>
<li><p><span style="color: indianred"><strong>외부 토큰 생성 (External Token):</strong></span></p>
<ul>
<li><p>Azure DevOps 파이프라인이 실행되면, 외부 자격 증명 공급자(Azure DevOps)는 현재 작업에 대한 정보를 담은 JWT(JSON Web Token)를 생성한다.</p>
</li>
<li><p>이 토큰에는 발급자(Issuer), 대상(Subject), 유효기간 등의 정보가 서명(Signed)되어 있다.</p>
</li>
</ul>
</li>
<li><p><span style="color: indianred"><strong>토큰 교환 요청:</strong></span></p>
<ul>
<li>파이프라인은 이 외부 토큰을 가지고 Azure Entra ID에 접근하여 &quot;Azure 리소스에 접근할 수 있는 액세스 토큰으로 교환해 달라&quot;고 요청한다.</li>
</ul>
</li>
<li><p><span style="color: indianred"><strong>검증:</strong></span></p>
<ul>
<li><p>Azure AD는 외부 공급자의 공개 키를 사용하여 JWT의 서명을 확인한다. (OIDC Discovery)</p>
</li>
<li><p>등록된 &#39;페더레이션 자격 증명&#39; 설정과 토큰의 정보(Issuer, Subject)가 일치하는지 대조한다.</p>
</li>
</ul>
</li>
<li><p><span style="color: indianred"><strong>액세스 토큰 발급:</strong></span></p>
<ul>
<li>검증이 완료되면 Azure AD는 Azure 리소스 제어에 사용할 수 있는 자체 액세스 토큰을 발급한다.<br>

</li>
</ul>
</li>
</ol>
<h3 id="span-stylecolor-slateblue3-왜-oidc가-더-안전한가span"><span style="color: SlateBlue">3. 왜 OIDC가 더 안전한가?</span></h3>
<ul>
<li><p><span style="color: indianred"><strong>Secret-less:</strong></span> 클라이언트 시크릿(비밀번호)을 어딘가에 저장하거나 전송할 필요가 없다. 오직 신뢰 관계(Trust)만 존재한다.</p>
</li>
<li><p><span style="color: indianred"><strong>단기 유효성:</strong></span> 교환에 사용되는 토큰은 유효 기간이 매우 짧아, 탈취되더라도 위험이 적다.</p>
</li>
<li><p><span style="color: indianred"><strong>표준화:</strong></span> GitHub, Azure DevOps, Kubernetes 등 다양한 플랫폼이 OIDC 표준을 따르므로 확장성이 뛰어나다.</p>
</li>
</ul>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine3-federation-설정-방법span"><span style='background-color: MediumAquamarine'>3. Federation 설정 방법</span></h2>
<hr>

<p><strong>Workload Identity Federation을 설정하는 데는 크게 두 가지 진입점이 있다.</strong></p>
<ul>
<li><p><span style="color: SlateBlue"><strong>옵션 A: 앱 등록 (App Registration) 사용</strong></span></p>
<ol>
<li><p>Microsoft Entra ID 테넌트에서 <code>새 앱 등록</code>을 생성한다. </p>
</li>
<li><p>등록 후 <code>[인증서 및 암호]</code> 메뉴로 이동</p>
</li>
<li><p>클라이언트 암호를 만드는 대신 <code>[페더레이션 자격 증명(Federated Credentials)]</code> 탭을 선택</p>
</li>
<li><p><code>[자격 증명 추가]</code>를 클릭하고 시나리오를 선택</p>
<ul>
<li><p>GitHub Actions나 Kubernetes 등을 선택할 수 있다.</p>
</li>
<li><p><span style="color: indianred"><strong>Azure DevOps를 사용하는 경우 <code>기타 발급자(Other issuer)</code>를 선택하고 값을 수동으로 입력</strong></span></p>
<br>


</li>
</ul>
</li>
</ol>
</li>
</ul>
<ul>
<li><p><span style="color: SlateBlue"><strong>옵션 B: 사용자 할당 관리 ID (User-assigned Managed Identity) 사용</strong></span></p>
<ol>
<li><p>Azure Portal에서 <code>관리 ID(Managed Identities)</code>를 검색하여 생성 또는 선택</p>
</li>
<li><p>설정 메뉴 중 <code>[페더레이션 자격 증명]</code> 탭으로 이동</p>
</li>
<li><p>자격 증명을 추가하며 GitHub Actions, Kubernetes 등의 시나리오를 지원</p>
<br>


</li>
</ol>
</li>
</ul>
<ul>
<li><p><span style="color: SlateBlue">💡<strong>관리 ID (Managed Identity)란?</strong></span></p>
<ul>
<li><p><strong>Azure 리소스(VM, App Service 등)가 다른 Azure 서비스(SQL DB, Storage 등)에 접근할 때, 코드 내에 자격 증명을 저장하지 않도록 돕는 기능</strong></p>
</li>
<li><p>Azure가 내부적으로 ID 관리를 전담하므로 개발자가 비밀번호를 알 필요도, 관리할 필요도 없음.
<img src="https://velog.velcdn.com/images/taekyu_/post/ba6d0aa7-7156-4d34-86aa-1f22855bd626/image.png" alt=""></p>
</li>
<li><p><span style="color: indianred"><strong>시스템 할당:</strong></span> 리소스 생명주기와 함께 생성 및 삭제됨.</p>
</li>
<li><p><span style="color: indianred"><strong>사용자 할당:</strong></span> 독립적인 리소스로 생성되어 여러 서비스에 할당 가능. </p>
</li>
</ul>
</li>
</ul>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine4-azure-devops에서-서비스-연결-생성span"><span style='background-color: MediumAquamarine'>4. Azure DevOps에서 서비스 연결 생성</span></h2>
<hr>

<p><strong>해당 프레젠테이션 데모에서는 Azure DevOps 프로젝트로 이동하여 실제 연결을 설정하는 과정을 설명하였다.</strong></p>
<ol>
<li><p>Azure DevOps 프로젝트의 <strong>[Project Settings]</strong> -&gt; <strong>[Service connections]</strong>로 이동한다.</p>
</li>
<li><p><strong>[New service connection]</strong>을 클릭하고 <code>Azure Resource Manager</code> 타입을 선택한다.</p>
<br>


</li>
</ol>
<ul>
<li><p><span style="color: SlateBlue">*<em>Azure Resource Manager (ARM) 란? *</em></span></p>
<ul>
<li><p>Azure의 배포 및 관리 서비스</p>
</li>
<li><p>Azure의 모든 리소스(VM, DB, Network 등)를 생성, 업데이트, 삭제하는 관리 계층을 제공</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/taekyu_/post/9ad03846-9a65-4091-8f2f-240a68933b0b/image.png" alt=""></p>
<ul>
<li><span style="color: indianred"><strong>Azure DevOps가 Azure 리소스를 제어하려면 ARM API와 통신해야 하므로, 서비스 연결 타입이 <code>Azure Resource Manager</code>가 되어야 함.</strong></span></li>
</ul>
</li>
</ul>
<br>

<ul>
<li><p><span style="color: SlateBlue">*<em>연결 설정 방식: 자동 vs 수동 *</em></span></p>
<ul>
<li><p><span style="color: indianred"><strong>Automatic (권장):</strong></span> </p>
<ul>
<li><p>테넌트 내 앱 등록 권한이 있다면 권장되는 방식</p>
</li>
<li><p>구독을 선택하고 저장하면 자동으로 앱 등록과 페더레이션 설정이 완료</p>
</li>
</ul>
</li>
<li><p><span style="color: indianred"><strong>Manual:</strong></span> </p>
<ul>
<li><p>앱 등록 권한이 없는 경우 사용</p>
</li>
<li><p>시스템이 생성해주는 발급자(Issuer)와 주체 식별자(Subject Identifier) 정보를 복사하여 Entra ID 관리자에게 전달하고 설정을 요청해야 함.</p>
</li>
</ul>
<br>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>페더레이션 자격 증명의 구성 요소</strong></span></p>
<ul>
<li><p>설정이 완료된 후 Entra ID에서 해당 앱 등록을 확인해보면 시크릿은 없고 페더레이션 자격 증명만 존재한다.
<img src="https://velog.velcdn.com/images/taekyu_/post/2ae2f8ea-97da-4ec7-9f0a-882db274670b/image.png" alt=""></p>
</li>
<li><p><span style="color: indianred"><strong>Issuer (발급자):</strong></span> Azure DevOps 환경의 URL</p>
</li>
<li><p><span style="color: indianred"><strong>Subject Identifier (주체 식별자):</strong></span> Organization, 프로젝트, 그리고 서비스 연결 이름을 식별하는 문자열</p>
</li>
<li><p><span style="color: indianred"><strong>Audience (대상):</strong></span>   <code>api://AzureADTokenExchange</code> (항상 해당 값으로 고정)</p>
</li>
</ul>
</li>
</ul>
<p>해당 설정 덕분에 Azure DevOps의 특정 서비스 연결이 요청을 보낼 때, Entra ID는 이를 신뢰할 수 있는 요청으로 식별하게 된다.</p>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine5-azure-pipeline에서-microsoft-graph-연동span"><span style='background-color: MediumAquamarine'>5. Azure Pipeline에서 Microsoft Graph 연동</span></h2>
<hr>

<p><strong>설정된 Workload ID Federation을 활용하여, 파이프라인 상에서 Microsoft Graph에 인증하고 데이터를 가져오는 시나리오이다.</strong>
<br></p>
<ul>
<li><p><span style="color: SlateBlue">*<em>데모의 핵심 의도 *</em></span></p>
<ul>
<li><p>일반적으로 Azure AD 사용자 조회나 관리 작업은 관리자가 직접 수행하거나, 스크립트에 관리자 ID/PW를 저장하여 수행한다.</p>
</li>
<li><p><span style="color: indianred"><strong>해당 데모는 파이프라인이 Workload ID Federation을 통해 스스로 신원을 증명하고, 관리자 개입 없이 보안 토큰을 발급받아 관리 도구인 Graph API를 호출할 수 있음을 검증하는 개념 증명 과정이다.</strong></span></p>
<br>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>Microsoft Graph란?</strong></span> </p>
<ul>
<li><p>Microsoft 365(Office, Windows, Entra ID 등)의 수많은 데이터와 인텔리전스에 접근할 수 있는 통합 API 엔드포인트 
<img src="https://velog.velcdn.com/images/taekyu_/post/ed1a2e51-63a1-4eb9-a375-b1a7ae473748/image.png" alt=""></p>
</li>
<li><p>이를 통해 사용자 정보 조회, 메일 발송, 일정 관리 등을 프로그래밍 방식으로 제어할 수 있다. </p>
</li>
<li><p><span style="color: indianred"><strong>해당 데모에서는 Connect-MgGraph를 통해 Entra ID의 사용자 정보를 조회하는 데 사용</strong></span></p>
<br>

</li>
</ul>
</li>
</ul>
<h3 id="span-stylecolor-slateblue4-1-파이프라인-구성-1단계--액세스-토큰-획득-azure-cli-span"><span style="color: SlateBlue">*<em>4-1. 파이프라인 구성 1단계 : 액세스 토큰 획득 (Azure CLI) *</em></span></h3>
<p>*<em>먼저 <code>AzureCLI@2</code> 태스크를 사용하여 토큰을 가져온다. *</em></p>
<p>해당 단계는 파이프라인이 &quot;나 신뢰할 수 있는 파이프라인이야&quot;라고 Azure AD에 신호를 보내고, OIDC 검증을 거쳐 Access Token를 건네받는 과정이다.</p>
<p>이때 서비스 연결은 Workload Identity Federation이 적용된 연결을 사용한다.</p>
<pre><code class="language-bash"># Azure CLI로 액세스 토큰 요청
az account get-access-token --resource-type ms-graph</code></pre>
<ul>
<li><p><code>--resource-type</code>을 ms-graph로 지정하여 Graph API용 토큰을 받는다. 
(ARM API나 Key Vault용으로도 변경 가능)</p>
</li>
<li><p><span style="color: indianred"><strong>핵심 원리:</strong></span> 파이프라인 에이전트가 자신의 OIDC 토큰을 Azure AD에 제시하면, Azure AD는 미리 등록된 &#39;페더레이션 자격 증명&#39;과 대조하여 유효성을 확인한 후 Microsoft Graph 접근용 액세스 토큰을 발급해준다.</p>
</li>
<li><p>받아온 토큰을 파이프라인 내에서 사용할 변수인 <code>secretToken</code>로 설정하고, 이를 Secret 타입으로 지정하여 로그에 노출되지 않도록 한다.</p>
<br>

</li>
</ul>
<h3 id="span-stylecolor-slateblue4-2-파이프라인-구성-2단계--보안-문자열-변환-및-graph-api-호출span"><span style="color: SlateBlue"><strong>4-2. 파이프라인 구성 2단계 : 보안 문자열 변환 및 Graph API 호출</strong></span></h3>
<p>앞서 발급받은 토큰을 사용하여 실제로 Microsoft Graph에 로그인하고 관리 작업을 수행한다.</p>
<pre><code class="language-bash"># 1. 일반 변수를 PowerShell의 SecureString으로 변환
$secureToken = ConvertTo-SecureString -String $env:secretToken -AsPlainText -Force

# 2. Microsoft Graph 연결
Connect-MgGraph -AccessToken $secureToken

# 3. 사용자 정보 조회
Get-MgUser -UserId &quot;testuser@domain.com&quot;</code></pre>
<ul>
<li><p><span style="color: indianred"><strong>의의:</strong></span> <code>Connect-MgGraph</code> 명령어 실행 시 별도의 로그인 창이나 패스워드 입력 없이, 1단계에서 획득한 토큰만으로 인증(-AccessToken)을 통과하는 것이 핵심이다.</p>
</li>
<li><p>파이프라인은 비밀 변수를 평문으로 접근할 수 있지만, <strong><code>Connect-MgGraph 명령어</code></strong>는 SecureString을 요구하므로 변환 과정이 필요하다.</p>
</li>
</ul>
<br>

<h3 id="span-stylecolor-slateblue4-3-주의사항-권한-부여-api-permissionsspan"><span style="color: SlateBlue"><strong>4-3. 주의사항: 권한 부여 (API Permissions)</strong></span></h3>
<p>인증(Authentication)에 성공했더라도, 특정 작업을 수행하려면 권한(Authorization)이 필요하다.</p>
<p><span style="color: indianred"><strong>토큰을 통해 &quot;내가 누구인지&quot;는 증명했지만, &quot;무엇을 할 수 있는지&quot;는 별도로 정의해야 한다.</strong></span></p>
<ol>
<li><p>Entra ID 포털의 해당 앱 등록 메뉴로 이동한다.</p>
</li>
<li><p>[API 권한] 탭에서 Microsoft Graph -&gt; <code>User.Read.All</code> 등의 필요한 권한을 추가하고 관리자 동의를 얻어야 한다.</p>
</li>
<li><p>이 과정이 누락되면 Get-MgUser 실행 시 권한 부족 오류가 발생한다.</p>
</li>
</ol>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine6-정리span"><span style='background-color: MediumAquamarine'>6. 정리</span></h2>
<hr>

<p><span style="color: indianred">*<em>Workload Identity Federation은 기존의 클라이언트 시크릿 방식이 가진 보안 취약점과 관리 비용을 OIDC 기반의 신뢰 관계로 대체하는 인증 기술이다. *</em></span></p>
<p>*<em>이는 외부 ID 공급자와 Azure AD 간의 토큰 교환을 통해 자격 증명이 필요 없는(Secret-less) 아키텍처를 구현함으로써, 보안 리스크를 원천적으로 차단한다. *</em></p>
<p>결과적으로 엔지니어는 시크릿 만료나 유출 걱정 없이 Microsoft Graph 및 Azure 리소스에 대한 일관된 보안 거버넌스를 유지하며, 더욱 견고한 자동화 파이프라인을 구축할 수 있다.</p>
<p><span style="color: indianred"></span>
<span style="color: SlateBlue"></span></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[90DaysOfDevOps (Day 76)]]></title>
            <link>https://velog.io/@taekyu_/90DaysOfDevOps-Day-76-v77hoer5</link>
            <guid>https://velog.io/@taekyu_/90DaysOfDevOps-Day-76-v77hoer5</guid>
            <pubDate>Thu, 22 Jan 2026 04:47:58 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>해당 스터디는 90DaysOfDevOps
<a href="https://github.com/MichaelCade/90DaysOfDevOps">https://github.com/MichaelCade/90DaysOfDevOps</a>
를 기반으로 진행한 내용입니다.</strong></p>
</blockquote>
<p>** Day 76 - All you need to know about AWS CDK **</p>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine1-aws-cdk란-span"><span style='background-color: MediumAquamarine'>1. AWS CDK란? </span></h2>
<hr>

<p>AWS에서 기존의 관리 콘솔을 통한 수동 작업은 오류가 발생할 확률이 높다. 이러한 문제를 해결하기 위해 등장한 것이 바로 AWS CDK이다.</p>
<p><span style="color: indianred"><strong>CDK(Cloud Development Kit)는 코드를 사용하여 클라우드 인프라를 정의할 수 있게 해주는 프레임워크이자 툴킷이다.</strong></span></p>
<p><strong>즉, 일반적인 소프트웨어를 개발하듯이 인프라를 코딩(Infrastructure as Code)하는 것이다.</strong></p>
<p><img src="https://velog.velcdn.com/images/taekyu_/post/f4dd8f54-2dfa-4aad-a4f8-a4fa4983add8/image.png" alt=""></p>
<p>*<em>사용자가 배포하고자 하는 인프라를 코드로 정의하면, CDK는 이를 AWS 리소스를 설정해 주는 서비스인 CloudFormation 템플릿으로 변환하여 배포한다. *</em></p>
<p>CloudFormation은 리소스의 프로비저닝, 구성, 의존성 관리를 자동으로 처리해 준다.</p>
<hr>
<p><span style="color: indianred"><strong>CDK를 이해할 때 가장 중요한 점은 작성한 코드가 AWS에 직접 배포되는 것이 아니라는 점이다.</strong></span></p>
<ol>
<li><p><span style="color: SlateBlue"><strong>코드 작성:</strong></span> 사용자가 CDK를 이용해 인프라를 코딩</p>
</li>
<li><p><span style="color: SlateBlue"><strong>변환:</strong></span> 작성된 코드는 JSON 또는 YAML 형태의 CloudFormation 템플릿으로 변환됨.</p>
</li>
<li><p><span style="color: SlateBlue"><strong>배포:</strong></span> 변환된 CloudFormation 템플릿이 AWS에 업로드되고, 이를 통해 리소스가 생성된다.</p>
</li>
</ol>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine2-aws-cdk를-사용해야하는-이유span"><span style='background-color: MediumAquamarine'>2. AWS CDK를 사용해야하는 이유</span></h2>
<hr>

<ul>
<li><p><span style="color: SlateBlue"><strong>관리 콘솔(Console) 대비 장점</strong></span></p>
<ul>
<li><p>S3 버킷을 생성하고 객체를 업로드하는 단순한 작업은 콘솔에서도 가능하지만, S3와 DynamoDB를 연동하는 등 복잡한 인프라를 구축할 때는 이야기가 다르다.</p>
</li>
<li><p>콘솔에서의 수동 클릭은 실수를 유발하기 쉽다.</p>
</li>
<li><p>복잡한 아키텍처를 단 몇 줄의 코드로 구현하여 빠르게 배포할 수 있다.</p>
<br>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>CloudFormation 직접 사용 대비 장점</strong></span></p>
<ul>
<li><p>&quot;어차피 CloudFormation으로 변환되는데, 처음부터 CloudFormation(JSON/YAML)으로 작성하면 되지 않나?&quot;라는 의문이 들 수 있다. 하지만 CDK는 다음과 같은 강력한 이점을 가진다.</p>
</li>
<li><p><span style="color: indianred"><strong>프로그래밍 언어 선택권:</strong></span> </p>
<ul>
<li><p>CloudFormation은 오직 JSON이나 YAML만 사용해야 하므로 복잡한 로직을 구현하기 어렵다. </p>
</li>
<li><p>반면, CDK는 Python, Java, TypeScript, JavaScript, .NET(C#), Go 등 친숙한 프로그래밍 언어를 사용하여 인프라를 구축할 수 있다.</p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine3-aws-cdk-아키텍처span"><span style='background-color: MediumAquamarine'>3. AWS CDK 아키텍처</span></h2>
<hr>

<p><img src="https://velog.velcdn.com/images/taekyu_/post/a9f4fe24-b7b1-4d24-a46a-680054bb5743/image.png" alt=""></p>
<ol>
<li><p><span style="color: SlateBlue"><strong>App (앱):</strong></span></p>
<ul>
<li><p>가장 상위 개념으로, Container 역할을 한다.</p>
</li>
<li><p>내부에 여러 개의 Stack을 담는다.</p>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>Stack (스택):</strong></span></p>
<ul>
<li><p>기본적으로 Template과 같은 개념이다.</p>
</li>
<li><p><strong>리소스 간의 관계를 설정하는 단위</strong></p>
</li>
<li><p><span style="color: indianred"><strong>Stack이 나중에 CloudFormation 템플릿으로 변환된다.</strong></span></p>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>Construct (컨스트럭트):</strong></span></p>
<ul>
<li><p>Stack 내부에서 정의되며, 실제 AWS 리소스들을 보유하고 그룹화하는 구성 요소</p>
</li>
<li><p>예를 들어, S3 버킷과 같은 구체적인 리소스 정의가 이곳에서 이루어진다.</p>
</li>
</ul>
</li>
</ol>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine4-정리span"><span style='background-color: MediumAquamarine'>4. 정리</span></h2>
<hr>

<p>AWS CDK는 복잡한 클라우드 인프라를 익숙한 프로그래밍 언어로 효율적으로 관리하고 배포할 수 있게 해주는 강력한 도구이다. </p>
<p><strong>Terraform과 같은 대안도 존재하지만, AWS 환경에서 프로그래밍 언어의 이점을 살려 인프라를 구축하고 싶다면 CDK는 최적의 선택이 될 것이다.</strong></p>
<p><span style="color: indianred"></span>
<span style="color: SlateBlue"></span></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[90DaysOfDevOps (Day 75)]]></title>
            <link>https://velog.io/@taekyu_/90DaysOfDevOps-Day-75-wtqg8hzq</link>
            <guid>https://velog.io/@taekyu_/90DaysOfDevOps-Day-75-wtqg8hzq</guid>
            <pubDate>Mon, 19 Jan 2026 15:48:31 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>해당 스터디는 90DaysOfDevOps
<a href="https://github.com/MichaelCade/90DaysOfDevOps">https://github.com/MichaelCade/90DaysOfDevOps</a>
를 기반으로 진행한 내용입니다.</strong></p>
</blockquote>
<p>** Day 75 - Distracted Development **</p>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine1-산만한-개발의-실체span"><span style='background-color: MediumAquamarine'>1. 산만한 개발의 실체</span></h2>
<hr>

<p>우리는 흔히 바쁜 것을 생산적인 것으로 착각한다. </p>
<p><span style="color: indianred"><strong>하지만 산만한 개발(Distracted Development)은 멀티태스킹이나 분산된 주의력으로 인해 집중력과 생산성을 잃는 현상을 말한다.</strong></span></p>
<p>이는 단순히 일을 덜 하는 문제가 아니라, 결과물의 품질과 영향력이 떨어지는 심각한 문제다.</p>
<p>*<em>캘리포니아 대학교 어바인의 연구에 따르면, 현대 직장인은 8시간 근무 중 평균 40~45회의 방해를 받는다고 한다. *</em></p>
<p>이러한 잦은 방해는 업무 흐름을 끊고, 깊이 있는 사고를 불가능하게 만든다.</p>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine2-멀티태스킹이라는-환상span"><span style='background-color: MediumAquamarine'>2. 멀티태스킹이라는 환상</span></h2>
<hr>

<p><strong>우리는 동시에 여러 일을 처리하는 능력을 찬양하지만, 뇌과학적으로 볼 때 멀티태스킹은 존재하지 않는다.</strong></p>
<h3 id="span-stylecolor-slateblue2-1-뇌는-전환할-뿐이다span"><span style="color: SlateBlue">2-1. 뇌는 전환할 뿐이다</span></h3>
<p>*<em>인간의 뇌는 한 번에 하나의 작업만 처리할 수 있다. *</em></p>
<p>우리가 멀티태스킹이라고 믿는 것은 사실 A 작업에서 B 작업으로 아주 빠르게 초점을 옮기는 행위일 뿐이다.
<br></p>
<h3 id="span-stylecolor-slateblue2-2-숨겨진-대가-전환-비용span"><span style="color: SlateBlue">2-2. 숨겨진 대가: 전환 비용</span></h3>
<p><strong>작업을 바꿀 때마다 우리 뇌는 새로운 문맥에 적응하기 위해 에너지를 쓴다. 이를 전환 비용이라고 한다.</strong></p>
<p>미국 심리학회에 따르면, 이 잦은 전환으로 인해 생산적인 시간의 최대 40%가 낭비된다.</p>
<p>생산성 저하 없이 진정으로 멀티태스킹이 가능한 슈퍼 태스커는 전 세계 인구의 단 2%에 불과하다.</p>
<p><span style="color: indianred"><strong>나머지 98%인 우리는 한 번에 하나만 하는 것이 훨씬 효율적이다.</strong></span></p>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine3-방해받은-시간의-경제학span"><span style='background-color: MediumAquamarine'>3. 방해받은 시간의 경제학</span></h2>
<hr>

<p>잠깐 메신저를 확인하고 다시 업무로 돌아오는 데 얼마나 걸릴까? 데이터는 충격적인 결과를 보여준다.</p>
<ul>
<li><p><span style="color: indianred"><strong>23분의 법칙:</strong></span> UC Irvine 연구에 따르면, 직장인은 평균 11분마다 방해를 받으며, 한 번 방해를 받은 후 원래의 깊은 집중 상태로 돌아가는 데는 최대 23분이 걸린다. 이를 계산하면 하루에 온전히 집중하는 시간은 약 3시간 18분에 불과하다.</p>
</li>
<li><p><span style="color: indianred"><strong>회의에 의한 죽음 (Death by Meeting):</strong></span> 아틀라시안의 연구에 따르면, 직장인들은 하루 약 1시간 30분을 가치 없는 회의에 소비한다. 이는 기업 입장에서 연간 수십억 원의 매몰 비용을 의미한다.</p>
</li>
</ul>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine4-몰입을-되찾는-3가지-전략-span"><span style='background-color: MediumAquamarine'>4. 몰입을 되찾는 3가지 전략 </span></h2>
<hr>

<p><strong>산만함의 늪에서 빠져나와 Deep Work를 실현하기 위한 검증된 방법들이다.</strong></p>
<h3 id="span-stylecolor-slateblue4-1-타임-블로킹과-우선순위span"><span style="color: SlateBlue">4-1. 타임 블로킹과 우선순위</span></h3>
<p>하루 종일 반응형으로 일해서는 안 된다. </p>
<p><span style="color: indianred"><strong>타임 블로킹을 통해 특정 작업에 전용 시간을 할당해야 한다.</strong></span></p>
<p><strong>또한, 아이젠하워 매트릭스를 활용해 긴급한 일과 중요한 일을 구분하고, 무엇에 집중할지 전략적으로 선택해야 한다.</strong>
<br></p>
<h3 id="span-stylecolor-slateblue4-2-휴식의-기술-포모도로-pomodorospan"><span style="color: SlateBlue">4-2. 휴식의 기술: 포모도로 (Pomodoro)</span></h3>
<p>*<em>쉬지 않고 일하는 것이 능사가 아니다. *</em></p>
<p><span style="color: indianred"><strong>25분간 집중하고 5분간 휴식하는 포모도로 기법을 활용한다.</strong> </span></p>
<p>일리노이 대학교의 연구에 따르면, 작업 중의 짧고 계획된 휴식은 뇌의 인지 배터리를 재충전시켜 장기적인 집중력을 극적으로 향상시킨다.
<br></p>
<h3 id="span-stylecolor-slateblue4-3-디지털-차단-digital-detoxspan"><span style="color: SlateBlue">4-3. 디지털 차단 (Digital Detox)</span></h3>
<p>이메일과 메신저는 정해진 시간에만 확인한다. 불필요한 알림을 끄고, 기술적으로 방해 요소를 차단하는 앱을 활용하는 것도 훌륭한 전략이다.</p>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine5-결론-싱글-태스킹의-힘span"><span style='background-color: MediumAquamarine'>5. 결론: 싱글 태스킹의 힘</span></h2>
<hr>

<p><strong>마이크로소프트는 회의 없는 날을 도입해 생산성을 높였고, 구글은 20% 타임을 통해 직원들이 한 가지 프로젝트에 몰입할 시간을 보장했다.</strong></p>
<p>하버드 비즈니스 리뷰를 비롯한 수많은 연구가 가리키는 결론은 명확하다. </p>
<p><span style="color: indianred">*<em>우리는 한 번에 하나에 온전히 집중할 때 가장 똑똑하고, 창의적이며, 평온하다. *</em></span></p>
<p>멀티태스킹의 환상을 버리고 싱글 태스킹을 선택할 때, 우리의 하루는 더 이상 산만하지 않을 것이다.</p>
<p><span style="color: indianred"></span>
<span style="color: SlateBlue"></span></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[90DaysOfDevOps (Day 74)]]></title>
            <link>https://velog.io/@taekyu_/90DaysOfDevOps-Day-74</link>
            <guid>https://velog.io/@taekyu_/90DaysOfDevOps-Day-74</guid>
            <pubDate>Mon, 19 Jan 2026 08:20:28 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>해당 스터디는 90DaysOfDevOps
<a href="https://github.com/MichaelCade/90DaysOfDevOps">https://github.com/MichaelCade/90DaysOfDevOps</a>
를 기반으로 진행한 내용입니다.</strong></p>
</blockquote>
<p>** Day 74 - Workload Identity Federation with Azure DevOps and Terraform **</p>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine1-workload-identity-federation-이란span"><span style='background-color: MediumAquamarine'>1. Workload Identity Federation 이란?</span></h2>
<hr>

<p><span style="color: indianred"><strong>해당 프레젠테이션은 Azure 클라우드 환경에서 보안의 핵심 트렌드로 자리 잡은 &#39;워크로드 아이덴티티 페더레이션(Workload Identity Federation)&#39;에 대해 다룬다.</strong></span></p>
<p>기존의 서비스 연결 방식이 가진 보안 취약점을 해결하고, 이 복잡한 설정 과정을 테라폼으로 자동화하는 방법, 그리고 실제 적용 시 주의해야 할 트러블슈팅 사례까지 상세히 정리한다.</p>
<hr>
<p><strong>시작에 앞서, 워크로드 아이덴티티 페더레이션(Workload Identity Federation)과 페더레이션 자격 증명(Federated Credentials)이 무엇인지, 왜 필요한지 정리해보겠다.</strong></p>
<h3 id="span-stylecolor-slateblue1-1-기존-방식의-문제점-secret-기반span"><span style="color: SlateBlue">1-1. 기존 방식의 문제점 (Secret 기반)</span></h3>
<p><strong>기존에 Azure DevOps 파이프라인이 Azure 리소스에 접근하려면 서비스 주체를 만들고 Secret이라고 불리는 비밀번호를 발급받아야 했다.</strong></p>
<ul>
<li><p><span style="color: indianred"><strong>방식:</strong></span> 아이디(App ID) + 비밀번호(Secret)를 Azure DevOps에 저장해두고 로그인하는 방식.</p>
</li>
<li><p><span style="color: indianred"><strong>문제점:</strong></span></p>
<ul>
<li><p>비밀번호는 유효기간이 있어 주기적으로 갱신해야 한다(관리 부담).</p>
</li>
<li><p>비밀번호가 유출되면 누구나 해당 권한을 사용할 수 있다(보안 위험).</p>
<br>

</li>
</ul>
</li>
</ul>
<h3 id="span-stylecolor-slateblue1-2-워크로드-아이덴티티-페더레이션-oidc-기반span"><span style="color: SlateBlue">1-2. 워크로드 아이덴티티 페더레이션 (OIDC 기반)</span></h3>
<p><span style="color: indianred"><strong>해당 방식은 비밀번호를 주고받는 것이 아니라 Azure DevOps을 신뢰하는 것이다.</strong> </span></p>
<p><strong>이를 기술적으로 OIDC(OpenID Connect) 프로토콜을 사용해 구현한다.</strong>
<img src="https://velog.velcdn.com/images/taekyu_/post/b22d675f-1b5f-412b-912f-7d7d279cd41e/image.png" width="80%" height="n%"></p>
<ul>
<li><p><span style="color: indianred"><strong>개념:</strong></span> Azure AD(Entra ID)에게 <strong>&quot;나는 Azure DevOps라는 곳에서 발행한 토큰을 믿겠다&quot;</strong>라고 설정하는 것. 이를 <strong><code>&#39;Federation(연합) 관계를 맺는다&#39;</code></strong>고 한다.</p>
</li>
<li><p><span style="color: indianred"><strong>작동 원리:</strong></span></p>
<ol>
<li><p>Azure DevOps 파이프라인이 실행되면 Azure DevOps가 &quot;이건 내가 보증하는 파이프라인이야&quot;라는 토큰을 발행한다.</p>
</li>
<li><p>이 토큰을 Azure AD에 건넨다.</p>
</li>
<li><p>Azure AD는 미리 설정된 페더레이션 자격 증명 정보(발급자, 대상 등)와 토큰을 대조한다</p>
</li>
<li><p>정보가 일치하면 비밀번호 없이도 접속을 허용한다.</p>
</li>
</ol>
</li>
<li><p><span style="color: indianred"><strong>장점:</strong></span> <strong>Secret이 아예 존재하지 않으므로, 유출될 키가 없고, 만료일 관리도 필요 없다. (Passwordless)</strong></p>
</li>
</ul>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine2-수동-설정의-번거로움과-terraform으로-자동화span"><span style='background-color: MediumAquamarine'>2. 수동 설정의 번거로움과 Terraform으로 자동화</span></h2>
<hr>

<p><strong>자동화 코드를 이해하기 위해서는 Azure AD와 Azure DevOps가 어떻게 **OIDC(OpenID Connect)</strong>를 통해 인증하는지 그 흐름을 알아야 한다.**</p>
<h3 id="span-stylecolor-slateblue2-0-azure와-devops-간의-신뢰-관계-oidcspan"><span style="color: SlateBlue">2-0. Azure와 DevOps 간의 신뢰 관계 (OIDC)</span></h3>
<ul>
<li><p><span style="color: indianred"><strong>Azure AD (Entra ID):</strong></span> </p>
<ul>
<li><p><strong>Azure 리소스에 대한 접근 권한(IAM)을 관리하는 Identity Provider</strong></p>
</li>
<li><p>Azure AD에서 앱 등록(Service Principal)을 생성해야 Azure 리소스에 접근할 수 있는 주체가 생긴다.</p>
</li>
</ul>
</li>
<li><p><span style="color: indianred"><strong>Azure DevOps:</strong></span> </p>
<ul>
<li>CI/CD를 수행하는 플랫폼이다. 배포 작업을 수행할 때 Azure AD에게 인증을 받아야 한다.</li>
</ul>
</li>
<li><p><span style="color: indianred"><strong>Trust Relationship (신뢰 관계)</strong></span> </p>
<ul>
<li><p>기존에는 Secret을 주고받았음.</p>
</li>
<li><p>WIF (Workload Identity Federation) 방식에서는 &quot;Azure DevOps의 특정 리포지토리/브랜치에서 발생한 토큰은 유효하다&quot;라는 규칙인 Federated Credential을 Azure AD에 등록</p>
</li>
</ul>
</li>
</ul>
<br>



<h3 id="span-stylecolor-slateblue2-1-수동-설정-프로세스-복잡함span"><span style="color: SlateBlue">2-1. 수동 설정 프로세스 (복잡함)</span></h3>
<p><strong>Tech Community 가이드에 따른 수동 설정은 두 플랫폼을 오가는 컨텍스트 스위칭이 발생한다.</strong></p>
<ol>
<li><p><span style="color: indianred"><strong>[Azure Portal]</strong></span> 앱 등록을 생성하여 Client ID, Tenant ID 확보.</p>
</li>
<li><p><span style="color: indianred"><strong>[Azure DevOps]</strong></span> 서비스 연결 생성 메뉴 진입 -&gt; &#39;Workload Identity Federation (Manual)&#39; 선택.</p>
</li>
<li><p><span style="color: indianred"><strong>[Azure DevOps]</strong></span> 화면에 생성된 Issuer URL과 Subject Identifier(주체 식별자) 문자열을 복사.</p>
</li>
<li><p><span style="color: indianred"><strong>[Azure Portal]</strong></span> 앱 등록 &gt; 인증서 및 암호 &gt; &#39;페더레이션 자격 증명&#39; 탭으로 이동하여 복사한 값 붙여넣기</p>
</li>
<li><p><span style="color: indianred"><strong>[Azure DevOps]</strong></span> 다시 돌아와서 연결 저장 및 검증</p>
<br>

</li>
</ol>
<h3 id="span-stylecolor-slateblue2-2-자동화-전략span"><span style="color: SlateBlue">2-2. 자동화 전략</span></h3>
<p><strong>프레젠테이션에서는 Terraform의 Provider들을 조합하여 이 상호 의존적인 설정을 한 번에 처리한다.</strong></p>
<p><span style="color: indianred"><strong>핵심은 azuread 프로바이더로 Azure 측 설정을 하고, 생성된 정보를 azuredevops 프로바이더로 넘겨주는 것이다.</strong></span>
<br></p>
<h3 id="span-stylecolor-slateblue2-3-자동화-코드-1-azure-ad-설정-entra-idspan"><span style="color: SlateBlue">2-3. 자동화 코드 1: Azure AD 설정 (Entra ID)</span></h3>
<p><strong>Azure 리소스에 접근할 수 있는 논리적인 자격 증명 주체를 생성하는 단계이다.</strong></p>
<ul>
<li><p><span style="color: indianred"><strong>App Registration 생성:</strong></span> </p>
<ul>
<li>Azure API를 호출할 수 있는 애플리케이션 개체를 생성</li>
</ul>
</li>
<li><p><span style="color: indianred"><strong>Federated Credentials 설정:</strong></span>  </p>
<ul>
<li><p>Secret을 생성하는 대신 <code>azuread_application_federated_identity_credential</code> 리소스를 사용</p>
</li>
<li><p><code>repo:&lt;조직&gt;/&lt;프로젝트&gt;:ref:refs/heads/main</code>과 같이 Azure DevOps가 발행할 토큰의 대상을 명시하여 Azure AD에 등록</p>
</li>
<li><p>즉, &quot;이 경로에서 오는 요청은 인증해라&quot;라는 정책을 심는 과정</p>
</li>
</ul>
</li>
</ul>
<br>

<h3 id="span-stylecolor-slateblue2-4-자동화-코드-2-azure-devops-설정span"><span style="color: SlateBlue">2-4. 자동화 코드 2: Azure DevOps 설정</span></h3>
<p><strong>Azure AD에 등록된 정보를 바탕으로, Azure DevOps 파이프라인이 사용할 연결 객체를 만든다.</strong></p>
<ul>
<li><p><span style="color: indianred"><strong>Service Connection 생성:</strong></span>  </p>
<ul>
<li><p><code>azuredevops_serviceendpoint_azurerm</code> 리소스를 생성한다.</p>
</li>
<li><p>앞서 생성한 App Registration의 Application ID(Client ID)와 Tenant ID를 주입</p>
</li>
<li><p><strong><code>service_endpoint_authentication_scheme</code> 속성을 <code>WorkloadIdentityFederation</code>으로 설정하여, Secret 기반 인증이 아님을 명시</strong></p>
</li>
</ul>
</li>
<li><p><span style="color: indianred"><strong>권한 부여:</strong></span> </p>
<ul>
<li>생성된 서비스 연결을 파이프라인들이 승인 없이 사용할 수 있도록 <code>azuredevops_resource_authorization</code> 리소스를 통해 권한을 열어준다.</li>
</ul>
</li>
</ul>
<br>

<h3 id="span-stylecolor-slateblue2-5-자동화-코드-3-azure-리소스-권한-부여-rbacspan"><span style="color: SlateBlue">2-5. 자동화 코드 3: Azure 리소스 권한 부여 (RBAC)</span></h3>
<p><strong>인증은 2-3, 2-4에서 해결되었으나, 실제 리소스를 조작할 수 있는 권한은 별도로 부여해야 한다.</strong></p>
<ul>
<li><p><span style="color: indianred"><strong>구독 범위 권한:</strong></span> </p>
<ul>
<li><p><code>Contributor</code>: Terraform이 리소스 그룹, 네트워크 등을 생성/삭제하기 위한 필수 권한</p>
</li>
<li><p><code>User Access Administrator</code>: Terraform이 배포 과정에서 또 다른 IAM 할당을 수행해야 할 경우 필요</p>
</li>
</ul>
</li>
<li><p><span style="color: indianred"><strong>스토리지 계정(Storage Account):</strong></span> </p>
<ul>
<li><p><code>Storage Blob Data Contributor</code></p>
</li>
<li><p>Terraform은 인프라의 현재 상태를 tfstate 파일로 관리하며, 해당 파일은 Azure Storage Blob에 저장된다.</p>
</li>
<li><p>단순 Contributor 권한은 Control Plane 권한이므로, 실제 데이터인 Blob 파일을 읽고 쓰기 위해서는 Data Plane 권한인 이 역할이 반드시 필요하다.</p>
</li>
</ul>
</li>
</ul>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine3-wif-서비스-연결을-이용한-테라폼-배포-방법span"><span style='background-color: MediumAquamarine'>3. WIF 서비스 연결을 이용한 테라폼 배포 방법</span></h2>
<hr>

<p>해당 방법을 통해 보안이 강화된(WIF 기반) 서비스 연결이 준비되었다. </p>
<p><strong>이를 사용하여 실제 인프라(예: VM, VNet 등)를 배포하는 파이프라인을 구성할 때 지켜야 할 4가지 필수 조건이 있다.</strong></p>
<ol>
<li><p><span style="color: indianred"><strong>RBAC 권한 확인:</strong></span></p>
<ul>
<li>사용할 서비스 주체(App)가 구독에 대한 Contributor 권한을 가지고 있어야 한다.</li>
</ul>
</li>
<li><p><span style="color: indianred"><strong>상태 파일 접근 권한:</strong></span></p>
<ul>
<li>테라폼 백엔드로 사용할 스토리지 계정에 대해 Storage Blob Data Contributor 권한이 있어야 한다. (단순 Contributor로는 데이터 접근이 안 될 수 있음)</li>
</ul>
</li>
<li><p><span style="color: indianred"><strong>테라폼 태스크 버전 업데이트:</strong></span></p>
<ul>
<li>Azure DevOps 파이프라인(YAML)에서 사용하는 테라폼 태스크 버전을 TerraformTaskV4@4 (버전 4) 이상으로 사용해야 한다. (Microsoft가 WIF 지원을 위해 업데이트함).</li>
</ul>
</li>
<li><p><span style="color: indianred"><strong>환경 변수 설정 (가장 중요):</strong></span></p>
<ul>
<li><p>테라폼이 시크릿 키를 찾지 않고 OIDC 토큰을 사용하도록 환경 변수를 명시해야 한다.</p>
</li>
<li><p><code>ARM_USE_OIDC = true 또는 AZURE_RM_USE_AZURE_AD = true</code></p>
</li>
</ul>
</li>
</ol>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine4-정리span"><span style='background-color: MediumAquamarine'>4. 정리</span></h2>
<hr>

<ul>
<li><p><span style="color: indianred"><strong>WIF 도입의 의의:</strong></span> 기존 Secret 기반 인증의 보안 취약점과 관리 부담을 해소하기 위해 OIDC 기반의 <strong><code>Workload Identity Federation</code></strong>을 도입하여 암호 없는 인증 체계를 구축한다.</p>
</li>
<li><p><span style="color: indianred"><strong>자동화의 효율성:</strong></span> Azure AD(신분증 발급)와 Azure DevOps(신분증 사용) 간의 복잡한 수동 연결 과정을 Terraform으로 일원화하여 설정 오류를 줄이고 배포 속도를 높인다.</p>
</li>
<li><p><span style="color: indianred"><strong>권한 분리의 중요성:</strong></span> 인증 설정 후에도 실제 인프라 제어(Contributor)와 상태 파일 관리(Storage Blob Data Contributor)를 위한 권한을 명확히 구분하여 할당해야 한다.</p>
</li>
<li><p><span style="color: indianred"><strong>실전 적용 포인트:</strong></span> 실제 파이프라인 적용 시에는 Terraform Task v4 이상 사용과 OIDC 환경 변수 활성화(<code>ARM_USE_OIDC = true</code>)가 필수적이다.</p>
</li>
</ul>
<p><span style="color: indianred"></span>
<span style="color: SlateBlue"></span></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[90DaysOfDevOps (Day 73)]]></title>
            <link>https://velog.io/@taekyu_/90DaysOfDevOps-Day-73-gtqd7z93</link>
            <guid>https://velog.io/@taekyu_/90DaysOfDevOps-Day-73-gtqd7z93</guid>
            <pubDate>Mon, 19 Jan 2026 02:44:40 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>해당 스터디는 90DaysOfDevOps
<a href="https://github.com/MichaelCade/90DaysOfDevOps">https://github.com/MichaelCade/90DaysOfDevOps</a>
를 기반으로 진행한 내용입니다.</strong></p>
</blockquote>
<p>** Day 73 - Introducing the Terraform Test Framework **</p>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine1-iac-테스트span"><span style='background-color: MediumAquamarine'>1. IaC 테스트?</span></h2>
<hr>

<p><strong>Terraform 1.6 및 OpenTofu 1.6 버전부터 테라폼 내에 기본적으로 내장된 테스트 프레임워크가 도입되었다.</strong> </p>
<p>이전에는 IaC의 통합 및 단위 테스트를 위해 TerraTest(Go 언어 기반)나 Kitchen-Terraform(Ruby 기반)과 같은 서드파티 도구를 사용해야 했지만, <span style="color: indianred"><strong>이제는 <code>terraform test</code> 명령어를 통해 테라폼 고유 문법인 HCL만으로 테스트를 수행할 수 있게 되었다.</strong></span></p>
<hr>
<p>인프라 엔지니어 역시 소프트웨어 개발 프로세스의 일부이며, 작성한 코드가 의도대로 작동하는지 검증할 필요가 있다. </p>
<p>*<em>하지만 테라폼은 일반적인 애플리케이션 코드와는 테스트 방식이 다르다. *</em></p>
<p><span style="color: indianred"><strong>테라폼 자체의 내부 함수나 바이너리 동작은 우리가 테스트할 영역이 아니다. (HashiCorp의 몫)</strong></span>
<img src="https://velog.velcdn.com/images/taekyu_/post/ebd91181-9a87-4d98-a385-1073f9abf507/image.png" alt=""></p>
<p><strong>그렇다면, 인프라 엔지니어는 어떤 영역을 검증해야할까?</strong></p>
<ol>
<li><p><span style="color: SlateBlue"><strong>기본 유효성(Basic Validity):</strong></span></p>
<ul>
<li><p>구문이 올바른가? 논리적으로 파싱 되는가?</p>
</li>
<li><p>인자타입이 맞고, 필수 속성이 존재하는가?</p>
</li>
<li><p><span style="color: indianred"><strong>해결:</strong></span> 이는 기존의 <code>terraform validate</code> 명령어로 충분히 검증 가능하다.</p>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>단위 테스트(Unit Testing - Rendering):</strong></span></p>
<ul>
<li><p>주어진 입력값에 따라 Configuration이 예상대로 렌더링되는가?</p>
</li>
<li><p>조건부 로직이나 함수가 의도대로 작동하는가?</p>
</li>
<li><p>잘못된 입력이 들어왔을 때 적절히 차단하는가?</p>
</li>
<li><p><span style="color: indianred"><strong>해결:</strong></span> <strong><code>테라폼 테스트 프레임워크의 plan 모드</code></strong>를 주로 사용한다.</p>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>통합 테스트(Integration Testing - Functionality):</strong></span></p>
<ul>
<li><p>실제 배포된 인프라가 예상대로 작동하는가? (예: 웹사이트가 200 OK를 반환하는가?)</p>
</li>
<li><p>네트워크 라우팅이나 방화벽 규칙이 올바르게 적용되었는가?</p>
</li>
<li><p><span style="color: indianred"><strong>해결:</strong></span> <strong><code>테라폼 테스트 프레임워크의 apply 모드</code></strong>를 사용한다.</p>
</li>
</ul>
</li>
</ol>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine2-terraform-test-framework-기본-구조span"><span style='background-color: MediumAquamarine'>2. Terraform Test Framework 기본 구조</span></h2>
<hr>

<p><strong>테스트 프레임워크는 새로운 언어(Go, Ruby 등)를 배울 필요 없이 기존 HCL 문법을 그대로 사용한다는 점이 가장 큰 장점이다.</strong>
<br></p>
<ul>
<li><p><span style="color: SlateBlue"><strong>파일 명명 규칙 및 위치</strong></span></p>
<ul>
<li><p><span style="color: indianred"><strong>디렉터리:</strong></span> 보통 tests 폴더 내에 위치시킴.</p>
</li>
<li><p><span style="color: indianred"><strong>확장자:</strong></span> <code>*.tftest.hcl</code> (또는 JSON 형식의 <code>*.tftest.json</code>)</p>
<br>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>기본 문법 구조</strong></span></p>
<p><strong>테스트 파일은 하나 이상의 run 블록으로 구성된다.</strong></p>
<pre><code class="language-python">run &quot;테스트_이름&quot; {
  command = plan  # 또는 apply (기본값은 apply)

  # 변수 주입 (Mocking Input)
  variables {
    input_var = &quot;value&quot;
  }

  # 검증 로직
  assert {
    condition     = &lt;조건식&gt;
    error_message = &quot;실패 시 출력할 메시지&quot;
  }
}</code></pre>
<ul>
<li><p><span style="color: indianred"><strong>run 블록:</strong></span> 테스트 실행 단위.</p>
</li>
<li><p><span style="color: indianred"><strong>command:</strong></span> <code>plan</code>(빠름, 리소스 미생성) or <code>apply</code>(느림, 실제 리소스 생성)</p>
</li>
<li><p><span style="color: indianred"><strong>assert 블록:</strong></span> 조건이 true면 통과, false면 실패 및 에러 메시지 출력.</p>
</li>
</ul>
</li>
</ul>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine3-단위-테스트-구현-데모span"><span style='background-color: MediumAquamarine'>3. 단위 테스트 구현 데모</span></h2>
<hr>

<p><strong>프레젠테이션에서는 Azure Storage Account에 정적 웹사이트를 배포하는 시나리오를 코드로 구현하였다.</strong></p>
<h3 id="span-stylecolor-slateblue3-1-시나리오span"><span style="color: SlateBlue"><strong>3-1. 시나리오</strong></span></h3>
<ul>
<li><p><span style="color: indianred"><strong>목표:</strong></span> Azure Storage Account 이름 규칙인 소문자만 가능, 특수문자 불가 규칙을 준수하도록 변환 로직을 검증</p>
</li>
<li><p><span style="color: indianred"><strong>로직:</strong></span> 사용자 입력 -&gt; 변환 <code>(특수문자 제거 + &quot;data001&quot; 추가 + 소문자화)</code> -&gt; 기대 결과 <code>(testwebsitenamedata001)</code>.</p>
<br>

</li>
</ul>
<h3 id="span-stylecolor-slateblue3-2-테스트-대상-코드-maintfspan"><span style="color: SlateBlue"><strong>3-2. 테스트 대상 코드 (main.tf)</strong></span></h3>
<p>*<em>먼저, 우리가 검증하고자 하는 테라폼 코드이다. *</em></p>
<p>사용자가 대충 입력한 값을 Azure가 허용하는 형식으로 강제 변환하는 로직이 들어있다.</p>
<pre><code class="language-python"># main.tf (테스트 대상 코드)

variable &quot;website_name&quot; {
  type = string
}

locals {
  # 입력값에서 특수문자 제거, 뒤에 data001 추가, 전체 소문자 변환
  storage_account_name = lower(format(&quot;%sdata001&quot;, replace(var.website_name, &quot;/[^a-zA-Z0-9]/&quot;, &quot;&quot;)))
}

resource &quot;azurerm_storage_account&quot; &quot;example&quot; {
  name = local.storage_account_name
  # ... 기타 설정 ...
}</code></pre>
<p>*<em>위 locals 블록의 <code>storage_account_name</code>은 다음 세 단계의 과정을 거쳐 값을 생성한다. *</em></p>
<p>이 순서가 정확히 작동하는지 확인하는 것이 테스트의 목적이다.</p>
<ol>
<li><p><span style="color: indianred"><strong><code>replace(var.website_name, &quot;/[^a-zA-Z0-9]/&quot;, &quot;&quot;)</code></strong></span>: 정규식을 사용하여 입력 변수인 var.website_name에서 알파벳(a-z, A-Z)과 숫자(0-9)가 아닌 모든 문자(공백, 특수기호 등)를 제거한다.</p>
</li>
<li><p><span style="color: indianred"><strong><code>format(&quot;%sdata001&quot;, ...)</code></strong></span>: 1번에서 정리된 문자열 뒤에 <code>data001</code>이라는 접미사를 붙인다. </p>
</li>
<li><p><span style="color: indianred"><strong><code>lower(...)</code></strong></span>: 마지막으로 문자열 전체를 소문자로 변환한다. 
(Azure Storage Account는 대문자를 허용하지 않기 때문)</p>
</li>
</ol>
<br>

<h3 id="span-stylecolor-slateblue3-3-단위-테스트-코드-testsunittftesthclspan"><span style="color: SlateBlue"><strong>3-3. 단위 테스트 코드 (tests/unit.tftest.hcl)</strong></span></h3>
<p>이제 위 로직이 제대로 작동하는지 확인하는 테스트 코드를 작성한다.</p>
<pre><code class="language-python"># tests/unit.tftest.hcl (단위 테스트 코드)

run &quot;sa_naming_convention_test&quot; {
  command = plan  # 리소스를 실제 생성할 필요 없으므로 plan 사용

  variables {
    website_name = &quot;Test Website Name&quot; # 대문자와 공백이 포함된 입력
  }

  assert {
    # 정규식을 사용하여 변환된 이름이 예상 패턴과 일치하는지 확인
    condition     = can(regex(&quot;^testwebsitenamedata001$&quot;, local.storage_account_name))
    error_message = &quot;스토리지 계정 이름이 예상대로 변환되지 않았습니다.&quot;
  }
}</code></pre>
<ol>
<li><p><span style="color: indianred"><strong><code>command = plan</code>의 의미:</strong></span></p>
<ul>
<li><p>해당 테스트는 실제 클라우드 리소스를 생성할 필요가 없다. </p>
</li>
<li><p>테라폼이 내부적으로 계산(Plan)만 수행하여 local 값이 어떻게 계산되는지만 확인하면 되기 때문에 plan 모드를 사용하여 속도가 매우 빠르다.</p>
</li>
</ul>
</li>
<li><p><span style="color: indianred"><strong>테스트 시나리오 (입력 vs 기대값):</strong></span></p>
<ul>
<li><p><strong>입력 <code>(variables)</code>:</strong> &quot;Test Website Name&quot;이라는 값을 넣었다. 여기에는 대문자와 공백이 포함되어 있어, 그대로 쓰면 Azure에서 에러가 난다.</p>
</li>
<li><p><strong>기대 결과:</strong> main.tf의 로직을 통과하면 공백이 사라지고, 소문자로 바뀌고, 접미사가 붙어 <code>testwebsitenamedata001</code>이 되어야 한다.</p>
</li>
</ul>
</li>
<li><p><span style="color: indianred"><strong>검증 방법 :</strong></span></p>
<ul>
<li><p>plan 단계가 끝나면 Terraform은 메모리 상에 <code>local.storage_account_name</code>값을 가지고 있다.</p>
</li>
<li><p><code>regex(&quot;^testwebsitenamedata001$&quot;, ...)</code> 구문을 통해 계산된 값이 정확히 우리가 기대한 문자열과 일치하는지 비교한다.</p>
</li>
<li><p>일치하면 true를 반환하여 Pass, 일치하지 않으면 error_message를 출력하며 Fail 처리된다.</p>
</li>
</ul>
</li>
</ol>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine4-실패-케이스-테스트-데모span"><span style='background-color: MediumAquamarine'>4. 실패 케이스 테스트 데모</span></h2>
<hr>

<p>성공하는 케이스만 테스트하는 것은 반쪽짜리 테스트다. </p>
<p><strong>해당 데모는 &quot;잘못된 입력이 들어왔을 때, 내 코드가 이를 적절히 막아내는가?&quot;를 확인하는 과정이다.</strong>
<br></p>
<h3 id="span-stylecolor-slateblue4-1-유효성-검사-코드-variablestfspan"><span style="color: SlateBlue"><strong>4-1. 유효성 검사 코드 (variables.tf)</strong></span></h3>
<pre><code class="language-python">variable &quot;website_name&quot; {
  type = string

  # 입력값 제한 로직
  validation {
    condition     = length(var.website_name) &lt;= 17
    error_message = &quot;웹사이트 이름은 17자 이하여야 합니다.&quot;
  }
}</code></pre>
<ul>
<li><p><span style="color: indianred"><strong>condition:</strong></span> 사용자가 입력한 <code>website_name</code>의 길이가 17자보다 작거나 같은지(&lt;=) 확인한다.</p>
</li>
<li><p><span style="color: indianred"><strong>이유:</strong></span> </p>
<ul>
<li><p>Azure Storage Account 이름은 최대 24자이다. </p>
</li>
<li><p>앞서 진행한 데모의 로직에서 뒤에 <code>data001(7자)</code>을 강제로 붙이기 때문에, 사용자가 입력할 수 있는 최대 글자 수는 24 - 7 = 17자가 된다.</p>
</li>
</ul>
</li>
<li><p><span style="color: indianred"><strong>기대 결과:</strong></span> 이 조건이 false가 되면 테라폼은 배포를 중단하고 error_message를 띄운다.</p>
<br>

</li>
</ul>
<h3 id="span-stylecolor-slateblue4-2-실패-테스트-코드-testsunittftesthclspan"><span style="color: SlateBlue"><strong>4-2. 실패 테스트 코드 (tests/unit.tftest.hcl)</strong></span></h3>
<pre><code class="language-python">run &quot;length_validation_test&quot; {
  command = plan

  # 1. 고의로 잘못된 값 입력
  variables {
    website_name = &quot;ThisNameIsWayTooLongForAzure&quot; # 30자 정도 되는 긴 문자열
  }

  # 2. 실패 기대 선언
  expect_failures = [
    var.website_name
  ]
}</code></pre>
<ol>
<li><p><span style="color: indianred"><strong>고의적인 오류 주입:</strong></span></p>
<ul>
<li><p><code>website_name</code> 변수에 17자를 훌쩍 넘기는 긴 문자열을 입력했다. </p>
</li>
<li><p>정상적인 상황이라면 Terraform은 여기서 에러를 뱉어야 한다.</p>
</li>
</ul>
</li>
<li><p><span style="color: indianred"><strong><code>expect_failures</code>의 역할:</strong></span></p>
<ul>
<li><p>보통 테스트 중에 에러가 나면 테스트는 실패로 간주된다. </p>
</li>
<li><p>하지만 <span style="color: indianred"><strong>해당 블록은 &quot;에러가 나는 것이 정상이다&quot;라고 테라폼에게 알려주는 것이다.</strong></span></p>
</li>
<li><p>Terraform은 <code>var.website_name</code>의 <code>validation</code> 블록에서 에러가 발생하는지 지켜본다.</p>
</li>
<li><p><span style="color: indianred"><strong>에러 발생 시:</strong></span> 유효성 검사가 잘 작동한다고 판단하여 테스트를 Pass 시킨다.</p>
</li>
<li><p><span style="color: indianred"><strong>에러 미발생 시:</strong></span> 유효성 검사가 고장 났다라고 판단하여 테스트를 Fail 시킨다.</p>
</li>
</ul>
</li>
</ol>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine5-통합-테스트-구현-상세-분석span"><span style='background-color: MediumAquamarine'>5. 통합 테스트 구현 상세 분석</span></h2>
<hr>

<p><strong>통합 테스트는 단위 테스트와 달리 실제 배포(apply)를 수행한다.</strong></p>
<p>해당 과정은 코드상의 논리가 아니라 <span style="color: indianred"><strong>&quot;실제 클라우드 환경에서의 동작을 검증&quot;</strong></span>한다.
<br></p>
<h3 id="span-stylecolor-slateblue5-1-통합-테스트-코드-testsintegrationtftesthclspan"><span style="color: SlateBlue"><strong>5-1. 통합 테스트 코드 (tests/integration.tftest.hcl)</strong></span></h3>
<p>해당 테스트는 3단계의 run 블록이 순차적으로 실행되며 상태를 공유한다.
<br></p>
<h4 id="span-stylecolor-slateblue1단계-준비span"><span style="color: SlateBlue">1단계: 준비</span></h4>
<pre><code class="language-python">run &quot;setup&quot; {
  command = apply 

  module {
    source = &quot;./tests/setup&quot; # 난수 생성 모듈
  }
}</code></pre>
<ul>
<li><p><span style="color: indianred"><strong>목적:</strong></span> 매번 테스트할 때마다 고유한 이름을 쓰기 위해 난수를 생성한다.</p>
</li>
<li><p><span style="color: indianred"><strong>방식:</strong></span> apply를 실행하여 <code>random_integer</code> 리소스를 실제로 생성하고, 그 결과값을 Output으로 저장해 둔다.</p>
<br>

</li>
</ul>
<h4 id="span-stylecolor-slateblue2단계-배포span"><span style="color: SlateBlue">2단계: 배포</span></h4>
<pre><code class="language-python">run &quot;deploy_infrastructure&quot; {
  command = apply

  variables {
    # 1단계의 결과값 참조
    website_name = &quot;test-${run.setup.integer}&quot;
  }
}</code></pre>
<ul>
<li><p><span style="color: indianred"><strong>데이터 연결:</strong></span> <code>run.setup.integer</code>를 통해 1단계에서 만든 난수를 가져온다.</p>
</li>
<li><p><span style="color: indianred"><strong>입력값 완성:</strong></span> 입력값은 <code>test-[난수값]</code>이 된다.</p>
</li>
<li><p><span style="color: indianred"><strong>실제 배포:</strong></span> </p>
<ul>
<li><p><code>command = apply</code>이므로, 테라폼은 Azure에 실제로 접속하여 리소스 그룹, 스토리지 계정, 컨테이너, 블롭(웹사이트 파일)을 모두 생성한다. </p>
</li>
<li><p>해당 과정이 에러 없이 끝나야 다음 단계로 넘어간다.</p>
</li>
</ul>
</li>
</ul>
<br>

<h4 id="span-stylecolor-slateblue3단계-검증span"><span style="color: SlateBlue">3단계: 검증</span></h4>
<pre><code class="language-python">run &quot;verify_website_200_ok&quot; {
  command = apply

  variables {
    # 2단계의 배포 결과(URL) 참조
    target_url = run.deploy_infrastructure.homepage_url
  }

  # HTTP 요청 헬퍼 모듈
  module {
    source = &quot;./tests/loader&quot;
  }

  assert {
    # 상태 코드 확인
    condition     = data.http.main.status_code == 200
    error_message = &quot;웹사이트 접속 실패. 코드: ${data.http.main.status_code}&quot;
  }
}</code></pre>
<ul>
<li><p><span style="color: indianred"><strong>URL 획득:</strong></span>  2단계에서 배포된 스토리지 계정의 정적 웹사이트 URL(<code>https://test123data001.web.core.windows.net</code>)을 <code>run.deploy_infrastructure.homepage_url</code>로 가져와 <code>target_url</code> 변수에 넣는다.</p>
</li>
<li><p><span style="color: indianred"><strong>HTTP 요청:</strong></span>  <code>./tests/loader</code> 모듈은 내부적으로 data &quot;http&quot; 리소스를 사용하여 해당 URL로 실제 GET 요청을 보낸다.</p>
</li>
<li><p><span style="color: indianred"><strong>최종 검증 :</strong></span> </p>
<ul>
<li><p>응답받은 HTTP 상태 코드가 200인지 확인한다.</p>
</li>
<li><p>200이면 웹사이트가 정상적으로 배포되어 접속 가능하다는 뜻이므로 테스트 Pass.</p>
</li>
<li><p>404나 403 등이 나오면 배포는 됐지만 설정이 잘못되었다는 뜻이므로 테스트 Fail.</p>
<br>

</li>
</ul>
</li>
</ul>
<hr>
<p><strong>따라서, 정리하자면 사용자가 터미널에서 <code>terraform test</code>를 입력하면 벌어지는 일은 다음과 같다.</strong></p>
<ol>
<li><p>Terraform은 tests 폴더를 스캔하여 파일 이름순(알파벳순)으로 정렬한다. (integration... -&gt; unit...)</p>
</li>
<li><p><span style="color: SlateBlue"><strong>통합 테스트 파일 실행:</strong></span></p>
<ul>
<li><p>난수 생성 (apply) -&gt; 생성된 난수로 리소스 배포 (apply) -&gt; 배포된 URL로 접속 시도 (apply) -&gt; 200 OK 확인.</p>
</li>
<li><p><span style="color: indianred">*<em>테스트가 끝나면 생성했던 리소스들은 자동으로 destroy 되어 정리된다. *</em></span>
(테라폼 테스트의 기본 동작)</p>
</li>
</ul>
</li>
<li><p><span style="color: SlateBlue"><strong>단위 테스트 파일 실행:</strong></span></p>
<ul>
<li><p><span style="color: indianred"><strong>변환 로직 테스트 (Terraform plan):</strong></span> 메모리상에서 계산해보고 정규식 매칭 확인.</p>
</li>
<li><p><span style="color: indianred"><strong>유효성 검사 테스트 (Terraform plan):</strong></span> 일부러 긴 값을 넣어보고 에러가 발생하는지 확인.</p>
</li>
</ul>
</li>
<li><p>모든 과정이 문제없으면 &quot;Success! All tests passed.&quot; 메시지를 출력한다.</p>
</li>
</ol>
<hr>

<h2 id="span-stylebackground-color-mediumaquamarine6-정리span"><span style='background-color: MediumAquamarine'>6. 정리</span></h2>
<hr>

<ul>
<li><p><span style="color: indianred"><strong>테라폼 테스트 프레임워크 도입:</strong></span> 별도의 언어(Go, Ruby) 학습 없이 HCL만으로 단위 및 통합 테스트가 가능해졌다.</p>
</li>
<li><p><span style="color: indianred"><strong>테스트의 목적 분리:</strong></span> </p>
<ul>
<li><p><code>plan 모드</code>는 로직 및 렌더링 검증 <code>Unit Test</code></p>
</li>
<li><p><code>apply 모드</code>는 실제 배포 및 기능 검증 <code>Integration Test</code></p>
</li>
</ul>
</li>
<li><p><span style="color: indianred"><strong>네거티브 테스트 지원:</strong></span> <code>expect_failures</code> 블록을 통해 잘못된 입력에 대한 유효성 검사 로직까지 확실하게 테스트할 수 있다.</p>
</li>
<li><p><span style="color: indianred"><strong>순차적 시나리오 구성:</strong></span> run 블록 간 데이터를 주고받으며 실제 인프라 배포부터 검증까지의 흐름을 자동화할 수 있다.</p>
</li>
<li><p><span style="color: indianred"><strong>결론:</strong></span> IaC도 소프트웨어 개발의 일부인 만큼, <code>terraform test</code>를 도입하여 인프라 코드의 안정성과 신뢰성을 높여야 한다.</p>
</li>
</ul>
<p><span style="color: indianred"></span>
<span style="color: SlateBlue"></span></p>
]]></description>
        </item>
    </channel>
</rss>