<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>보배로움</title>
    <link>https://binux.tistory.com/</link>
    <description>소소한 개발 이야기</description>
    <language>ko</language>
    <pubDate>Fri, 8 May 2026 06:06:40 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>KimDoubleB</managingEditor>
    <image>
      <title>보배로움</title>
      <url>https://tistory1.daumcdn.net/tistory/2923945/attach/9bc637a630f542c2a927cbd02f62adfc</url>
      <link>https://binux.tistory.com</link>
    </image>
    <item>
      <title>How much do language models memorize? - 논문 정리</title>
      <link>https://binux.tistory.com/195</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://arxiv.org/pdf/2505.24832&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://arxiv.org/pdf/2505.24832&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;위 논문을 읽고 내용을 정리했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;LLM은 얼마나 암기하고, 언제부터 이해할까?&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;대형 언어 모델(LLM)이 방대한 데이터를 학습할 때 정보를 그대로 '암기'하는 것인지, 그 속의 원리를 '이해(일반화)'하는 것인지에 대한 근본적인 질문이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&quot;How much do language models memorize?&quot; 논문은 이 질문에 정보 이론을 바탕으로 명확한 경계와 정량적 측정 기준을 제시한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 연구는 LLM의 작동 방식을 더 깊이 이해하고, 프라이버시와 AI 윤리 문제에 대한 중요한 시사점을 제공한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;핵심 개념: 암기와 일반화, 그리고 '용량'의 발견&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 논문은 기존에 막연하게 여겨졌던 '암기'와 '일반화'를 엄밀하게 분리하여 정의하는 것에서 출발한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;암기(Memorization) vs. 일반화(Generalization)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;암기 (Memorization)&lt;/b&gt;: 모델이 훈련 데이터의 특정 샘플을 그대로 저장하는 것이다.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;시험 전 문제의 답만 외우는 것과 같다. 외운 문제는 맞출 수 있지만, 처음 보는 문제는 풀지 못한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;일반화 (Generalization)&lt;/b&gt;: 데이터에 담긴 공통적인 패턴이나 규칙을 학습해, 본 적 없는 새로운 데이터에도 적용하는 능력이다.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;수학 공식을 이해하여 어떤 응용 문제가 나와도 풀어내는 것과 같다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;AI의 핵심 성능은 &lt;b&gt;일반화 능력&lt;/b&gt;에서 나오며, 이 논문은 모델이 언제 암기를 멈추고 일반화를 시작하는지에 주목한다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;최초의 정량적 측정: &lt;b&gt;파라미터당 3.6 비트&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;연구진은 실험을 통해 LLM이 순수하게 정보를 암기하는 데 사용할 수 있는 용량의 한계를 계산했고, 그 결과는 일관적이었다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;LLM은 파라미터 1개당 약 3.6비트(bit)의 정보를 저장할 수 있다.&lt;/b&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이는 모델의 전체 &lt;b&gt;암기 용량&lt;/b&gt;이 &lt;code&gt;(총 파라미터 수) &amp;times; 3.6비트&lt;/code&gt;라는 것을 의미한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;예를 들어, 8억 개의 파라미터를 가진 모델은 약 343MB 분량의 무작위 정보를 완전히 외울 수 있다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;만약 학습 데이터가 &lt;b&gt;이 용량을 초과하면, 모델은 더 이상 개별 정보를 외우는 것을 포기하고 데이터의 패턴을 학습하는 일반화 모드로 전환된다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;이 결과를 얻기 위해 연구진은 일반화 가능성을 원천적으로 차단하는 실험을 설계했다. 즉,&amp;nbsp;&lt;/span&gt;&lt;b&gt;완전히 무작위적인 비트스트링(패턴이 없는 데이터)&lt;/b&gt;을 데이터셋으로 사용했다. 이 데이터셋을 다양한 크기의 트랜스포머 모델에 학습시키면서, 데이터셋의 크기를 점차 늘려 모델이 더 이상 외우지 못하는 포화 지점을 찾았다. 모델이 암기할 수 있는 정보의 총량(비트 수)을 모델의 파라미터 개수로 나누어 파라미터당 암기 용량을 계산했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;모델의 학습 방식: 암기 포화와 일반화의 시작&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;모델의 암기 용량은 데이터셋 크기와 상호작용하며 학습 방식을 결정한다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;모델 용량 &amp;gt; 데이터셋 크기&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;모델은 데이터셋 전체를 암기할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;모델 용량 &amp;lt; 데이터셋 크기&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;모델의 암기 용량이 가득 차 '포화' 상태가 된다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이때부터 모델은 한정된 자원으로 정보를 효율적으로 처리하기 위해, &lt;b&gt;개별 데이터를 외우기보다 공통된 규칙을 찾는 일반화에 집중&lt;/b&gt;한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 전환 과정에서 특정 구간에 모델의 오차율이 다시 한번 감소하는 '이중 하강(double descent)' 현상이 관찰되기도 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;또한, &quot;이 데이터가 학습에 사용되었는가?&quot;를 맞추는 &lt;b&gt;멤버십 추론(Membership Inference)&lt;/b&gt; 공격은 모델 용량이 데이터셋보다 훨씬 클 때만 유효하며, &lt;b&gt;현대 LLM처럼 방대한 데이터를 학습한 경우 사실상 불가능&lt;/b&gt;하다는 점을 실험적으로 증명했다. 데이터가 너무 많아 개별 샘플을 일일이 기억하지 않기 때문이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;이 연구의 의의: 실용적 관점&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이러한 발견은 학술적 의미를 넘어 AI 기술의 여러 측면에 구체적인 영향을 미친다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;1. 개인정보 보호와 AI 윤리&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;모델의 암기 용량을 알면, 훈련 데이터에 포함된 민감한 개인정보가 유출될 위험을 &lt;b&gt;정량적으로 평가&lt;/b&gt;할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;예를 들어, 모델의 총 암기 용량을 훨씬 초과하는 대규모 데이터셋으로 학습시켰다면, 특정 개인정보가 그대로 암기되었을 확률은 거의 0에 수렴한다고 이론적으로 판단할 수 있다. 이는 모델을 배포하거나 공개할 때 중요한 &lt;b&gt;안전 기준&lt;/b&gt;을 제공한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;2. 모델 개발자를 위한 가이드&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;개발자들은 이 원리를 활용해 더 효율적이고 안전한 모델을 설계할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;데이터 설계&lt;/b&gt;: 모델이 암기 대신 일반화를 하도록 유도하려면, 데이터셋의 정보량이 모델의 총 암기 용량보다 충분히 커야 한다는 명확한 가이드라인을 얻을 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;위험 구간 식별&lt;/b&gt;: &quot;모델이 데이터를 통째로 외우기만 하는 위험 구간&quot;과 &quot;본격적으로 지능을 발휘하는 일반화 구간&quot;을 사전에 예측하여 학습 전략을 수립할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;3. AI 성능 평가의 새로운 관점&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;AI의 성능은 결국 &lt;b&gt;일반화 능력&lt;/b&gt;으로 평가된다. 이 연구는 암기와 일반화를 분리할 수 있는 척도를 제공함으로써, 모델의 성능을 더 깊이 있고 다각적으로 평가할 수 있는 새로운 관점을 제시한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;결론&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&quot;How much do language models memorize?&quot; 논문은 LLM이 '단순 암기 기계'인지 '추론하는 지능'인지에 대한 오랜 질문에 정량적 접근법을 제시했다. &lt;b&gt;파라미터당 3.6비트&lt;/b&gt;라는 구체적인 수치를 통해 암기의 물리적 한계를 정의했고, 그 한계를 넘어서는 지점에서 일반화가 시작됨을 밝혔다. 이 연구는 AI의 프라이버시, 안전성, 성능 평가에 있어 중요한 기준을 제시했다는 점에서 의의가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;읽고나니, 아래 논문하고 일맥상통한 부분이 있다.&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://arxiv.org/pdf/2201.02177&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://arxiv.org/pdf/2201.02177&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Development/ETC</category>
      <category>AI</category>
      <category>LLM</category>
      <author>KimDoubleB</author>
      <guid isPermaLink="true">https://binux.tistory.com/195</guid>
      <comments>https://binux.tistory.com/195#entry195comment</comments>
      <pubDate>Sun, 12 Oct 2025 15:15:32 +0900</pubDate>
    </item>
    <item>
      <title>[Tempo] Metrics-generator 알아보기</title>
      <link>https://binux.tistory.com/194</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;연휴가 참 기네요.&lt;br /&gt;&lt;s&gt;할 것도 없고... 그래서&lt;/s&gt; 이번에는 Tempo 내부 컴포넌트를 다뤄보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Tempo에는 (&lt;i&gt;특이하게&lt;/i&gt;) Metrics-generator라는 컴포넌트가 존재합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;963&quot; data-origin-height=&quot;633&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnipoO/btsL3hHTok5/JHd2ltqiJjz5YA0O1qmn2K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnipoO/btsL3hHTok5/JHd2ltqiJjz5YA0O1qmn2K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnipoO/btsL3hHTok5/JHd2ltqiJjz5YA0O1qmn2K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnipoO%2FbtsL3hHTok5%2FJHd2ltqiJjz5YA0O1qmn2K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;627&quot; height=&quot;412&quot; data-origin-width=&quot;963&quot; data-origin-height=&quot;633&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Tracing Backend 역할을 담당하는 Tempo가 Metrics과는 무슨 상관일까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이에 대해 공식문서를 보고 간단히 정리해보고자 합니다. 자세한 내용은 아래 문서를 참조해주세요.&lt;/p&gt;
&lt;figure id=&quot;og_1738242365436&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Metrics-generator |  Grafana Tempo documentation&quot; data-og-description=&quot;Metrics-generator Metrics-generator is an optional Tempo component that derives metrics from ingested traces. If present, the distributor writes received spans to both the ingester and the metrics-generator. The metrics-generator processes spans and writes&quot; data-og-host=&quot;grafana.com&quot; data-og-source-url=&quot;https://grafana.com/docs/tempo/latest/metrics-generator/&quot; data-og-url=&quot;https://grafana.com/docs/tempo/latest/metrics-generator/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Oz9TQ/hyX7X4Lvnu/6pEP0Xsem1cvRHDYh2dV6K/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bSK1Z2/hyX7PeAQ2b/tCN8pm6Ukt2fhdKrOvOhg0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://grafana.com/docs/tempo/latest/metrics-generator/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://grafana.com/docs/tempo/latest/metrics-generator/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Oz9TQ/hyX7X4Lvnu/6pEP0Xsem1cvRHDYh2dV6K/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bSK1Z2/hyX7PeAQ2b/tCN8pm6Ukt2fhdKrOvOhg0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Metrics-generator | Grafana Tempo documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Metrics-generator Metrics-generator is an optional Tempo component that derives metrics from ingested traces. If present, the distributor writes received spans to both the ingester and the metrics-generator. The metrics-generator processes spans and writes&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;grafana.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Metrics-generator&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단하게 한글로 해석해보면 '메트릭 생성기'라고 해석해볼 수 있을 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다는건 Tempo 애플리케이션 자체의 Metric을 나타내는 것일까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 컴포넌트로 따로 구성되어 문서가 정리될 필요도, 이렇게 글을 작성할 필요도 없을 것 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;참고) Tempo 자체의 metrics은 기본적으로 &lt;a href=&quot;https://grafana.com/docs/tempo/latest/api_docs/#endpoints&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;`/metrics` HTTP endpoint로 노출&lt;/a&gt;됩니다.&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Metrics-generator의 주된 목적은 &lt;u&gt;&lt;b&gt;수집된 Trace의 Metric을 수집하기 위함&lt;/b&gt;&lt;/u&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 맨 앞에 Trace가 생략되어 있다고 이해하시면 됩니다. Trace metrics generator !&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 Tempo는 Trace 정보를 저장하고 관리할 뿐, Trace 자체의 Metric을 생성하거나 관리하지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;metrics-generator 컴포넌트를 활성화 하게 되면, 그때부터 Trace의 Metric을 생성, 관리하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;글 처음 부분의 그림에서 보셨듯, 그리고 아래 그림을 통해 알 수 있 metrics-generator를 활성화 하게 되면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그때부터 distributor는 받은 span 정보를 ingester에게 보낼 뿐 아니라 &lt;b&gt;metrics-generator에게도 보내게 됩니다&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1302&quot; data-origin-height=&quot;302&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXvlLk/btsL2mwoPyj/5VVSOjfV2oCKqk8LATVjb1/tfile.svg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXvlLk/btsL2mwoPyj/5VVSOjfV2oCKqk8LATVjb1/tfile.svg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXvlLk/btsL2mwoPyj/5VVSOjfV2oCKqk8LATVjb1/tfile.svg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXvlLk%2FbtsL2mwoPyj%2F5VVSOjfV2oCKqk8LATVjb1%2Ftfile.svg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1302&quot; height=&quot;302&quot; data-origin-width=&quot;1302&quot; data-origin-height=&quot;302&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;(alloy는 opentelemetry collector, mimir는 prometheus로 이해하셔도 무방합니다)&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;metrics-generator는 받은 span 정보를 이용하여 Metric을 생성하고, 이를 metrics 저장소로 전송하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;metrics 저장소로 보낼 때는 &lt;a href=&quot;https://prometheus.io/docs/specs/remote_write_spec/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Prometheus remote write Protocol&lt;/a&gt;을 이용하여 전송하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 기존 Metric에서 기본적으로 이용하는 Pooling 방식이 아닌 직접 Metric 생산지에서 전송하는 방식을 이용하는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기에 사용하고 있는 Metric 저장소(ex. Prometheus, Thanos, VictoriaMetrics 등)에서 Remote write을 제공하지 않거나 옵션이 활성화 되어 있지 않다면 사용이 불가능합니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;최근 Cloud Native 환경의 Infra Application들을 보다보면 Remote Write Protocol을 사용하는 사례가 종종 보이곤 합니다.&lt;br /&gt;&lt;a href=&quot;https://www.yes24.com/Product/Goods/80452497&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;처음에 Prometheus를 학습&lt;/a&gt;할 땐 Pooling 방식을 기본 철학으로 설계되었다고 배웠는데 말이죠.&lt;br /&gt;&lt;br /&gt;Remote Write Protocol은 기존 Prometheus에서 Metric을 Scrap 하는 개념과 조금 다릅니다.&lt;br /&gt;(공식문서에 따르면) Remote Write Protocol의 주요 용도는 모니터링 시스템 간의 메트릭 전송입니다.&lt;br /&gt;개별 애플리케이션이 직접 메트릭을 푸시하는 용도로는 설계되지 않았습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;왜 사용할까? 어떤 정보를 확인할 수 있는가?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 왜 Trace Metric을 생성하고, 저장하는 것일까요? 단순합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Trace에 부가 정보를 제공함으로써, 서비스 상태 정보 Observability에 추가적인 가치를 제공하기 위함입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 Metrics-generator에서는 3가지 Processor를 제공하고 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Service graphs&lt;/li&gt;
&lt;li&gt;Span metrics&lt;/li&gt;
&lt;li&gt;Local blocks&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필요에 따라 &lt;a href=&quot;https://github.com/grafana/helm-charts/blob/main/charts/tempo/values.yaml#L181-L190&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;원하는 Processor만 활성화시켜 사용&lt;/a&gt;할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Service Graph&lt;/b&gt;&lt;/h3&gt;
&lt;figure id=&quot;og_1738249484449&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Service graphs |  Grafana Tempo documentation&quot; data-og-description=&quot;Service graphs A service graph is a visual representation of the interrelationships between various services. Service graphs help you to understand the structure of a distributed system, and the connections and dependencies between its components: Infer th&quot; data-og-host=&quot;grafana.com&quot; data-og-source-url=&quot;https://grafana.com/docs/tempo/latest/metrics-generator/service_graphs/&quot; data-og-url=&quot;https://grafana.com/docs/tempo/latest/metrics-generator/service_graphs/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/oMPI5/hyX7WY7OOp/Q8AdiO0P9kBwEn3v0FBgKK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/cZIWMK/hyX7TH5fCt/ZWVhL47FuVZ7DzdvRURxUk/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bFYhmy/hyX717bTJi/QKqJOqSYDAzCPTjRAC0461/img.png?width=1705&amp;amp;height=939&amp;amp;face=0_0_1705_939&quot;&gt;&lt;a href=&quot;https://grafana.com/docs/tempo/latest/metrics-generator/service_graphs/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://grafana.com/docs/tempo/latest/metrics-generator/service_graphs/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/oMPI5/hyX7WY7OOp/Q8AdiO0P9kBwEn3v0FBgKK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/cZIWMK/hyX7TH5fCt/ZWVhL47FuVZ7DzdvRURxUk/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bFYhmy/hyX717bTJi/QKqJOqSYDAzCPTjRAC0461/img.png?width=1705&amp;amp;height=939&amp;amp;face=0_0_1705_939');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Service graphs | Grafana Tempo documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Service graphs A service graph is a visual representation of the interrelationships between various services. Service graphs help you to understand the structure of a distributed system, and the connections and dependencies between its components: Infer th&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;grafana.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1705&quot; data-origin-height=&quot;939&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dqVXdI/btsL17GjpJA/3jkC1ZxM9GDkHEL7kVqSK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dqVXdI/btsL17GjpJA/3jkC1ZxM9GDkHEL7kVqSK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dqVXdI/btsL17GjpJA/3jkC1ZxM9GDkHEL7kVqSK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdqVXdI%2FbtsL17GjpJA%2F3jkC1ZxM9GDkHEL7kVqSK1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1705&quot; height=&quot;939&quot; data-origin-width=&quot;1705&quot; data-origin-height=&quot;939&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Service Graph는 분산 시스템 구조(MSA)에서 유용하게 활용될 수 있는 Processor 입니다.&lt;br /&gt;단순한 서비스 간의 연결을 보여주는 것을 넘어서 시스템의 구조와 상태를 파악할 수 있도록 돕습니다.&lt;br /&gt;&lt;i&gt;(zipkin, pinpoint를 사용해보셨더라면 위와 비슷한 그래프를 보신 적이 있으실 겁니다)&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3가지 유형을 감지하여 위 그림처럼 시각화하여 보여줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 서비스 간 직접 요청&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 서비스 간의 직접적인 통신을 의미합니다.&lt;br /&gt;발신 Span의 경우 `client`, 수신 Span의 경우 `server` 속성을 가지고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 메시징 시스템을 통한 요청&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Kafka와 같은 메시징 시스템을 통해 서비스들이 통신하는 경우가 해당됩니다.&lt;br /&gt;발신 Span은 `producer`, 수신 Span은 `consumer` 속성을 가지고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 데이터베이스 요청&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스로 요청하는 경우를 의미합니다.&lt;br /&gt;`client` Span 속성 중 `db.name` 혹은 `db.system` 하나가 포함되는 경우, 데이터베이스 요청으로 간주합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Service Graph는 &lt;a href=&quot;https://grafana.com/docs/tempo/latest/metrics-generator/service_graphs/#virtual-nodes&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Virtual Node라는 개념&lt;/a&gt;을 도입하여, 실제로 계측되지 않은 외부 시스템 또한 포현합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Root Span의 `span.kind`가 `server`인 경우
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;계측되지 않은 외부 시스템(ex. FE App)으로 부터 요청이 시작되었음을 의미합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;`server` Span에 매칭되는 `client` Span이 없지만, `peer` 속성을 가진 Span이 있는 경우
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;계측되지 않은 외부 서비스로의 호출을 의미합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Span Metrics&lt;/b&gt;&lt;/h3&gt;
&lt;figure id=&quot;og_1738249502390&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Span metrics |  Grafana Tempo documentation&quot; data-og-description=&quot;Span metrics The span metrics processor generates metrics from ingested tracing data, including request, error, and duration (RED) metrics. Span metrics generate two metrics: A counter that computes requestsA histogram that tracks the distribution of durat&quot; data-og-host=&quot;grafana.com&quot; data-og-source-url=&quot;https://grafana.com/docs/tempo/latest/metrics-generator/span_metrics/&quot; data-og-url=&quot;https://grafana.com/docs/tempo/latest/metrics-generator/span_metrics/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/mxMuG/hyX7RwD3We/zmJkmZZsrX6GQkIe8l14cK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/cdami6/hyX7PFFKzE/2vyKvKJEbkskXYyM9vAmdk/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://grafana.com/docs/tempo/latest/metrics-generator/span_metrics/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://grafana.com/docs/tempo/latest/metrics-generator/span_metrics/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/mxMuG/hyX7RwD3We/zmJkmZZsrX6GQkIe8l14cK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/cdami6/hyX7PFFKzE/2vyKvKJEbkskXYyM9vAmdk/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Span metrics | Grafana Tempo documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Span metrics The span metrics processor generates metrics from ingested tracing data, including request, error, and duration (RED) metrics. Span metrics generate two metrics: A counter that computes requestsA histogram that tracks the distribution of durat&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;grafana.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;821&quot; data-origin-height=&quot;180&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bb9JrV/btsL2bICIRh/elwOP7Ly1ueaK14y7BQGc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bb9JrV/btsL2bICIRh/elwOP7Ly1ueaK14y7BQGc1/img.png&quot; data-alt=&quot;https://grafana.com/docs/tempo/latest/getting-started/metrics-from-traces/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bb9JrV/btsL2bICIRh/elwOP7Ly1ueaK14y7BQGc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbb9JrV%2FbtsL2bICIRh%2FelwOP7Ly1ueaK14y7BQGc1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;821&quot; height=&quot;180&quot; data-origin-width=&quot;821&quot; data-origin-height=&quot;180&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://grafana.com/docs/tempo/latest/getting-started/metrics-from-traces/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Span Metrics는 Tracing 데이터로부터 RED (Request, Error, Duration) Metric을 생성할 수 있는 Processor 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요청을 계산하는 Counter와 요청의 지속시간 분포를 추적하는 Histogram 같은 Tracing의 핵심적인 Metric 정보를 제공하여 전체적인 서비스의 상태를 추적하는데 큰 도움을 받을 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로, Span Metrics의 중요한 특징 중 하나는 &lt;b&gt;&lt;a href=&quot;https://grafana.com/docs/grafana/next/fundamentals/exemplars/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Exemplars&lt;/a&gt;와의 통합&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Examplars는 특정 시간 간격에서 측정된 대표적인 Trace를 의미하며, Metric과 Trace가 Metric generator를 통해 공존하는 상황이기 때문에 자동으로 추가될 수 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;문제 발생 시 해당 Metric과 관련된 구체적인 Trace를 빠르게 찾아볼 수 있게 해주는 강력한 디버깅 도구 입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Local Blocks&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Span 데이터를 일정기간 동안 저장하고, 이를 기반으로 복잡한 계산을 수행할 수 있게 해줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 프로세서는 특별한 Metric API들을 위한 기반이 되며, 이러한 API들을 사용하기 위해서는 반드시 이 프로세서가 활성화되어 있어야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Tempo에서 제공하는 Metrics-generator에 대하여 간단하게 정리해보았는데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 제공되는 각 Processor마다의 상세 문서에서 더 자세한 내용들을 다루고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저도 다 보지는 않았지만 각 기능들에 대한 자세한 설명과 더불어 Grafana에서 어떻게 활용할 수 있는지 다루고 있어, 사용 예정에 있다면 한 번 살펴보면 좋을 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;긴 글 읽어주셔서 감사합니다.&lt;/p&gt;</description>
      <category>Development</category>
      <category>grafana</category>
      <category>metric generator</category>
      <category>service graph</category>
      <category>span metrics</category>
      <category>tempo</category>
      <category>trace metric</category>
      <category>메트릭 생성기</category>
      <category>서비스 그래프</category>
      <category>템포</category>
      <category>트레이스 메트릭</category>
      <author>KimDoubleB</author>
      <guid isPermaLink="true">https://binux.tistory.com/194</guid>
      <comments>https://binux.tistory.com/194#entry194comment</comments>
      <pubDate>Fri, 31 Jan 2025 00:42:14 +0900</pubDate>
    </item>
    <item>
      <title>[Loki] 구성 요소로 보는 Loki Architecture</title>
      <link>https://binux.tistory.com/193</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;연휴에 Loki 구조에 대해 학습하며 간단하게 정리한 내용이 있어 공유해보고자 합니다.&lt;br /&gt;아무런 이해 없이 PoC하며 여러 문서들을 살펴보고 처음 정리해 본 내용으로서 부족한 부분이 많습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;더 자세히 살펴보고 싶다면, 아래 공식문서들을 참조해보시면 좋을 것 같습니다.&lt;/p&gt;
&lt;figure id=&quot;og_1738238244475&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Loki architecture |  Grafana Loki documentation&quot; data-og-description=&quot;Loki architecture Grafana Loki has a microservices-based architecture and is designed to run as a horizontally scalable, distributed system. The system has multiple components that can run separately and in parallel. The Grafana Loki design compiles the co&quot; data-og-host=&quot;grafana.com&quot; data-og-source-url=&quot;https://grafana.com/docs/loki/latest/get-started/architecture/&quot; data-og-url=&quot;https://grafana.com/docs/loki/latest/get-started/architecture/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/pbcGK/hyX73w8YGQ/lZO7vqSWKpcKq7cSXPMuQ0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/SRkQi/hyX7P6GvQa/BW0dR6PtgszbIWBLkPOqsk/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://grafana.com/docs/loki/latest/get-started/architecture/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://grafana.com/docs/loki/latest/get-started/architecture/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/pbcGK/hyX73w8YGQ/lZO7vqSWKpcKq7cSXPMuQ0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/SRkQi/hyX7P6GvQa/BW0dR6PtgszbIWBLkPOqsk/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Loki architecture | Grafana Loki documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Loki architecture Grafana Loki has a microservices-based architecture and is designed to run as a horizontally scalable, distributed system. The system has multiple components that can run separately and in parallel. The Grafana Loki design compiles the co&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;grafana.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;figure id=&quot;og_1738238271303&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Loki components |  Grafana Loki documentation&quot; data-og-description=&quot;Loki components Loki is a modular system that contains many components that can either be run together (in &amp;ldquo;single binary&amp;rdquo; mode with target all), in logical groups (in &amp;ldquo;simple scalable deployment&amp;rdquo; mode with targets read, write, backend), or individ&quot; data-og-host=&quot;grafana.com&quot; data-og-source-url=&quot;https://grafana.com/docs/loki/latest/get-started/components/&quot; data-og-url=&quot;https://grafana.com/docs/loki/latest/get-started/components/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/GFHMA/hyX7ZBvrAP/62H8SxBCRe5bLkUkN1p6b1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/b98csK/hyX7UfQjc2/Z7iayyNKrl0BCAg9tyt8Wk/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://grafana.com/docs/loki/latest/get-started/components/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://grafana.com/docs/loki/latest/get-started/components/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/GFHMA/hyX7ZBvrAP/62H8SxBCRe5bLkUkN1p6b1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/b98csK/hyX7UfQjc2/Z7iayyNKrl0BCAg9tyt8Wk/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Loki components | Grafana Loki documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Loki components Loki is a modular system that contains many components that can either be run together (in &amp;ldquo;single binary&amp;rdquo; mode with target all), in logical groups (in &amp;ldquo;simple scalable deployment&amp;rdquo; mode with targets read, write, backend), or individ&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;grafana.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Loki Architecture&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로키의 내부 구조를 살펴보면 아래와 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;200&quot; data-origin-height=&quot;150&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Vfw1O/btsL1z3Q1xS/EE5TzuOUh06kAkhzz2sIE0/tfile.svg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Vfw1O/btsL1z3Q1xS/EE5TzuOUh06kAkhzz2sIE0/tfile.svg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Vfw1O/btsL1z3Q1xS/EE5TzuOUh06kAkhzz2sIE0/tfile.svg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVfw1O%2FbtsL1z3Q1xS%2FEE5TzuOUh06kAkhzz2sIE0%2Ftfile.svg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;525&quot; data-origin-width=&quot;200&quot; data-origin-height=&quot;150&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음 로키의 구조에 대해 생각했을 땐 로키라는 애플리케이션이 있고 &lt;br /&gt;내부에 멀티 모듈처럼 여러 코드 컴포넌트들이 나뉘어져 소통하는 것으로 이해했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 이해도 틀린 것은 아닙니다. 하나의 모놀리틱으로 배포가 가능하니 말이죠.&lt;br /&gt;하지만, Loki 배포 방법에서 볼 수 있듯 MSA 처럼 &lt;b&gt;모듈 별 Replicas를 다르게해서 배포가 가능&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;즉, Distributor는 3개의 Replicas를 두고, Query Frontend는 1개의 Replicas를 두는 것이 가능합니다.&lt;br /&gt;(&lt;i&gt;Loki의 배포방법에 대해서는 다음 글에서 정리해보겠습니다&lt;/i&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;이러한 특징은 대규모 환경에서는 참 중요합니다. &lt;br /&gt;&lt;b&gt;리소스 부족에 따라 불필요하게 모든 컴포넌트의 Replicas를 늘릴 필요 없이, &lt;br /&gt;적절히 필요한 컴포넌트의 Replicas만 늘려 비용 최적화를 이뤄낼 수 있습니다&lt;/b&gt; (&lt;i&gt;MSA 구조의 장점과 같습니다&lt;/i&gt;).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 점을 염두해두고 Component 들의 특성들을 이해하시면 좋습니다.&lt;br /&gt;상황에 따라 어떤 Component를 Scale-out하고, Scale-in 할지 결정하는데 도움이 될 것 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 위 Architecture에서 각 Component 들의 역할에 대해 간단히 살펴보겠습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Distributor (분배기)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Distributor는 Loki의 쓰기 경로에서 첫 번째로 만나는 핵심 컴포넌트입니다. &lt;br /&gt;&lt;b&gt;클라이언트(fluentd, logstash, server application 구현체 등)로부터 들어오는 모든 로그 데이터를 처리&lt;/b&gt;하는데, 이때 여러 가지 중요한 단계를 거치게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 번째로 유효성 검사(Validation)를 수행합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;들어오는 각 스트림이 올바른지, 설정된 테넌트(또는 전역) 제한 내에 있는지 확인합니다. Prometheus 형식의 라벨인지, 타임스탬프가 적절한지, 로그 라인의 길이는 제한 내인지 등을 검사하죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 번째로 전처리 과정(Preprocessing)에서는 라벨을 정규화합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 {foo=&quot;bar&quot;, bazz=&quot;buzz&quot;}와 {bazz=&quot;buzz&quot;, foo=&quot;bar&quot;}를 동일하게 취급할 수 있도록 라벨을 정렬하는 거죠. 이렇게 하면 캐싱과 해싱을 결정적으로 수행할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세 번째로 Rate limiting을 수행하는데, 이는 테넌트별 최대 데이터 수집 속도를 제어합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체 클러스터 레벨에서 설정된 제한을 현재 활성화된 distributor 수로 나누어 관리하는데, 이렇게 하면 distributor를 스케일링해도 제한이 적절히 조정됩니다. &lt;br /&gt;예를 들어 테넌트 A에 10MB 제한이 있고 distributor가 10개라면, 각 distributor는 1MB/s까지 허용합니다. 나중에 큰 테넌트가 추가되어 distributor를 10개 더 추가하면, 테넌트 A의 제한은 distributor당 500KB/s로 자동 조정되죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 검증된 데이터는 설정된 복제 계수/replication_factor(보통 3)에 따라 여러 ingester로 전달됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 &lt;a href=&quot;https://binux.tistory.com/119&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Consistent hashing&lt;/a&gt;을 사용해 데이터를 분산시키는데, 각 스트림(특정 라벨셋을 가진 로그들의 집합)에 대해 라벨을 해시하고 그 값을 사용해 ring에서 replication_factor 수만큼의 ingester를 찾아 데이터를 전송합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 작업들은 모두 stateless하게 수행되어 쉽게 스케일링할 수 있고, ingester에 가해지는 부하를 분산시킬 수 있습니다. 또한 이런 방식으로 DoS 공격으로부터도 보호할 수 있죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 distributor 앞에는 로드 밸런서가 있어야 하는데, Kubernetes에서는 서비스 로드 밸런서가 이 역할을 담당합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Ingester (수집기)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ingester는 distributor로부터 받은 &lt;b&gt;로그 데이터를 메모리에서 관리하고 장기 저장소로 보내는 역할&lt;/b&gt;을 합니다. &lt;br /&gt;스트림을 받으면 이를 메모리상의 여러 &quot;청크(chunks)&quot;로 구성하는데, 이 청크들은 정해진 간격으로 저장소로 플러시됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;청크는 세 가지 경우에 압축되고 읽기 전용으로 표시됩니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;현재 청크가 용량(설정 가능)에 도달했을 때&lt;/li&gt;
&lt;li&gt;너무 오랫동안 업데이트되지 않았을 때&lt;/li&gt;
&lt;li&gt;플러시가 발생할 때&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;청크가 읽기 전용이 되면 새로운 쓰기 가능한 청크가 그 자리를 대체합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ingester는 자신의 상태를 lifecycler를 통해 관리하는데, 다섯 가지 상태가 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;PENDING: 다른 ingester로부터 핸드오프를 기다리는 상태 (레거시 모드)&lt;/li&gt;
&lt;li&gt;JOINING: ring에 토큰을 삽입하고 초기화하는 상태&lt;/li&gt;
&lt;li&gt;ACTIVE: 완전히 초기화된 상태로 읽기와 쓰기 요청을 모두 처리&lt;/li&gt;
&lt;li&gt;LEAVING: 종료 중인 상태로 읽기 요청만 처리&lt;/li&gt;
&lt;li&gt;UNHEALTHY: 하트비트 실패로 distributor가 설정한 상태&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 손실 방지를 위해 WAL(Write Ahead Log)을 지원하며, 이는 복제 기능과 함께 작동하면 더욱 안전합니다.&lt;br /&gt;갑자기 프로세스가 중단되더라도 WAL을 통해 데이터를 복구할 수 있죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 타임스탬프 순서를 검증하여 로그가 시간순으로 들어오는지 확인합니다. out-of-order 쓰기를 허용하도록 설정할 수도 있습니다.&lt;br /&gt;동일한 나노초 타임스탬프를 가진 로그의 경우, 내용이 완전히 동일하다면 중복으로 간주하여 무시하고, 내용이 다르다면 허용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Query Frontend (쿼리 프론트엔드)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Query Frontend는 &lt;b&gt;Loki의 읽기 경로를 최적화하는 선택적 컴포넌트&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 컴포넌트가 배치되면 모든 쿼리 요청은 먼저 Query Frontend로 전달되어야 하며, 실제 쿼리 실행은 여전히 Querier가 담당합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Query Frontend는 내부적으로 쿼리를 조정하고 큐에 보관합니다. 이때 Querier들은 마치 작업자처럼 동작하면서 이 큐에서 작업을 가져가 실행하고, 결과를 다시 Query Frontend로 반환하여 집계가 이뤄집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 위해 Querier들은 설정에서 Query Frontend의 주소를 알고 있어야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 Query Frontend는 큰 쿼리를 여러 개의 작은 쿼리로 분할하여 병렬로 실행합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 여러 날에 걸친 큰 쿼리가 들어오면 이를 일단위로 나누어 여러 Querier에 분산시키고, 그 결과를 다시 모아서 제공하는 식입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하면 단일 Querier의 메모리 부족 문제를 방지하고 쿼리 실행 속도도 높일 수 있습니다.&lt;br /&gt;추가적으로 여러 캐싱 기능들도 제공하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Query Scheduler (쿼리 스케줄러)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Query Scheduler는 Query Frontend보다 더 발전된 형태의 Queuing을 제공하는 선택적 컴포넌트입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Query Frontend가 쿼리를 분할하면, 이 조각들을 Query Scheduler의 내부 메모리 큐로 전달합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Querier들은 이 스케줄러에 연결되어 큐에서 작업을 가져가고 실행한 뒤, 결과를 다시 Query Frontend로 전달합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 &lt;u&gt;각 테넌트별로 별도의 큐를 유지하여 테넌트 간 공정성을 보장하는 것이 특징&lt;/u&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 테넌트 A와 B가 있을 때 각각의 큐를 별도로 관리하므로, 테넌트 A가 많은 쿼리를 보내더라도 테넌트 B의 쿼리 처리가 지연되지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무상태(stateless) 컴포넌트이지만, 내부 메모리 큐를 사용하기 때문에 고가용성을 위해 보통 둘 이상의 복제본을 운영합니다. 대부분의 경우 두 개의 복제본이면 충분합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Querier (질의기)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Querier는 &lt;b&gt;LogQL 쿼리를 실제로 실행&lt;/b&gt;하는 핵심 컴포넌트입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영 모드에 따라 클라이언트의 HTTP 요청을 직접 처리하거나(&quot;Single binary&quot; 모드), Query Frontend&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또는 Query Scheduler로부터 서브쿼리를 받아 처리할 수 있습니다(&quot;Microservice&quot; 모드).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Querier는 두 곳에서 데이터를 가져옵니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;먼저 모든 Ingester에 쿼리하여 아직 저장소로 플러시되지 않은 최신 데이터를 확인하고, 그다음 장기 저장소를 조회하여 과거 데이터를 가져옵니다.&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복제로 인해 동일한 데이터가 여러 번 조회될 수 있는데, Querier는 내부적으로 같은 나노초 타임스탬프, 라벨셋, 로그 메시지를 가진 데이터의 중복을 제거합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Index Gateway (인덱스 게이트웨이)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Index Gateway는 &lt;b&gt;메타데이터 쿼리를 효율적으로 처리하기 위한 특별한 컴포넌트&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 메타데이터 쿼리란 인덱스에서 데이터를 조회하는 쿼리를 의미하는데, 이는 Single Store TSDB나 Single Store BoltDB와 같은 &quot;shipper stores&quot;를 사용할 때만 활용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 컴포넌트의 역할을 이해하기 위해서는 실제 동작 흐름을 살펴보면 좋습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, Query Frontend가 큰 쿼리를 어떻게 나눌지 결정하려면 로그 데이터의 볼륨을 알아야 하는데, 이때 Index Gateway에 로그 볼륨 쿼리를 보냅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 Querier가 특정 쿼리에 필요한 청크들을 찾으려면 먼저 어떤 청크들이 관련이 있는지 알아야 하는데, 이를 위해 Index Gateway에 청크 참조를 요청합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Index Gateway는 두 가지 모드로 운영할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Simple 모드&lt;/b&gt;에서는 각 Index Gateway 인스턴스가 모든 테넌트의 모든 인덱스를 서비스합니다. 이는 구성이 간단하지만 확장성에 제한이 있죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Ring 모드&lt;/b&gt;에서는 consistent hash ring을 사용해 테넌트별 인덱스를 여러 인스턴스에 분산시킵니다. 이렇게 하면 부하를 분산시킬 수 있고, 특정 인스턴스에 문제가 생겨도 다른 인스턴스가 그 역할을 이어받을 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Compactor (압축기)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Compactor는 Loki에서 단일 인스턴스로 운영되는 특별한 컴포넌트입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주된 역할은 두 가지인데, &lt;br /&gt;&lt;b&gt;첫째는 인덱스 파일들을 효율적으로 압축하는 것이고, &lt;br /&gt;&lt;/b&gt;&lt;b&gt;둘째는 로그 보존 정책을 관리하는 것&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;압축 과정을 통해 &lt;u&gt;Ingester들이 생성한 여러 개의 인덱스 파일들을 테넌트와 일자별로 하나의 파일로 통합&lt;/u&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 하루 동안 여러 Ingester가 각각 생성한 인덱스 파일들이 있다면 &lt;u&gt;Compactor는 이들을 하나의 효율적인 일간 인덱스 파일&lt;/u&gt;로 만드는 거죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하면 나중에 인덱스를 조회할 때 여러 파일을 열어볼 필요 없이 하나의 파일만 확인하면 되므로 성능이 크게 향상됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 작업을 위해 Compactor는 정기적으로 저장소에서 파일들을 다운로드하고, 병합하고, 새로운 통합 인덱스를 업로드한 다음 원본 파일들을 정리합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 &lt;u&gt;설정된 보존 기간에 따라 오래된 로그 데이터를 자동으로 삭제하는 역할도 수행&lt;/u&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Ruler (규칙 관리자)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ruler는 Loki에서 규칙과 알림을 관리하는 중요한 컴포넌트입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마치 Prometheus의 규칙처럼, Loki에서도 로그 데이터를 기반으로 특정 조건을 모니터링하고 필요할 때 알림을 발생시킬 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;규칙 설정은 객체 저장소나 로컬 파일시스템에 저장되며, 관리 방법은 두 가지가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ruler API를 통해 프로그래매틱하게 관리하거나, 직접 저장소에 설정 파일을 업로드하는 방식입니다. 이러한 유연성 덕분에 다양한 환경에서 효과적으로 운영할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;`&lt;span style=&quot;color: #454554; text-align: start;&quot;&gt;remote rule evaluation` 기능을 이용하여&lt;/span&gt; Ruler가 규칙 평가를 Query Frontend에 위임할 수도 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하면 Query Frontend가 제공하는 쿼리 분할, 샤딩, 캐싱 등의 장점을 활용할 수 있어 더 효율적인 규칙 평가가 가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Bloom 관련 컴포넌트들 (Experimental feature)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 실험적으로 제공되는 Bloom 관련 컴포넌트들이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이들은 쿼리 성능을 최적화하기 위한 실험적인 기능들을 제공합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Bloom Planner는 싱글톤으로 운영되며 bloom 생성 작업을 계획합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 날짜와 테넌트에 대해 어떤 bloom이 이미 만들어졌는지, 어떤 시리즈가 새로 추가되어야 하는지를 고려하여 작업을 계획하고, 이를 큐에 넣어 Bloom Builder들이 처리할 수 있게 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Bloom Builder는 이 계획된 작업들을 실제로 수행합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그 엔트리의 메타데이터를 분석하여 bloom 블록을 생성하는데, 이 블록들은 하루 단위로 여러 시리즈와 청크들을 포함합니다. 또한 어떤 블록들이 각 시리즈와 TSDB 인덱스 파일에 사용 가능한지 추적하는 메타데이터 파일도 만듭니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Bloom Gateway는 청크 필터링 요청을 처리합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Index Gateway가 쿼리와 관련된 청크들을 찾을 때, Bloom Gateway를 통해 불필요한 청크들을 미리 걸러낼 수 있습니다. 이는 마치 도서관에서 책을 찾을 때 카테고리를 먼저 확인하여 찾아볼 필요 없는 섹션을 제외하는 것과 비슷합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 Loki Architecture와 내부 Components들에 대해 살펴보았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에 이야기드렸듯 내부 구조를 아는 것은 &lt;b&gt;어떻게 동작하는가를 살펴볼 뿐 아니라 배포할 때 어떻게 배포할 지에 영향을 중요한 부분&lt;/b&gt; 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떠한 상황에서 어떤 Component를 Scale-out 할지, Scale-in 할지 고민이 필요하기 때문입니다.&lt;br /&gt;이러한 배포 방법에 대해서는 다음 글에서 정리해보도록 하겠습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;부가적인 내용으로 Tempo도 Loki Components와 유사한 Components를 이용하여 구성되어져 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;943&quot; data-origin-height=&quot;613&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/usr3F/btsL2ljY6AP/sgKIZU2xsbAvzbGyP6UCRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/usr3F/btsL2ljY6AP/sgKIZU2xsbAvzbGyP6UCRk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/usr3F/btsL2ljY6AP/sgKIZU2xsbAvzbGyP6UCRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fusr3F%2FbtsL2ljY6AP%2FsgKIZU2xsbAvzbGyP6UCRk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;943&quot; height=&quot;613&quot; data-origin-width=&quot;943&quot; data-origin-height=&quot;613&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;figure id=&quot;og_1738241155280&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Tempo architecture |  Grafana Tempo documentation&quot; data-og-description=&quot;Scaling your distributed tracing with Grafana Tempo In this demo, we&amp;rsquo;ll show how Grafana Tempo allows you to scale tracing as far as possible with less operational cost and complexity than ever before.&quot; data-og-host=&quot;grafana.com&quot; data-og-source-url=&quot;https://grafana.com/docs/tempo/latest/operations/architecture/&quot; data-og-url=&quot;https://grafana.com/docs/tempo/latest/operations/architecture/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/lgURX/hyX7OGJ1oO/hKhKzkNjHDMZfuAPI0gxBk/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/VntJc/hyX7Yo3153/H7JeKRbwX6SPCaqU1zBmKk/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/Wz0H9/hyX72ydv3V/DIF3aZUVDVIjBfDKsvF6pk/img.png?width=943&amp;amp;height=613&amp;amp;face=0_0_943_613&quot;&gt;&lt;a href=&quot;https://grafana.com/docs/tempo/latest/operations/architecture/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://grafana.com/docs/tempo/latest/operations/architecture/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/lgURX/hyX7OGJ1oO/hKhKzkNjHDMZfuAPI0gxBk/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/VntJc/hyX7Yo3153/H7JeKRbwX6SPCaqU1zBmKk/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/Wz0H9/hyX72ydv3V/DIF3aZUVDVIjBfDKsvF6pk/img.png?width=943&amp;amp;height=613&amp;amp;face=0_0_943_613');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Tempo architecture | Grafana Tempo documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Scaling your distributed tracing with Grafana Tempo In this demo, we&amp;rsquo;ll show how Grafana Tempo allows you to scale tracing as far as possible with less operational cost and complexity than ever before.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;grafana.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름이 같은 Component들이 실제 동작하는 액션은 다를 수 있어도 비슷한 목적을 가진 것을 보실 수 있습니다.&lt;br /&gt;(&lt;i&gt;자세한 동작에 대해서는 위 공식문서를 참조해주세요&lt;/i&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;긴 글 읽어주셔서 감사합니다.&lt;/p&gt;</description>
      <category>Development</category>
      <category>compactor</category>
      <category>distributor</category>
      <category>index gateway</category>
      <category>ingester</category>
      <category>logql</category>
      <category>Loki</category>
      <category>loki architecture</category>
      <category>querier</category>
      <category>ruler</category>
      <category>로키</category>
      <author>KimDoubleB</author>
      <guid isPermaLink="true">https://binux.tistory.com/193</guid>
      <comments>https://binux.tistory.com/193#entry193comment</comments>
      <pubDate>Thu, 30 Jan 2025 21:50:15 +0900</pubDate>
    </item>
    <item>
      <title>서버 성능 테스트 종류 6가지</title>
      <link>https://binux.tistory.com/192</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;k6 문서를 읽다보니 테스트 종류에 대한 글이 눈에 들어왔다.&lt;/p&gt;
&lt;figure id=&quot;og_1737380598597&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Load test types |  Grafana k6 documentation&quot; data-og-description=&quot;Load test types Many things can go wrong when a system is under load. The system must run numerous operations simultaneously and respond to different requests from a variable number of users. To prepare for these performance risks, teams use load testing. &quot; data-og-host=&quot;grafana.com&quot; data-og-source-url=&quot;https://grafana.com/docs/k6/latest/testing-guides/test-types/&quot; data-og-url=&quot;https://grafana.com/docs/k6/latest/testing-guides/test-types/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/xXBV1/hyX4mQTVrp/JIbuY8OeG0rGsPNk7MFA8K/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/NqScl/hyX4tJgUUT/RFsEZRKRFYCEq3Lt5LnR8K/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://grafana.com/docs/k6/latest/testing-guides/test-types/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://grafana.com/docs/k6/latest/testing-guides/test-types/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/xXBV1/hyX4mQTVrp/JIbuY8OeG0rGsPNk7MFA8K/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/NqScl/hyX4tJgUUT/RFsEZRKRFYCEq3Lt5LnR8K/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Load test types | Grafana k6 documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Load test types Many things can go wrong when a system is under load. The system must run numerous operations simultaneously and respond to different requests from a variable number of users. To prepare for these performance risks, teams use load testing.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;grafana.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;360&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cvTbkF/btsLSNBdkMP/XX6HDjxNJv5oaZmjJKwBjK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cvTbkF/btsLSNBdkMP/XX6HDjxNJv5oaZmjJKwBjK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cvTbkF/btsLSNBdkMP/XX6HDjxNJv5oaZmjJKwBjK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcvTbkF%2FbtsLSNBdkMP%2FXX6HDjxNJv5oaZmjJKwBjK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;360&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;360&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버 성능 테스트에도 종류가 여러가지 있음에도 보통 Load Testing만 해왔던 것 같다.&lt;br /&gt;공부하는 김에 한 페이지로 정리하고자 글을 작성했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;테스트마다 짧게 요약한 글이니, 관심이 있으면 그냥 공식문서 전체를 보기 추천한다.&lt;br /&gt;공식문서에는 k6를 이용한 예제 코드를 담고 있다.&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;스모크 테스트 (Smoke test)&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;540&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcOjRP/btsLUXWqLBh/glkMc6rdRBXVuGi49GHB00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcOjRP/btsLUXWqLBh/glkMc6rdRBXVuGi49GHB00/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcOjRP/btsLUXWqLBh/glkMc6rdRBXVuGi49GHB00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcOjRP%2FbtsLUXWqLBh%2FglkMc6rdRBXVuGi49GHB00%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1920&quot; height=&quot;540&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;540&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://grafana.com/docs/k6/latest/testing-guides/test-types/smoke-testing/&quot;&gt;https://grafana.com/docs/k6/latest/testing-guides/test-types/smoke-testing/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;기본적인 시스템의 정상작동 여부를 확인하는 가장 기본적인 테스트&lt;/li&gt;
&lt;li&gt;2-5명의 최소 가상 사용자로 테스트, 30초에서 3분 정도의 짧은 테스트 시간&lt;/li&gt;
&lt;li&gt;목적
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시스템 변경사항 배포 후 기본 검증용으로 활용&lt;/li&gt;
&lt;li&gt;최소 부하에서의 시스템 에러 검출&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;부하 테스트 (Load test)&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;540&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4jY6p/btsLUjlz9fV/S77WKnC64iSeK6JoOrPX1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4jY6p/btsLUjlz9fV/S77WKnC64iSeK6JoOrPX1K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4jY6p/btsLUjlz9fV/S77WKnC64iSeK6JoOrPX1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4jY6p%2FbtsLUjlz9fV%2FS77WKnC64iSeK6JoOrPX1K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1920&quot; height=&quot;540&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;540&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://grafana.com/docs/k6/latest/testing-guides/test-types/load-testing/&quot;&gt;https://grafana.com/docs/k6/latest/testing-guides/test-types/load-testing/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;일반적인 실제 운영환경을 시물레이션하여 시스템의 성능을 측정하기 위한 테스트&lt;/li&gt;
&lt;li&gt;실제 프로덕션 환경의 평균적인 사용자 수와 요청 수준으로 테스트&lt;/li&gt;
&lt;li&gt;전체 테스트 시간의 5~15% 램프업 기간으로 설정. 램프업 후 평균 부하를 램프업 기간의 5배 이상 유지&lt;/li&gt;
&lt;li&gt;목적
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일반적인 부하 상황에서의 시스템 성능 및 리소스 사용량 평가&lt;/li&gt;
&lt;li&gt;램프업 기간 동안의 성능 저하 징후 조기 발견&lt;/li&gt;
&lt;li&gt;시스템 변경 후 성능 표준 충족여부 확인&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;스트레스 테스트 (Stress test)&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;540&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/937zl/btsLSOmEagz/wE96OzNN1k4OwYyJMZk5wk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/937zl/btsLSOmEagz/wE96OzNN1k4OwYyJMZk5wk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/937zl/btsLSOmEagz/wE96OzNN1k4OwYyJMZk5wk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F937zl%2FbtsLSOmEagz%2FwE96OzNN1k4OwYyJMZk5wk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1920&quot; height=&quot;540&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;540&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://grafana.com/docs/k6/latest/testing-guides/test-types/stress-testing/&quot;&gt;https://grafana.com/docs/k6/latest/testing-guides/test-types/stress-testing/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;시스템의 한계를 찾고 성능을 측정하기 위해 평균 이상의 부하를 주는 테스트&lt;/li&gt;
&lt;li&gt;평균보다 높은 부하(50~100% 이상)를 발생&lt;/li&gt;
&lt;li&gt;더 긴 램프업 기간 설정, 부하 테스트보다 더 긴 피크 부하유지 시간 설정&lt;/li&gt;
&lt;li&gt;부하 테스트 이후에 진행하는 것이 일반적 =&amp;gt; 시스템 성능을 파악 후 한계찾기&lt;/li&gt;
&lt;li&gt;목적
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시스템의 최대 수용능력 측정&lt;/li&gt;
&lt;li&gt;과부하 상황에서의 시스템 안정성 검증&lt;/li&gt;
&lt;li&gt;성능 저하 시점과 패턴파악&lt;/li&gt;
&lt;li&gt;자원확장 계획(HPA 등) 수립을 위한 데이터 수집&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;스파이크 테스트 (Spike test)&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;540&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uJqr0/btsLSSpbpBS/XGVsR5UKp1BkKm6gSngAt0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uJqr0/btsLSSpbpBS/XGVsR5UKp1BkKm6gSngAt0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uJqr0/btsLSSpbpBS/XGVsR5UKp1BkKm6gSngAt0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuJqr0%2FbtsLSSpbpBS%2FXGVsR5UKp1BkKm6gSngAt0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1920&quot; height=&quot;540&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;540&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://grafana.com/docs/k6/latest/testing-guides/test-types/spike-testing/&quot;&gt;https://grafana.com/docs/k6/latest/testing-guides/test-types/spike-testing/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;갑작스러운 대규모 트래픽 증가 상황에서의 시스템 반응 테스트&lt;/li&gt;
&lt;li&gt;매우 짧은 시간에 극닥전인 부하 증가와 부하 감소&lt;/li&gt;
&lt;li&gt;광범위한 프로세스보단 특정 핵심 프로세스에만 집중&lt;/li&gt;
&lt;li&gt;목적
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;대규모 이벤트 트래픽 대비, 급격한 부하에서의 시스템 안정성 검증&lt;/li&gt;
&lt;li&gt;긴급 상황에서의 시스템 복구 능력(Failover) 평가&lt;/li&gt;
&lt;li&gt;주요 프로세스 처리능력 확인&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;소크 테스트 (Soak test)&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;540&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFcXeC/btsLUZmqvxd/eJoJ0iHJfQP97RC4qLevK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFcXeC/btsLUZmqvxd/eJoJ0iHJfQP97RC4qLevK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFcXeC/btsLUZmqvxd/eJoJ0iHJfQP97RC4qLevK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFcXeC%2FbtsLUZmqvxd%2FeJoJ0iHJfQP97RC4qLevK0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1920&quot; height=&quot;540&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;540&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://grafana.com/docs/k6/latest/testing-guides/test-types/soak-testing/&quot;&gt;https://grafana.com/docs/k6/latest/testing-guides/test-types/soak-testing/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;장시간 지속적인 부하를 발생시켜 시스템 안정성 테스트&lt;/li&gt;
&lt;li&gt;평균 부하로 장시간(시간~일) 테스트 진행&lt;/li&gt;
&lt;li&gt;일반적인 부하 테스트와 동일하게 램프업/다운&lt;/li&gt;
&lt;li&gt;시스템 리소스 모니터링이 중요&lt;/li&gt;
&lt;li&gt;목적
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시스템 리소스 이상 확인 (Memory leak, Database connection 등)&lt;/li&gt;
&lt;li&gt;장기 운영에서 발생하는 성능 저하 패턴 분석&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;브레이크 포인트 테스트 (Breakpoint test)&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;540&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ymWJD/btsLUDRq76V/99rbSI2UxZOqh2hFyFfi01/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ymWJD/btsLUDRq76V/99rbSI2UxZOqh2hFyFfi01/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ymWJD/btsLUDRq76V/99rbSI2UxZOqh2hFyFfi01/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FymWJD%2FbtsLUDRq76V%2F99rbSI2UxZOqh2hFyFfi01%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1920&quot; height=&quot;540&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;540&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://grafana.com/docs/k6/latest/testing-guides/test-types/breakpoint-testing/&quot;&gt;https://grafana.com/docs/k6/latest/testing-guides/test-types/breakpoint-testing/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;시스템의 최대 한계점을 찾기 위한 테스트&lt;/li&gt;
&lt;li&gt;점진적으로 부하를 증가시켜 시스템 한계에 도달&lt;/li&gt;
&lt;li&gt;임계치 도달 시 자동 중단하거나 어느정도 확인 후 수동 중단 필요&lt;/li&gt;
&lt;li&gt;HPA 같은 탄력적 확장 구조 비활성화 필요&lt;/li&gt;
&lt;li&gt;시스템 실패지점에 대한 정밀 분석&lt;/li&gt;
&lt;li&gt;목적
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시스템의 실제 수용한계 파악&lt;/li&gt;
&lt;li&gt;성능저하 시작지점 확인 및 장애발생 패턴 분석&lt;/li&gt;
&lt;li&gt;시스템 튜닝 포인트 도출&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;k6에서는 6가지로 소개하고 있지만, 사실 어떻게 정의하고 나누느냐에 따라 더 적게 혹은 더 많게 나눠질 것 같다.&lt;br /&gt;&lt;br /&gt;당연하게도 종류에 초점을 맞추지 말고 &quot;내 개발 결과물에 있어 어떤 것을 검증하고 싶은가&quot;에 초점을 맞추고 어떻게 테스트할지 시나리오를 설정하는 것이 중요할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 테스트 종류를 학습하고 k6로 구현함에 있어 &lt;a href=&quot;https://grafana.com/docs/k6/latest/using-k6/scenarios/executors/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Executor&lt;/a&gt;를 유심히 보고 있는데 이후 이것도 정리해봐야겠다.&lt;/p&gt;</description>
      <category>Development/Server</category>
      <category>k6</category>
      <category>k6 testing</category>
      <category>load testing</category>
      <category>test</category>
      <category>test type</category>
      <category>부하 테스트</category>
      <category>서버 성능 테스트</category>
      <category>종류</category>
      <category>테스트</category>
      <category>테스트 종류</category>
      <author>KimDoubleB</author>
      <guid isPermaLink="true">https://binux.tistory.com/192</guid>
      <comments>https://binux.tistory.com/192#entry192comment</comments>
      <pubDate>Mon, 20 Jan 2025 23:00:19 +0900</pubDate>
    </item>
    <item>
      <title>SLI / SLO / SLA</title>
      <link>https://binux.tistory.com/191</link>
      <description>&lt;h3 style=&quot;background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;SLI (Service Level Indicator)&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;서비스 수준을 측정하는 실제 지표 =&amp;gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&quot;무엇을 측정할 것인가?&quot;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Example&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;요청 성공률: (성공한 요청 수 / 전체 요청 수) &amp;times; 100%&lt;/li&gt;
&lt;li&gt;응답시간: API 응답 시간의 p95 값&lt;/li&gt;
&lt;li&gt;시스템 가용성: (전체 시간 - 장애 시간) / 전체 시간 &amp;times; 100%&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;SLO (Service Level Objective)&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;SLI에 대한 목표치 =&amp;gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&quot;어느 수준을 달성할 것인가?&quot;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Example&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;월간 가용성 99.95% 이상 달성&lt;/li&gt;
&lt;li&gt;API 응답시간 p95가 300ms 이하&lt;/li&gt;
&lt;li&gt;분당 에러율 0.1% 미만 유지&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;SLA (Service Level Agreement)&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;서비스 제공자와 고객간의 공식적인 계약 =&amp;gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&quot;고객에게 어떤 서비스 품질을 보장할 것인가?&quot;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;계약&quot;이므로 위반 시 보상조항이 포함됨 (ex.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://aws.amazon.com/ko/s3/sla/&quot;&gt;AWS S3 서비스 수준 계약&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Example&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;월간 가용성 99.9% 보장&lt;/li&gt;
&lt;li&gt;계획된 점검 시간 월 최대 4시간&lt;/li&gt;
&lt;li&gt;SLA 위반 시 월 이용료의 10% 환불&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;결론&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;위 3개를 조합하면 다음과 같이 서비스의 현재, 목표, 계약을 살펴볼 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Example&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Example: 가용성
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SLI: 현재 측정된 가용성 99.97%&lt;/li&gt;
&lt;li&gt;SLO: 내부 목표치 99.95%&lt;/li&gt;
&lt;li&gt;SLA: 고객과의 계약상 보장 99.9%&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Example: 응답시간
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SLI: 현재 측정된 p95 응답시간 280ms&lt;/li&gt;
&lt;li&gt;SLO: 내부 목표치 300ms&lt;/li&gt;
&lt;li&gt;SLA: 고객과의 계약상 보장 500ms&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Example: 결제 서비스
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SLI: 결제 성공률, 평균 처리 시간, p99 응답시간&lt;/li&gt;
&lt;li&gt;SLO: 성공률 99.99%, p99 응답시간 1초 이내&lt;/li&gt;
&lt;li&gt;SLA: 월간 가용성 99.9%, 중대 장애 시 응답시간 30분 이내&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Example: 검색 서비스
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SLI: 검색 응답시간, 검색 정확도, 초당 처리 요청 수&lt;/li&gt;
&lt;li&gt;SLO: p95 응답시간 800ms, 검색 정확도 95%&lt;/li&gt;
&lt;li&gt;SLA: 피크 시간대 초당 1000요청 처리 보장&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;실제로 SLI / SLO / SLA를 정할 땐, 값의 크기가&lt;span&gt;&amp;nbsp;&lt;/span&gt;SLI &amp;gt; SLO &amp;gt; SLA와 같아야 한다.&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SLA보다 SLI / SLO가 작으면, 계약을 안하겠다는 의미이자 서비스 규칙을 지키지 못했으니 보상하겠다는 말이 된다.&lt;/li&gt;
&lt;li&gt;SLO는 목표치이자 SLA를 지키기 위한 수준이라고 볼 수 있다. SLO로 알림을 설정해서 받아보며 SLA를 지키고자 노력해야 할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;모니터링 전략&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SLI 모니터링
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실시간 메트릭 수집&lt;/li&gt;
&lt;li&gt;트렌드 분석&lt;/li&gt;
&lt;li&gt;이상 징후 감지&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;SLO 위반 임박 시
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;원인 분석&lt;/li&gt;
&lt;li&gt;즉각적인 대응&lt;/li&gt;
&lt;li&gt;리소스 스케일링&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;SLA 위반 가능성 발생 시
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;긴급 대응 체계 가동&lt;/li&gt;
&lt;li&gt;고객 커뮤니케이션&lt;/li&gt;
&lt;li&gt;임시 해결책 적용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Development</category>
      <category>monitoring</category>
      <category>SLA</category>
      <category>SLI</category>
      <category>SLO</category>
      <category>모니터링</category>
      <category>슬라</category>
      <category>슬로</category>
      <category>슬리</category>
      <category>전략</category>
      <author>KimDoubleB</author>
      <guid isPermaLink="true">https://binux.tistory.com/191</guid>
      <comments>https://binux.tistory.com/191#entry191comment</comments>
      <pubDate>Sat, 18 Jan 2025 04:35:41 +0900</pubDate>
    </item>
    <item>
      <title>Percentile / 백분위수 (P90, P95, P99)</title>
      <link>https://binux.tistory.com/190</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;메트릭 혹은 성능 테스트 결과를 보다보면, 많이 볼 수 있는 숫자가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;P90, P95, P99&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이 숫자가 의미하는 것은 무엇일까? =&amp;gt; 바로 &lt;b&gt;백분위수(Percentile)&lt;/b&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;백분위 수는 전체 데이터를 순서대로 나열했을 때, &lt;b&gt;특정 위치의 값&lt;/b&gt;을 의미한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;p90은 &lt;b&gt;90번째 백분위수&lt;/b&gt;라는 의미로 전체 데이터 중 &lt;b&gt;90%가 이 값보다 작다는 의미&lt;/b&gt;이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;예를 들어, Resposne time이 p90 = 200ms라면, 전체 요청 중 90%는 200ms보다 빠르게 처리된다는 것.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Percentile / 백분위수의 필요성&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그럼, 왜 p90, p95, p99을 나눠서 볼까?&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;p90: 상위 10%를 제외한, &lt;b&gt;일반적인 상황&lt;/b&gt;의 성능을 보여준다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;p95: 상위 5%를 제외한, &lt;b&gt;조금 더 엄격한 기준&lt;/b&gt;의 성능을 보여준다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;p99: 상위 1%를 제외한, &lt;b&gt;매우 까다로운 기준&lt;/b&gt;의 성능을 보여준다&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좋다 좋아. 근데 왜 평균 값을 이용하지 않고 Percentile(백분위수)를 이용할까?&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;평균값은 Outlier 값에 매우 민감하게 반응&lt;/b&gt;하기 때문이다. 특정 값이 매우 크거나 적으면 평균값도 이동한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;즉, 대부분의 요청은 정상이지만, 한 번의 느리거나 빠른 응답으로 평균이 크게 왜곡될 수 있다는 것이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;백분위수는 이런 Outlier 값에 영향을 받지 않고 &lt;b&gt;실제 사용자 경험을 더 잘 반영&lt;/b&gt;한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;# Example / 예제&lt;br /&gt;Response time: 10ms, 15ms, 20ms, 18ms, 25ms, 1000ms&lt;br /&gt;=&amp;gt; 평균: 181.3 ms&lt;br /&gt;=&amp;gt; p95: 25 ms&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Percentile / 백분위수 모니터링&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Percentile(백분위수)를 통한 모니터링 전략&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;평균값도 의미가 있을 수 있지만, 위에서 말한 평균값의 단점 때문에 모니터링에서는 백분위수를 많이 사용한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;p90, p95, p99 값을 실시간으로 그래프로 모니터링 =&amp;gt; p90/95/99마다 다르게 알림을 설정해서 활용하자.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;p90이 적거나 높아졌다? =&amp;gt; 대부분의 요청이 영향 받은 것&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;p99이 적거나 높아졌다? =&amp;gt; p90은 그대로다? =&amp;gt; &lt;b&gt;상위 9%에서 변화가 감지된 것&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;=&amp;gt; 해당 유저가 어떤 액션을 했을까 추적이 필요 (대규모 업로드 등)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;모든 백분위수가 점진적으로 증가한다?&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;=&amp;gt; 시스템 리소스 부족(memory leak, connection 고갈 등) 의심&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;예를 들어보면, 다음과 같이 모니터링 전략을 잡아볼 수도 있겠다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;p90 &amp;lt; 200ms: 대부분의 사용자가 빠른 응답을 경험&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;p95 &amp;lt; 500ms: 느린 응답(500ms 이상)을 경험하는 사용자를 5% 이하로 제한&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;p99 &amp;lt; 1초: 매우 느린 응답(1s 이상)을 경험하는 사용자를 1% 이하로 제한&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 당연히 애플리케이션 및 API 상황마다 다르므로, &lt;b&gt;기존 결과를 보면서 최적화해 모니터링 전략&lt;/b&gt;을 잡는 것이 좋다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;주요 API별로 따로 모니터링하기&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;로그인 API: p95 &amp;lt; 300ms&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;검색 API: p95 &amp;lt; 800ms 같은 식으로 API 특성에 맞는 목표 설정&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;비즈니스 중요도에 따라 다른 기준 적용&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;결제 관련: p99 기준으로 모니터링&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;일반 조회: p95 기준으로 모니터링&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Development/Server</category>
      <category>monitoring</category>
      <category>P90</category>
      <category>p95</category>
      <category>P99</category>
      <category>percentile</category>
      <category>메트릭</category>
      <category>모니터링</category>
      <category>백분위수</category>
      <category>테스트</category>
      <category>평균</category>
      <author>KimDoubleB</author>
      <guid isPermaLink="true">https://binux.tistory.com/190</guid>
      <comments>https://binux.tistory.com/190#entry190comment</comments>
      <pubDate>Sat, 18 Jan 2025 00:05:04 +0900</pubDate>
    </item>
    <item>
      <title>Trace Sampling / 트레이스 샘플링</title>
      <link>https://binux.tistory.com/189</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Trace를 학습하다보면 &quot;Sampling&quot;, &quot;샘플링&quot;에 대해 필수적으로 알아야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;근데 주변에서 가끔 헷갈려하시는 분들이 있어 글로 좀 정리해보자 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;본 글의 내용은 아래 Opentelemetry 공식문서 글을 참조했다.&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1737027467227&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Sampling&quot; data-og-description=&quot;Learn about sampling and the different sampling options available in OpenTelemetry.&quot; data-og-host=&quot;opentelemetry.io&quot; data-og-source-url=&quot;https://opentelemetry.io/docs/concepts/sampling/&quot; data-og-url=&quot;https://opentelemetry.io/docs/concepts/sampling/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bLbhy5/hyX0sq7rMt/AB6UC9vDGt20QcUzE4uq00/img.png?width=1910&amp;amp;height=1000&amp;amp;face=0_0_1910_1000,https://scrap.kakaocdn.net/dn/lqN8Q/hyX4nhmram/SPXAmK4Gl34F036RKQHKE1/img.png?width=1910&amp;amp;height=1000&amp;amp;face=0_0_1910_1000&quot;&gt;&lt;a href=&quot;https://opentelemetry.io/docs/concepts/sampling/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://opentelemetry.io/docs/concepts/sampling/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bLbhy5/hyX0sq7rMt/AB6UC9vDGt20QcUzE4uq00/img.png?width=1910&amp;amp;height=1000&amp;amp;face=0_0_1910_1000,https://scrap.kakaocdn.net/dn/lqN8Q/hyX4nhmram/SPXAmK4Gl34F036RKQHKE1/img.png?width=1910&amp;amp;height=1000&amp;amp;face=0_0_1910_1000');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Sampling&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Learn about sampling and the different sampling options available in OpenTelemetry.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;opentelemetry.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Sampling? 샘플링?&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1077&quot; data-origin-height=&quot;753&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dXj9Dr/btsLQs32arF/P1JKyuQKjeOviG11UihlQK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dXj9Dr/btsLQs32arF/P1JKyuQKjeOviG11UihlQK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dXj9Dr/btsLQs32arF/P1JKyuQKjeOviG11UihlQK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdXj9Dr%2FbtsLQs32arF%2FP1JKyuQKjeOviG11UihlQK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1077&quot; height=&quot;753&quot; data-origin-width=&quot;1077&quot; data-origin-height=&quot;753&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Sampling / 샘플링&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;모든&amp;nbsp;가시성&amp;nbsp;지표를&amp;nbsp;저장하지&amp;nbsp;않고,&amp;nbsp;대표적인&amp;nbsp;데이터만(대표성을&amp;nbsp;띄는&amp;nbsp;데이터만)&amp;nbsp;저장하는&amp;nbsp;것&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;'대표성'이라는&amp;nbsp;건&amp;nbsp;작은&amp;nbsp;그룹이&amp;nbsp;더&amp;nbsp;큰&amp;nbsp;그룹을&amp;nbsp;정확하게&amp;nbsp;대표할&amp;nbsp;수&amp;nbsp;있다는&amp;nbsp;원칙&amp;nbsp;(위&amp;nbsp;그림이&amp;nbsp;이를&amp;nbsp;잘&amp;nbsp;표현하는&amp;nbsp;그림)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;i&gt;&quot; Sampling 됬어?&quot;&lt;/i&gt; 같은 개념을 헷갈리는 사람들이 있다. 헷갈리지 말자.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Sampled (샘플링 됬다)&lt;/b&gt;: Trace/Span이 전송됨. 전체 데이터의 대표가 된 것&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Not Sampled (샘플링 되지 않았다)&lt;/b&gt;: Trace/Span이 전송/처리되지 않은 것&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;샘플링을 왜 사용할까?&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&quot;비용&quot;과 &quot;접근성/용이성&quot; 측면이 있다. 근데 접근성/용이성도 개발자의 &quot;비용&quot;과 관련이 있으므로 그냥 &quot;비용&quot; 때문에 사용한다라고 볼 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;샘플링은 &quot;비용&quot;을 줄이는 가장 효과적인 방법 중 하나이다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;대용량 시스템에서 잘 만들어진 트레이싱 샘플링 구조에선 1% 그 이하의 샘플링 비율로도 나머지 99% 데이터를 매우 정확하게 대표한다 (최상단의 사진이 이를 표현한다).&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;샘플링이 비용을 줄이기 위한 기능이지만, 사실 새로운 비용을 만들기도 한다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1) Tail Sampling 같이 효과적으로 데이터를 샘플링하는데 드는 직접적인 컴퓨팅 비용 (계산 비용)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2) 더 많은 애플리케이션, 시스템, 데이터가 관련될 때, 효과적인 샘플링 방식을 유지하는데 드는 엔지니어링 비용&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;3) 비효과적인 샘플링 기술로 인해 중요한 정보를 놓치는 간접적인 기회비용&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;샘플링 자체는 데이터를 줄여(대표성 있는 데이터만 저장해) 비용을 줄이는데 효과적이나, 제대로 수행되지 않으면 오히려 예상치 못한 비용이 발생&lt;/b&gt;할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;그럼 무조건 사용해야 할까?&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;샘플링이 필요한 경우는 언제일까?&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;초당 1000개 이상의 Trace를 생성하고 있는 경우&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;대부분의 Trace 데이터가 데이터 변동이 적은 정상 트래픽을 표현하는 경우&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;오류, 높은 지연시간 같이 문제를 나타내는 일반적인 기준이 있는 경우&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;오류, 높은 지연시간 외에 이러한 정보를 표현할 수 있는 도메인 별 기준이 있는 경우&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;데이터 샘플링 할지/말지를 결정할 수 있는 일반적인 규칙이 있는 경우&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;서비스를 구분할 수 있어 고용량/저용량 서비스를 다르게 샘플링 할 수 있는 경우&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;샘플링 되지 않은 데이터를 저비용 저장 시스템으로 라우팅 할 수 있는 경우&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;전체 예산이 제한 적인 경우&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;관찰가능성에 대해 제한된 예산이 있지만&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;효과적인 샘플링에 시간을 투자할 수 있는 경우&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;샘플링이 적합하지 않은 경우도 있다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;매우 적은 Trace 데이터를 생성하고 있는 경우 (초당 수십개 정도)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;관찰가능성을 데이터 집계로만 사용하고자 하는 경우&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;데이터 삭제를 금지하는 규제가 존재하는 경우&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;샘플링 방법&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;샘플링은 크게 2가지 방법으로 나뉜다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;background-color: #ffffff; color: #0e1116;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Head Sampling&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;background-color: #ffffff; color: #0e1116;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Tail Sampling&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Head Sampling&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;가능한 빨리 샘플링 여부를 결정하는 기술&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Trace 전체를 검사하지 않고&lt;/b&gt;, Trace/Span을 샘플링 여부 결정 결정한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;가장 일반적인 Head Sampling은&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px; color: #000000;&quot; href=&quot;https://opentelemetry.io/docs/specs/otel/trace/tracestate-probability-sampling-experimental/#consistent-probability-sampling&quot;&gt;Consistent Probability Sampling&lt;/a&gt;&lt;span style=&quot;background-color: #ffffff; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;이 있으며, &lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;Deterministic Sampling(결정론적 샘플링)이라고도 한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;간단히 설명하면 &lt;/span&gt;&lt;b&gt;Trace ID와 샘플링 하는 비율 기반으로 샘플링 여부를 결정하는 방식&lt;/b&gt;. &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이를 통해 전체 Trace가 누락된 Span 없이 5% 같은 일관된 비율로 샘플링 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;장점을 보면...&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이해 및 구성이 쉽다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;효율적으로 동작한다. Trace 전체를 볼 필요 없으니 계산이 복잡하지 않다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Trace 수집 파이프라인 어디서나 수행이 가능하다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;전체 Trace 데이터를 기반으로 샘플링 결정을 내리는 것이 아니라는 단점&lt;/b&gt;이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;예를 들어, 오류가 있는 모든 Trace는 샘플링 되도록 보장하고 싶어도 할 수 없다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이러한 경우에는 Tail Sampling이 필요함.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Tail Sampling&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;Trace 내의 모든 또는 대부분의 Span을 고려해 샘플링 여부를 결정하는 방식&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;Head Sampling에서는 불가능한 &lt;b&gt;Trace/Span의 정보를 이용하여 특정 기준에 따라 샘플링 여부를 결정&lt;/b&gt;할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1225&quot; data-origin-height=&quot;796&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBnY9g/btsLQGOv3IK/jkoYEPIjzlAyyxYv1morn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBnY9g/btsLQGOv3IK/jkoYEPIjzlAyyxYv1morn1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBnY9g/btsLQGOv3IK/jkoYEPIjzlAyyxYv1morn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBnY9g%2FbtsLQGOv3IK%2FjkoYEPIjzlAyyxYv1morn1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1225&quot; height=&quot;796&quot; data-origin-width=&quot;1225&quot; data-origin-height=&quot;796&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;예시를 보면 이해가 더 쉽다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;오류가 포함된 Trace를 100% 샘플링 하기&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;전체 지연시간 기준으로 어느 이상이 되는 Trace를 샘플링 하기&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Trace 내 하나 이상의 Span에 있는 특정 속성 존재 혹은 값 기준으로 Trace 샘플링 하기 (배포 버전에 맞게 샘플링 등)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;저용량 서비스에서 오는 Trace, 고용량 서비스에서 오는 Trace를 구분해서 샘플링 비율을 다르게 샘플링 하기&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;예시에서 알 수 있듯 Head Sampling보다 훨씬 더 정교하게 샘플링이 가능하다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;샘플링 필요한 대규모 시스템의 경우, 데이터 볼륨/균형을 맞추기 위해 Tail Sampling을 사용하는 것이 거의 항상 필요하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;(당연하지만) 장점만 있지는 않다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;구현의 어려움&lt;/b&gt;: 시스템의 변화에 따라 샘플링 전략도 계속 변화해야 함 (설정하고 잊어버려서는 안됨). 대규모/분산 시스템에서 이러한 전략을 구현하는 규칙도 크고 정교할 수 있음.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;운영의 어려움&lt;/b&gt;: Tail Sampling을 구현하는 컴포넌트는 많은 양의 데이터를 받아들이고 저장할 수 있는 stateful system이여야 함. 트래픽 패턴에 따라 많은 양의 컴퓨팅 노드가 필요할 수 있음. 고로, Tail Sampling 컴포넌트를 모니터링해서 샘플링 로직에 필요한 리소스가 여유로운지 모니터링해야 함.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;관찰가능성을 위해 유료 벤더를 이용하는 경우, 벤더에서 제공하는 Tail Sampling으로 제한될 수 있음.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Tail Sampling과 Head Sampling을 따로 사용해야만 하는 것은 아니다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Telemetry Pipeline이 과부하 되는 것을 방지하기 위해 함께 사용될 수도 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;매우 많은 양의 Trace 데이터를 생성하는 서비스의 경우, &lt;b&gt;먼저 Head Sampling을 통해 Trace를 작은 비율로 줄이고 Telemetry Pipeline에서 Tail Sampling을 이용하여 더 정교한 로직을 통해 Sampling 여부를 결정&lt;/b&gt;할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;추가 내용&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이에 대해서 &lt;a href=&quot;https://github.com/open-telemetry/opentelemetry-collector-contrib&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;OpenTelemetry Collector&lt;/a&gt;에서도 지원한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #0e1116; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/processor/filterprocessor/README.md&quot;&gt;Filter processor&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;- 전달된 정보를 이용해 필터링 여부 결정할 수 있음 (단순 결정)&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/processor/probabilisticsamplerprocessor&quot;&gt;Probabilistic Sampling processor&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;- 퍼센트 정해놓고 샘플링 -&amp;gt; 헤드 샘플링&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/processor/tailsamplingprocessor&quot;&gt;Tail Sampling processor&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;- 테일 샘플링. 복잡한 조건도 가능하고, probabilistic sampling도 가능함.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Development/Server</category>
      <category>head sampling</category>
      <category>OpenTelemetry</category>
      <category>sampling</category>
      <category>span</category>
      <category>tail sampling</category>
      <category>Trace</category>
      <category>샘플링</category>
      <category>테일 샘플링</category>
      <category>트레이스</category>
      <category>헤드 샘플링</category>
      <author>KimDoubleB</author>
      <guid isPermaLink="true">https://binux.tistory.com/189</guid>
      <comments>https://binux.tistory.com/189#entry189comment</comments>
      <pubDate>Fri, 17 Jan 2025 00:02:05 +0900</pubDate>
    </item>
    <item>
      <title>[책] 소프트웨어 엔지니어 가이드북</title>
      <link>https://binux.tistory.com/188</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dZniTC/btsKX8dViQm/Eqk0qUbBiddZuAYHB5qrkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dZniTC/btsKX8dViQm/Eqk0qUbBiddZuAYHB5qrkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dZniTC/btsKX8dViQm/Eqk0qUbBiddZuAYHB5qrkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdZniTC%2FbtsKX8dViQm%2FEqk0qUbBiddZuAYHB5qrkK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;442&quot; height=&quot;589&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;기술은 끊임없이 변화하지만, 성장의 본질은 변하지 않는다&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IT 업계에서 일하면서 이런 책이 진작 있었더라면 하는 아쉬움이 들 정도로 유익한 내용들이 많았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;책 목차&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;책은 총 6부로 구성되어 있습니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1부: 개발자 커리어의 기본 사항&lt;/li&gt;
&lt;li&gt;2부: 유능한 소프트웨어 개발자&lt;/li&gt;
&lt;li&gt;3부: 다재다능한 시니어 엔지니어&lt;/li&gt;
&lt;li&gt;4부: 실용주의 테크리드&lt;/li&gt;
&lt;li&gt;5부: 롤모델로서의 스태프 및 수석 엔지니어&lt;/li&gt;
&lt;li&gt;6부: 결론&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마음에 들었던 점&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;실용적인 조언들&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각종 실전 팁들이 현장감 있게 서술되어 있습니다.&lt;/li&gt;
&lt;li&gt;특히 코드 리뷰, 프로젝트 관리 부분은 바로 적용해볼 수 있는 내용들이 많았어요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;균형 잡힌 시각&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기술적 역량과 소프트 스킬의 균형을 강조합니다.&lt;/li&gt;
&lt;li&gt;'사람'과 '기술' 사이의 조화를 잘 다루고 있어요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;성장 단계별 가이드&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 레벨에 맞는 기대치와 역량이 명확히 제시되어 있습니다.&lt;/li&gt;
&lt;li&gt;다음 단계로의 성장을 준비하는 데 실질적인 도움이 됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 인상깊었던 점은 각 단계별로 요구되는 역량과 기대치가 명확하게 제시되어 있다는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 기술적 역량뿐만 아니라 커뮤니케이션, 팀워크, 리더십 같은 소프트 스킬의 중요성도 균형있게 다루고 있어서 &lt;br /&gt;실제 현장에서 매우 유용하게 적용할 수 있을 것 같습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;아쉬웠던 점&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일부 내용들은 대기업 중심의 시각이 강한 것 같았습니다.&lt;/li&gt;
&lt;li&gt;한국 IT 업계의 특수성을 반영하지 못한 부분들이 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;추천하는 독자&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;커리어 초기 단계의 주니어 개발자&lt;/b&gt; - 업계의 전체적인 그림을 그리는데 도움이 됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;다음 단계로의 성장을 고민하는 중급 개발자&lt;/b&gt; - 자신의 현재 위치를 점검하고, 다음 단계를 준비하는데 도움이 됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;팀 리더로 전환을 준비하는 시니어 개발자 &lt;/b&gt;- 리더십과 매니지먼트에 대한 실용적인 조언이 많습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작성해놓고 보니 모든 이들이 읽어봐도 좋을 것 같다는 생각이 드는군요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리하며&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 책은 단순한 기술 서적이 아닌, 개발자로서의 전체적인 커리어 여정을 그려볼 수 있는 지도와 같습니다.&lt;br /&gt;매년 한 번씩 꺼내서 읽으며 자신의 성장 방향을 점검하기에 좋을 것 같네요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&quot;한빛미디어&amp;nbsp;&amp;lt;나는리뷰어다&amp;gt;&amp;nbsp;활동을 위해서 책을 제공받아 작성된 서평입니다.&quot;&lt;/span&gt;&lt;/p&gt;</description>
      <category>Book</category>
      <category>개발자</category>
      <category>소프트웨어 엔지니어 가이드북</category>
      <category>엔지니어</category>
      <category>지침서</category>
      <author>KimDoubleB</author>
      <guid isPermaLink="true">https://binux.tistory.com/188</guid>
      <comments>https://binux.tistory.com/188#entry188comment</comments>
      <pubDate>Tue, 26 Nov 2024 23:47:27 +0900</pubDate>
    </item>
    <item>
      <title>Github issue를 파일로 동기화하기 (using Github Action)</title>
      <link>https://binux.tistory.com/187</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;bdeb8ef2b89065b0db438cd40ae69fa2_t.jpeg&quot; data-origin-width=&quot;340&quot; data-origin-height=&quot;340&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wGIEa/btsKsoBJDPk/aHz1zYVg6o2BUUkkqH1gPk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wGIEa/btsKsoBJDPk/aHz1zYVg6o2BUUkkqH1gPk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wGIEa/btsKsoBJDPk/aHz1zYVg6o2BUUkkqH1gPk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwGIEa%2FbtsKsoBJDPk%2FaHz1zYVg6o2BUUkkqH1gPk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;340&quot; height=&quot;340&quot; data-filename=&quot;bdeb8ef2b89065b0db438cd40ae69fa2_t.jpeg&quot; data-origin-width=&quot;340&quot; data-origin-height=&quot;340&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;오늘은 Github issue 내용을 Github 파일로 동기화 시키는 Github action 개발기를 이야기 해볼까 해요.&lt;/span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;오늘 이야기 할 Github action은 Marketplace에서 확인 및 사용할 수 있어요.&lt;/span&gt;&lt;/i&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1730393697578&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;Issue to File Sync - GitHub Marketplace&quot; data-og-description=&quot;Sync GitHub issues to files with customizable paths and labels&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/marketplace/actions/issue-to-file-sync&quot; data-og-url=&quot;https://github.com/marketplace/actions/issue-to-file-sync&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/d9ACxu/hyXs2Sod6y/iAq6Bllj9AlSBHm6c2nMt1/img.jpg?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/dFYen0/hyXsQj7LGG/MIftYq48NDMyLrd9j8YP8k/img.jpg?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400&quot;&gt;&lt;a href=&quot;https://github.com/marketplace/actions/issue-to-file-sync&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/marketplace/actions/issue-to-file-sync&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/d9ACxu/hyXs2Sod6y/iAq6Bllj9AlSBHm6c2nMt1/img.jpg?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/dFYen0/hyXsQj7LGG/MIftYq48NDMyLrd9j8YP8k/img.jpg?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Issue to File Sync - GitHub Marketplace&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Sync GitHub issues to files with customizable paths and labels&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;개발 동기&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;개발자들은 Github repository에 문서를 모아두기도 하고, 블로그를 운영하며 글을 작성해두기도 해요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;저 또한 마찬가지였어요. 문서를 정리해 Github repository에 올려두기도 하고&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;(지금은 미사용 중이긴 하지만) &lt;a href=&quot;http://github.io&quot;&gt;github.io&lt;/a&gt; 블로그가 있어 해당 글을 작성할 때 로컬에서 작성해 repository에 올려두기도 했죠.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이럴 때마다 몇 가지 불편한 점이 있었어요.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;로컬에서 직접 IDE 혹은 Text editor로 &amp;lsquo;작성 &amp;gt; 저장&amp;rsquo; 후 Git add/commit/push 과정을 수행해야 됬어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이미지 파일을 첨부하고 싶은 경우, 직접 추가해서 경로를 문서에 입력해줘야했어요. &lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;(vscode 같은 IDE를 이용한다면 plugin의 도움을 받을 수 있지만, 가끔 오류가 발생할 때마다 스트레스를 받았어요)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;로컬에서 작성한 문서의 Preview가 Github에 올라갔을 때 차이가 발생했어요. &lt;br /&gt;수정을 하고자 하면 다시 add/commit/push를 수행해야 했죠.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;그래서 문서를 Repository에 직접 올리는 것 대신, Github issue를 활용해보는 방법을 고민하게 되었어요.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;맞아요, 사실 Github issue는 Github repository에 대해서 문제가 발생하거나, &lt;br /&gt;추가할 기능이 있는 등 개발적으로 필요한 사항에 대해 이야기하고, 이를 Pull Request로 해결해가는 용도긴 하죠.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;하지만, 제가 일하고 있는 곳에서는 기술 문서화/공유 용도로 Github issue를 사용하고 있었고, &lt;br /&gt;문서 관련 Repository에서는 실제 이슈 트래킹 용도의 Github issue 기능이 거의 필요하지 않았어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;그래서 Github issue로 작성한 글을 바로 파일로 동기화 시켜서 Repository에 추가해보자 라고 생각하게 됬습니다. &lt;br /&gt;이 방식이라면 위에서 문제 삼았던 부분들을 다 해결할 수 있을 것 같았어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;add/commit/push의 귀찮음에서 해방 될 수 있고, 이미지도 Github에 올라간 이미지 링크로 바로 참조가 가능하겠죠. &lt;br /&gt;Issue Preview를 통해 보여지는 형태를 미리 살펴볼 수도 있을거에요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;개발하기&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Github action을 개발한 경험은 조금 있었기에 일단 목적에 맞는 action 프로세스를 구상해봤어요.&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;issue를 작성했나?&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;issue의 글을 가져온다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;글을 파일로 만들어 repository에 commit/push 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;push 후 문제 없으면 issue에 완료 comment를 추가한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;간단하죠? &lt;br /&gt;근데 위 방식으로 진행하면, 아직 완성되지 않은 글이 바로 동기화 될 수 있는 문제가 있어요.&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;그리고 동기화 시키고 싶지 않은 issue 임에도 무조건 동기화 될 수 밖에 없죠.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;그래서 label을 이용하기로 했어요.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2048&quot; data-origin-height=&quot;1140&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vTbml/btsKsXwZUCf/ftlPB5w5d7Z7LYsZMLjMRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vTbml/btsKsXwZUCf/ftlPB5w5d7Z7LYsZMLjMRk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vTbml/btsKsXwZUCf/ftlPB5w5d7Z7LYsZMLjMRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvTbml%2FbtsKsXwZUCf%2FftlPB5w5d7Z7LYsZMLjMRk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2048&quot; height=&quot;1140&quot; data-origin-width=&quot;2048&quot; data-origin-height=&quot;1140&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;특정 label이 추가된 issue만 동기화를 시키는거죠. 그럼 위 문제를 해결할 수 있겠죠?&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;그래서 수정한 최종 파이프라인은 아래와 같아요.&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;issue에 label이 달렸나? =&amp;gt; &lt;/span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;그 label이 특정 label인가?&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;issue의 글을 가져온다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;글을 파일로 만들어 repository의 특정 위치에 commit/push 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;push 후 문제 없으면 issue에 완료 comment를 추가한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;그리고 반대 케이스로 'label이 제거된 경우 파일제거', 'issue가 제거된 경우 파일 제거' 경우도 고려해서 다른 Job으로 추가했죠.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Label 추가/제거 이벤트 받기&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Trigger 조건&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;먼저 issue를 통해 트리거 받을 수 있는 조건들을 살펴봐야 해요.&lt;/span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1730393839236&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;워크플로를 트리거하는 이벤트 - GitHub Docs&quot; data-og-description=&quot;GitHub에 대한 특정 작업이 예약된 시간에 발생하거나 GitHub 외부의 이벤트가 발생할 때 실행되도록 워크플로를 구성할 수 있습니다.&quot; data-og-host=&quot;docs.github.com&quot; data-og-source-url=&quot;https://docs.github.com/ko/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#issues&quot; data-og-url=&quot;https://docs.github.com/ko/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bEAD0b/hyXptc5ccR/mmFe8rzcHxxFzKDODjkTo0/img.png?width=1200&amp;amp;height=1200&amp;amp;face=0_0_1200_1200,https://scrap.kakaocdn.net/dn/ch9U9Q/hyXs077oNG/IRa7MjDyNIoC4DAPgUHUc0/img.png?width=2122&amp;amp;height=952&amp;amp;face=0_0_2122_952&quot;&gt;&lt;a href=&quot;https://docs.github.com/ko/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#issues&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.github.com/ko/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#issues&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bEAD0b/hyXptc5ccR/mmFe8rzcHxxFzKDODjkTo0/img.png?width=1200&amp;amp;height=1200&amp;amp;face=0_0_1200_1200,https://scrap.kakaocdn.net/dn/ch9U9Q/hyXs077oNG/IRa7MjDyNIoC4DAPgUHUc0/img.png?width=2122&amp;amp;height=952&amp;amp;face=0_0_2122_952');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;워크플로를 트리거하는 이벤트 - GitHub Docs&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;GitHub에 대한 특정 작업이 예약된 시간에 발생하거나 GitHub 외부의 이벤트가 발생할 때 실행되도록 워크플로를 구성할 수 있습니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;여러 옵션들이 제공하지만, &lt;br /&gt;저희 목적에 맞는 것은 &lt;b&gt;labeled (레이블 추가) , unlabeled (레이블 제거), deleted (이슈 제거)&lt;/b&gt; 이렇게 총 3가지 이벤트였어요.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;shell&quot; data-ke-language=&quot;shell&quot;&gt;&lt;code&gt;on:
  issues:
    types: [labeled, unlabeled, deleted]&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Label 이름 포함 조건&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;특정 조건의 Label을 확인할 수 있어야 하니 Label 이름을 파악할 수 있어야 했어요.&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이는 github.event.label context에서 제공되고 있어요. 예시를 github docs에서 확인할 수 있죠.&lt;/span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1730393874046&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;워크플로 트리거 - GitHub Docs&quot; data-og-description=&quot;GitHub Actions 워크플로를 자동으로 트리거하는 방법&quot; data-og-host=&quot;docs.github.com&quot; data-og-source-url=&quot;https://docs.github.com/ko/actions/writing-workflows/choosing-when-your-workflow-runs/triggering-a-workflow#example-using-a-value-in-the-event-payload&quot; data-og-url=&quot;https://docs.github.com/ko/actions/writing-workflows/choosing-when-your-workflow-runs/triggering-a-workflow&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/LiumD/hyXppPiHdA/t0lfJoKjEPm765yvcqKu5K/img.png?width=1200&amp;amp;height=1200&amp;amp;face=0_0_1200_1200&quot;&gt;&lt;a href=&quot;https://docs.github.com/ko/actions/writing-workflows/choosing-when-your-workflow-runs/triggering-a-workflow#example-using-a-value-in-the-event-payload&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.github.com/ko/actions/writing-workflows/choosing-when-your-workflow-runs/triggering-a-workflow#example-using-a-value-in-the-event-payload&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/LiumD/hyXppPiHdA/t0lfJoKjEPm765yvcqKu5K/img.png?width=1200&amp;amp;height=1200&amp;amp;face=0_0_1200_1200');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;워크플로 트리거 - GitHub Docs&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;GitHub Actions 워크플로를 자동으로 트리거하는 방법&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;저는 Label에 이모지를 추가 및 변경을 하고 싶어, 특정 이름의 label이 완벽히 같은지보단&lt;b&gt; 느슨하게 포함 여부&lt;/b&gt;로 하기로 결정했어요.&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이렇게 포함여부 연산을 지원하기 위해 github action에서는 contains 함수가 존재해서 이걸 이용하기로 했죠.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;shell&quot; data-ke-language=&quot;shell&quot;&gt;&lt;code&gt;jobs:
  check-label-and-sync:
    # Label이 추가됬으면서, Label 이름에 'Ready to publish'이 포함되면 아래오는 Action을 수행
    if: github.event.action == 'labeled' &amp;amp;&amp;amp; contains(github.event.label.name, 'Ready to publish')&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;참고로 github action에서는 여러 편의 함수들이 제공되요. 아래 주소를 참고해보세요.&lt;/span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1730393933544&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Evaluate expressions in workflows and actions - GitHub Docs&quot; data-og-description=&quot;You can use expressions to programmatically set environment variables in workflow files and access contexts. An expression can be any combination of literal values, references to a context, or functions. You can combine literals, context references, and fu&quot; data-og-host=&quot;docs.github.com&quot; data-og-source-url=&quot;https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/evaluate-expressions-in-workflows-and-actions&quot; data-og-url=&quot;https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/evaluate-expressions-in-workflows-and-actions&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/i8uaV/hyXsT2dj81/s0dYhTnt5sODHKwozrk5Uk/img.png?width=1200&amp;amp;height=1200&amp;amp;face=0_0_1200_1200&quot;&gt;&lt;a href=&quot;https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/evaluate-expressions-in-workflows-and-actions&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/evaluate-expressions-in-workflows-and-actions&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/i8uaV/hyXsT2dj81/s0dYhTnt5sODHKwozrk5Uk/img.png?width=1200&amp;amp;height=1200&amp;amp;face=0_0_1200_1200');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Evaluate expressions in workflows and actions - GitHub Docs&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;You can use expressions to programmatically set environment variables in workflow files and access contexts. An expression can be any combination of literal values, references to a context, or functions. You can combine literals, context references, and fu&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Issue 가져와 파일로 동기화&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;위에서 계획한 파이프라인의 2~4번 작업은 개발로 작업해야 해요.&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;br /&gt;이를 위해 저는 &lt;b&gt;python&lt;/b&gt;을 이용했어요.&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;javascript, go 등 다양한 언어들이 지원되는데, 그냥 제가 개발하기 편한 언어를 선택했어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;구현 코드에 대해서도 상세히 설명하고 싶지만, 그냥 Python 언어 설명이 되는 것 같아서 생략할게요.&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;코드가 어렵지 않아서, 아래 코드와 주석만 봐도 충분히 이해가 되실거에요. (참 쉽죠?)&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;python&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;- name: Setup Python
  uses: actions/setup-python@v5
  with:
    python-version: '3.13'
    
- name: Install dependencies
  run: |
    python -m pip install --upgrade pip
    pip install requests

- name: Sync file
  run: |
    import os
    import json
    import requests
    from datetime import datetime
    
    # GitHub API 설정
    GITHUB_TOKEN = os.getenv('GITHUB_TOKEN')
    GITHUB_API = &quot;&amp;lt;https://api.github.com&amp;gt;&quot;
    headers = {
        &quot;Authorization&quot;: f&quot;Bearer {GITHUB_TOKEN}&quot;,
        &quot;Accept&quot;: &quot;application/vnd.github.v3+json&quot;
    }
    
    # 이벤트 데이터 읽기
    event_path = os.getenv('GITHUB_EVENT_PATH')
    with open(event_path, 'r', encoding='utf-8') as f:
        event = json.load(f)
    
    # 이슈 정보 가져오기
    issue = event['issue']
    issue_number = issue['number']
    repo_full_name = event['repository']['full_name']
    title = issue['title']
    body = issue['body'] or ''
    
    # 현재 날짜 가져오기 (UTC 기준)
    current_date = datetime.utcnow().strftime('%Y-%m-%d')
    
    # 파일명 생성 (날짜-이슈제목.md)
    safe_title = title.lower().replace(' ', '-')

    # 파일명에 사용할 수 없는 문자 제거
    safe_title = ''.join(c for c in safe_title if c.isalnum() or c in '-_')
    
    # 디렉토리(_posts) 및 파일이름 지정
    filename = f&quot;_posts/{current_date}-issue#{issue_number}-{safe_title}.md&quot;
    
    # 디렉토리가 없으면 생성
    os.makedirs(os.path.dirname(filename), exist_ok=True)
    
    # 마크다운 파일 생성/수정
    with open(filename, 'w', encoding='utf-8') as f:
        f.write(body)
    
    # Git 설정
    os.system('git config --global user.name &quot;github-actions[bot]&quot;')
    os.system('git config --global user.email &quot;github-actions[bot]@users.noreply.github.com&quot;')
    
    # 변경사항 커밋
    os.system(f'git add &quot;{filename}&quot;')
    os.system(f'git commit -m &quot;sync: Update issue #{issue_number} to markdown&quot;')
    os.system('git push')
    
    # 완료 코멘트 추가
    comments_url = f&quot;{GITHUB_API}/repos/{repo_full_name}/issues/{issue_number}/comments&quot;
    comment_data = {
        &quot;body&quot;: &quot;  Publish complete  &quot;
    }
    requests.post(comments_url, headers=headers, json=comment_data)
  env:
    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  shell: python&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;br /&gt;Label 제거 및 Issue 제거를 통한 동기화 파일 제거도 비슷해요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;자세한 내용은 아래를 참고해주세요.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1730394563327&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;remove-on-unlabel:
    if: github.event.action == 'unlabeled' &amp;amp;&amp;amp; contains(github.event.label.name, 'Ready to publish')
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          token: ${{ secrets.GITHUB_TOKEN }}

      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.13'

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install requests

      
      - name: Remove Markdown
        run: |
          import os
          import json
          import glob
          import requests
          
          # GitHub API 설정
          GITHUB_TOKEN = os.getenv('GITHUB_TOKEN')
          GITHUB_API = &quot;https://api.github.com&quot;
          headers = {
              &quot;Authorization&quot;: f&quot;Bearer {GITHUB_TOKEN}&quot;,
              &quot;Accept&quot;: &quot;application/vnd.github.v3+json&quot;
          }
          
          # 이벤트 데이터 읽기
          event_path = os.getenv('GITHUB_EVENT_PATH')
          with open(event_path, 'r', encoding='utf-8') as f:
              event = json.load(f)
          
          issue_number = event['issue']['number']
          repo_full_name = event['repository']['full_name']
          # 해당 이슈 번호를 가진 파일 찾기
          files = glob.glob(f&quot;_posts/*issue#{issue_number}-*.md&quot;)
          
          if files:
              # Git 설정
              os.system('git config --global user.name &quot;github-actions[bot]&quot;')
              os.system('git config --global user.email &quot;github-actions[bot]@users.noreply.github.com&quot;')
              
              # 파일 삭제 및 커밋
              for file in files:
                  os.remove(file)
                  os.system(f'git add &quot;{file}&quot;')
              
              os.system(f'git commit -m &quot;sync: Remove markdown for issue #{issue_number} (label removed)&quot;')
              os.system('git push')

              # 삭제 완료 코멘트 추가
              comments_url = f&quot;{GITHUB_API}/repos/{repo_full_name}/issues/{issue_number}/comments&quot;
              comment_data = {
                  &quot;body&quot;: &quot; ️ Markdown file has been removed  ️&quot;
              }
              requests.post(comments_url, headers=headers, json=comment_data)
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        shell: python

  delete-markdown:
    if: github.event.action == 'deleted'
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          token: ${{ secrets.GITHUB_TOKEN }}

      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.13'

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install requests

      - name: Delete Markdown
        run: |
          import os
          import json
          import glob
          import requests
          
          # 이벤트 데이터 읽기
          event_path = os.getenv('GITHUB_EVENT_PATH')
          with open(event_path, 'r', encoding='utf-8') as f:
              event = json.load(f)
          
          issue_number = event['issue']['number']
          
          # 해당 이슈 번호를 가진 파일 찾기
          files = glob.glob(f&quot;_posts/*issue#{issue_number}-*.md&quot;)
          
          if files:
              # Git 설정
              os.system('git config --global user.name &quot;github-actions[bot]&quot;')
              os.system('git config --global user.email &quot;github-actions[bot]@users.noreply.github.com&quot;')
              
              # 파일 삭제 및 커밋
              for file in files:
                  os.remove(file)
                  os.system(f'git add &quot;{file}&quot;')
              
              os.system(f'git commit -m &quot;sync: Remove markdown for deleted issue #{issue_number}&quot;')
              os.system('git push')
        shell: python&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;사용하기&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이렇게 직접 Github action을 만들어서 활용해보았는데요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;아래와 같이 제대로 동작하는 것을 확인할 수 있었어요.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1363&quot; data-origin-height=&quot;988&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vCOMG/btsKqZ4tSra/66ksDqZFfpLBywCbVq6Gfk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vCOMG/btsKqZ4tSra/66ksDqZFfpLBywCbVq6Gfk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vCOMG/btsKqZ4tSra/66ksDqZFfpLBywCbVq6Gfk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvCOMG%2FbtsKqZ4tSra%2F66ksDqZFfpLBywCbVq6Gfk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1363&quot; height=&quot;988&quot; data-origin-width=&quot;1363&quot; data-origin-height=&quot;988&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;물론 삭제하는 것도 제대로 동작했어요.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1472&quot; data-origin-height=&quot;970&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/osHNj/btsKrRRXShr/APGGwExMJj8VhGTRxVgmh0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/osHNj/btsKrRRXShr/APGGwExMJj8VhGTRxVgmh0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/osHNj/btsKrRRXShr/APGGwExMJj8VhGTRxVgmh0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FosHNj%2FbtsKrRRXShr%2FAPGGwExMJj8VhGTRxVgmh0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1472&quot; height=&quot;970&quot; data-origin-width=&quot;1472&quot; data-origin-height=&quot;970&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;Github action 배포하기&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;만들어놓고 나니, 다른 프로젝트에도 쉽게 적용할 수 있는 방안을 고민하기 시작했어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;필요할 때마다 레포에 복사/붙여넣기 방식은 귀찮기도 하고,&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;디렉토리명 등 커스텀하게 수정이 필요할텐데 전체 코드를 보면서 수정하다보니 실수할 포인트들이 있었죠.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;그래서 그냥 Custom Github Action으로 쉽게 사용 가능하도록 배포하고, &lt;a href=&quot;https://github.com/marketplace?type=actions&quot;&gt;Marketplace&lt;/a&gt;에 올려보고자 했어요.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Custom Github Action 만들기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;사실 기존에 만든 Github Action을 Custom Github Action로 만드는 과정은 간단해요.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;배포할 Github Action에 대한 정보를 담는 actions.yml 작성이 필요해요. (&lt;a href=&quot;https://docs.github.com/en/actions/sharing-automations/creating-actions/metadata-syntax-for-github-actions&quot;&gt;docs&lt;/a&gt;)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;작성한 코드를 실행할 방법 선택 및 코드 구성이 필요해요. &lt;br /&gt;기본적으로 Dockerfile, Javascript, Composite 3가지 방법을 지원해요. &lt;br /&gt;요약하면 &lt;b&gt;Javascript를 제외한 언어라면 Dockerfile을 통해서 구성&lt;/b&gt;해야 해요.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;관련해 자세한 내용을 확인하고 싶다면, 아래 문서를 참고해주세요.&lt;/span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1730394158027&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;About custom actions - GitHub Docs&quot; data-og-description=&quot;You can create actions by writing custom code that interacts with your repository in any way you'd like, including integrating with GitHub's APIs and any publicly available third-party API. For example, an action can publish npm modules, send SMS alerts wh&quot; data-og-host=&quot;docs.github.com&quot; data-og-source-url=&quot;https://docs.github.com/en/actions/sharing-automations/creating-actions/about-custom-actions&quot; data-og-url=&quot;https://docs.github.com/en/actions/sharing-automations/creating-actions/about-custom-actions&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/HkPpK/hyXsQdlYQW/LMjCheDbVuoPknINkffsW1/img.png?width=1200&amp;amp;height=1200&amp;amp;face=0_0_1200_1200&quot;&gt;&lt;a href=&quot;https://docs.github.com/en/actions/sharing-automations/creating-actions/about-custom-actions&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.github.com/en/actions/sharing-automations/creating-actions/about-custom-actions&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/HkPpK/hyXsQdlYQW/LMjCheDbVuoPknINkffsW1/img.png?width=1200&amp;amp;height=1200&amp;amp;face=0_0_1200_1200');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;About custom actions - GitHub Docs&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;You can create actions by writing custom code that interacts with your repository in any way you'd like, including integrating with GitHub's APIs and any publicly available third-party API. For example, an action can publish npm modules, send SMS alerts wh&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;actions.yml&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;actions.yml은 구현한 Github Action에 대한 메타데이터를 나타내요.&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Github Action의 이름과 어떤 목적을 가지고 있는지, 어떤 input 데이터를 넣어야 하는지, &lt;br /&gt;어떤 방식으로 동작하는지 등 정보를 담고 있어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;저는 아래와 같이 작성했어요.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;shell&quot; data-ke-language=&quot;shell&quot;&gt;&lt;code&gt;name: 'Issue to File Sync'
description: 'Sync GitHub issues to files with customizable paths and labels'
author: '@KimDoubleB'

inputs:
  github-token:
    description: 'GitHub token for API access'
    required: true
  output-dir:
    description: 'Directory path for files to be created'
    required: true
  trigger-label:
    description: 'Label that triggers the sync'
    required: true
    default: 'documentation'
  timezone:
    description: 'Timezone for date formatting'
    required: false
    default: 'Asia/Seoul'
  file-extension:
    description: 'File extension for output files (without dot)'
    required: false
    default: 'md'

runs:
  using: 'docker'
  image: 'Dockerfile'

branding:
  icon: 'refresh-cw'
  color: 'blue'&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;기능을 확장하고자 파일 경로, 타임존, 파일 확장자를 받도록 추가했어요.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;branding 부분에 icon과 color를 입력하지 않으면 marketplace에 배포할 수 없어요.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Code 및 Dockerfile&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;action.yml에서 Dockerfile을 이용하도록 설정했으니, 이젠 여기서부턴 개발자 자유에요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;소스에 맞게 Dockerfile을 구성해서, 동작하고자 하는 목적을 이루면 되는거죠.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;저는 앞서 작성한 code를 python file(.py)로 추출하고, 이를 실행시킬 수 있는 Dockerfile로 구성했어요.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;dockerfile&quot;&gt;&lt;code&gt;# Dockerfile
FROM python:3.9-slim

RUN apt-get update &amp;amp;&amp;amp; \\
    apt-get install -y git &amp;amp;&amp;amp; \\
    apt-get clean &amp;amp;&amp;amp; \\
    rm -rf /var/lib/apt/lists/*

COPY requirements.txt /requirements.txt
RUN pip install -r /requirements.txt

COPY src /src
ENTRYPOINT [&quot;python&quot;, &quot;/src/main.py&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;배포 및 릴리즈&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;작성을 완료했다면, release하고 사용하기만 하면되요.&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Release 섹션에 가면 아래와 같이 Github Marketplace에 배포할지 묻는 체크박스가 추가되어 있는 것을 볼 수 있어요.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;999&quot; data-origin-height=&quot;723&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bf0eV5/btsKqZi1AmF/bekDvSkAXSX3mDUKCXGkJk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bf0eV5/btsKqZi1AmF/bekDvSkAXSX3mDUKCXGkJk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bf0eV5/btsKqZi1AmF/bekDvSkAXSX3mDUKCXGkJk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbf0eV5%2FbtsKqZi1AmF%2FbekDvSkAXSX3mDUKCXGkJk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;999&quot; height=&quot;723&quot; data-origin-width=&quot;999&quot; data-origin-height=&quot;723&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;배포를 원한다면 체크를 하고, Release를 하면 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;앗 참고로 배포에는 몇 가지 조건(README 작성 등)이 필요해요. &lt;br /&gt;해당 조건들을 다 채우고 Release 하면, 아래와 같이 Marketplace에서 배포된 것을 확인할 수 있어요.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2038&quot; data-origin-height=&quot;1366&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cC4yvH/btsKq09Xbx0/lecV0pAJoX8RAA32UZRKWk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cC4yvH/btsKq09Xbx0/lecV0pAJoX8RAA32UZRKWk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cC4yvH/btsKq09Xbx0/lecV0pAJoX8RAA32UZRKWk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcC4yvH%2FbtsKq09Xbx0%2FlecV0pAJoX8RAA32UZRKWk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2038&quot; height=&quot;1366&quot; data-origin-width=&quot;2038&quot; data-origin-height=&quot;1366&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;근데 사실 배포를 하지 않아도 다른 프로젝트에서 사용하는 것은 문제 되지 않아요. &lt;br /&gt;&lt;b&gt;Marketplace는 단순히 공유 용도로 사용된다는 점을 알아두세요.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;대신 Release는 하는 편이 좋으니 꼭 해주세요.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;사용하기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;사용하기 위해선 정의한 Github action repository와 Release version을 명시하면 되요.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;shell&quot; data-ke-language=&quot;shell&quot;&gt;&lt;code&gt;name: Sync Issues to Markdown

on:
  issues:
    types: [labeled, unlabeled, deleted]

jobs:
  sync-issues:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          
      - name: Sync Issue to File
        uses: KimDoubleB/issue-to-file-action@v1
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          output-dir: '_posts'
          trigger-label: 'Ready to publish'
          timezone: 'Asia/Seoul'
          file-extension: 'md'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;간단하죠~?&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;맨 처음에 직접 Github action에 모든 코드를 작성했을 때보다 &lt;b&gt;훨씬 간결해진 것&lt;/b&gt;을 볼 수 있어요.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1933&quot; data-origin-height=&quot;854&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/E0Uj1/btsKsfZd8Mf/UEEecSpccEjEHKk12Ly6r0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/E0Uj1/btsKsfZd8Mf/UEEecSpccEjEHKk12Ly6r0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/E0Uj1/btsKsfZd8Mf/UEEecSpccEjEHKk12Ly6r0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FE0Uj1%2FbtsKsfZd8Mf%2FUEEecSpccEjEHKk12Ly6r0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1933&quot; height=&quot;854&quot; data-origin-width=&quot;1933&quot; data-origin-height=&quot;854&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;결론&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이렇게 필요한 기능을 Github action을 작성해보고, &lt;br /&gt;직접 다른 프로젝트에서 쉽게 활용할 수 있도록 Marketplace에 배포해 볼 수 있었어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;그리고 직접 Github 블로그에 적용해서 블로그 글을 단순 issue에 작성하고 Label을 달아줌으로써 발행할 수 있었죠 &lt;br /&gt;(IDE를 켜지 않아도 되고, Add/Commit/Push를 하지 않아도 됬어요  ).&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Dockerfile로 구성이 가능하다는 것을 보셨다시피, Github action의 사용처는 무궁무진해요.&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;무언가 Github에서 트리거되어 동작하는 기능을 구현하고 싶었다면, Github action을 구성해보시는 것은 어떨까요?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;긴 글 읽어주셔서 감사해요.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Development</category>
      <category>custom github action</category>
      <category>file sync</category>
      <category>github</category>
      <category>GitHub Action</category>
      <category>github action issue</category>
      <category>Github Action 배포</category>
      <category>github issue</category>
      <category>github issue label</category>
      <category>marketplace</category>
      <category>workflow</category>
      <author>KimDoubleB</author>
      <guid isPermaLink="true">https://binux.tistory.com/187</guid>
      <comments>https://binux.tistory.com/187#entry187comment</comments>
      <pubDate>Fri, 1 Nov 2024 05:11:45 +0900</pubDate>
    </item>
    <item>
      <title>SBOM (Software Bill of Materials)</title>
      <link>https://binux.tistory.com/186</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이 글을 통해 SBOM 대한 생각을 정리하고, 여러 툴들을 이용해 SBOM을 만들며 보안 이슈를 확인해볼까 해요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;간단히 만들어 보는 과정만을 담고 있으므로 SBOM 생성/분석 툴들의 상세한 옵션들은 다루지 않을게요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;SBOM이란 무엇일까요?&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;SBOM은 &lt;b&gt;Software Bill of Materials의 약자&lt;/b&gt;예요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Maven을 사용해보신 개발자라면 BOM이라는 단어 그리고 Bill of Materials는 많이 접해보셨을 텐데요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;단어 뜻 그대로 &quot;자재명세서&quot;를 의미해요. '어떤 소프트웨어가 무엇으로 이루어져있지?'한다면 Bill of Materials를 통해 '아 이런 소프트웨어들이 내포되어 있구나!'라는 것을 알 수 있어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이러한 Maven BOM을 이용하여 여러 라이브러리들의 의존성 버전을 관리하고, 라이브러리 간 버전 충돌 방지 등의 이점을 얻을 수 있었죠.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;SBOM도 비슷한 의미이지만, 하고자 하는 역할이 달라요.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;SBOM 파일을 통해서 &lt;b&gt;특정 소프트웨어가 어떤 라이브러리, 패키지, 라이선스 등 어떠한 구성요소로 이루어져 있는지 확인&lt;/b&gt;할 수 있어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;하지만 Maven BOM에서는 빌드 간 편의성을 이를 관리했던 것과 달리 SBOM은 소프트웨어 공급망(Software Supply Chain)에 대한 가시성을 높이고, 소프트웨어 종속성을 편리하게 추적하고 관리하기 위한 용도로 활용돼요.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Maven은 Maven 생태계에서 빌드 환경에 편의를 위해 고안된 것이라면,&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;SBOM은 특정 언어 및 빌드 툴에 의존적인 형태가 아닌 소프트웨어에 대해 종속성에 대한 가시성을 높이고 편리하게 관리하기 위해 고안되었다고 볼 수 있어요.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;왜 필요할까요?&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;그럼 '소프트웨어 공급망(Software Supply Chain)에 대한 가시성을 높이고, 소프트웨어 종속성을 편리하게 추적하고 관리하기 위한 용도'가 왜 필요할까요?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;큰 프로젝트를 관리해보신 분이라면 라이브러리 종속성 관리의 어려움을 아실 거예요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;프로젝트가 커져감에 따라 필요한 기능들이 많아지고, 기능들을 손수 구현하는 것이 아닌 여러 라이브러리들을 사용하다보면 어느새 엄청나게 많은 라이브러리가 의존성 목록에 존재하게 돼요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이와중에 컨테이너 환경이 도입되면서 빌드에 사용되는 툴/소스들을 관리하게 되고, 운영 컨테이너 내부적으로 사용되는 소프트웨어 등 추가적으로 관리해야하는 소프트웨어들은 엄청나게 많아요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;이 때, 특정 소프트웨어의 버전에 보안 취약점이 공개되었다고 해볼까요? 이 소프트웨어가 사용 중인지 어떻게 알 수 있을까요? 더 나아가 특정 버전이 사용 중인지 어떻게 알 수 있을까요?&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;맞아요. 모든 환경에서 사용중인지 직접 찾아보는 과정을 거쳐야 해요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;소규모 프로젝트라면 쉽게 확인할 수 있겠지만, 대규모 프로젝트라면 이 과정도 쉽지 않을 거예요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;만약 쉽게 찾더라도, 이를 보안 취약점이 공개될 때마다 수동으로 찾아봐야한다는 문제도 있어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;CVE, GHSA 등 보안취약점은 계속적으로 추가되고 공개되는데, 그 때마다 내 소프트웨어가 이에 해당하는지 찾아보는 것은 비효율적이에요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;SBOM은 이러한 문제를 해결하기 위해 등장했어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;SBOM&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;SBOM은 라이브러리, 패키지, 라이선스 등 소프트웨어의 구성요소 목록이에요.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;패키지 이름, 버전, 작성자, 사용 위치, 배포되는 라이선스, 보안 취약점 등 중요한 정보를 캡슐화하여 제공해요.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;단순한 목록이 아닌 소프트웨어 투명성을 위한 도구로서 보안, 규정 준수, 종속성 관리 측면에서 소프트웨어를 개선할 수 있도록 도와요.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;미래에는 SBOM과 이를 통한 보안 취약점 관리 등이 필수적인 요소로 자리잡을 것으로 예상돼요.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;현재는 아직 필수적인 요소로 보여지지는 않아요. 하지만 추후 시간이 지남에 따라 SBOM의 중요성이 부각되면서 필수적인 요소로 보여질 것 같아요 (&lt;i&gt;복잡한 소프트웨어 생태계에서 보안을 위한 스탠다드 느낌&lt;/i&gt;).&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;CI/CD 단계에서도 SBOM을 생성하고, 이를 통해 보안 취약점을 분석하는 작업을 하게 될 거예요. 또한, Private Registry에 올라간 이미지들에 대하여 정기적인 SBOM을 이용한 보안 분석이 수행될 거예요 (&lt;i&gt;빌드 될 때 발견되지 않은 보안취약점/잠재적인 보안취약점 발견을 위한 프로세스&lt;/i&gt;).&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;당연하겠지만 그냥 '내가 Markdown으로 라이브러리 목록 작성해서 만들어야지~'는 SBOM이 아니에요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;위 목적에 맞게 정해진 스펙으로 만들어진 것이 SBOM이며 여러 포맷을 지원하고 있어요. 이에 대해서는 뒤에서 알아볼게요!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;SBOM과 그 필요성에 대해 더 자세히 보고 싶다면, &lt;a href=&quot;https://anchore.com/sbom/what-is-an-sbom/&quot;&gt;anchore의 글&lt;/a&gt;을 참고하시면 좋아요.&lt;/span&gt;&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;SBOM 생성하기&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이제, SBOM을 만들어볼까요?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;SBOM은 정해진 형식이 있는 파일이에요. 고로, 저희가 수동으로 만들기보단 툴을 이용해서 만들어요.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Syft 이용하기&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;SBOM에는 여러 포맷(&lt;a href=&quot;https://github.com/anchore/syft?tab=readme-ov-file#output-formats&quot;&gt;Syft&lt;/a&gt;&lt;a href=&quot;https://github.com/anchore/syft&quot;&gt;,&lt;/a&gt; &lt;a href=&quot;https://cyclonedx.org/&quot;&gt;CycloneDX&lt;/a&gt;, &lt;a href=&quot;https://spdx.dev/learn/overview/&quot;&gt;SPDX&lt;/a&gt;등)이 있으며, 이를 만드는 툴(Trivy, Syft, Docker Scout 등)도 여러가지가 존재해요.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;참고) 지금으로부터 2년이 되긴했는데, &lt;a href=&quot;https://www.itworld.co.kr/news/250420&quot;&gt;포맷에 대해 설명한 IT WORLD (한국어로 작성된) 기사&lt;/a&gt;가 있네요.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이 중 많이 활용되고 있는 Syft 툴을 이용해볼까요?&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1730134373845&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - anchore/syft: CLI tool and library for generating a Software Bill of Materials from container images and filesystems&quot; data-og-description=&quot;CLI tool and library for generating a Software Bill of Materials from container images and filesystems - anchore/syft&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/anchore/syft&quot; data-og-url=&quot;https://github.com/anchore/syft&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Mw9LB/hyXpoooXPz/klw5aLgId8BvAfKKd8fwi0/img.png?width=2582&amp;amp;height=1376&amp;amp;face=0_0_2582_1376,https://scrap.kakaocdn.net/dn/xIRQt/hyXpqfqYDf/rAQJnp7AX5TKrdU5BO9rcK/img.png?width=2582&amp;amp;height=1376&amp;amp;face=0_0_2582_1376&quot;&gt;&lt;a href=&quot;https://github.com/anchore/syft&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/anchore/syft&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Mw9LB/hyXpoooXPz/klw5aLgId8BvAfKKd8fwi0/img.png?width=2582&amp;amp;height=1376&amp;amp;face=0_0_2582_1376,https://scrap.kakaocdn.net/dn/xIRQt/hyXpqfqYDf/rAQJnp7AX5TKrdU5BO9rcK/img.png?width=2582&amp;amp;height=1376&amp;amp;face=0_0_2582_1376');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - anchore/syft: CLI tool and library for generating a Software Bill of Materials from container images and filesystems&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;CLI tool and library for generating a Software Bill of Materials from container images and filesystems - anchore/syft&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Syft는 앞서 이야기한 3개의 포맷을 다 지원하기 때문에(&lt;a href=&quot;https://github.com/anchore/syft?tab=readme-ov-file#output-formats&quot;&gt;syft output formats&lt;/a&gt;), 원하는 포맷을 타겟해서 SBOM을 생성할 수 있어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;사용 방법은 간단해요. CLI를 설치하고 단순히 특정 컨테이너 이미지를 넘겨주기만 하면 돼요.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1730134390675&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ syft tree9295/sbom-test-spring:0.0.1 -o syft-json &amp;gt; syft.sbom.json
 ✔ Loaded image                      tree9295/sbom-test-
 ✔ Parsed image                    sha256:916882e8fb9a6cb4
 ✔ Cataloged contents              5c7a714ff592cac86f4d3ff
   ├── ✔ Packages                        [51 packages]
   ├── ✔ File digests                    [220 files]
   ├── ✔ File metadata                   [220 locations]
   └── ✔ Executables                     [107 executables]&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;설치 방법은 &lt;a href=&quot;https://github.com/anchore/syft?tab=readme-ov-file#installation&quot;&gt;Syft README&lt;/a&gt;를 참고해주세요.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;테스트를 위해 Spring boot 3.2.1 + Web/MVC을 이용해 구성된 container를 배포해두었어요 (&lt;a href=&quot;https://hub.docker.com/repository/docker/tree9295/sbom-test-spring/general&quot;&gt;tree9295/sbom-test-spring&lt;/a&gt;)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;만약 다른 format을 이용하고 싶다면, `-o cyclonedx-json` 같이 output option으로 설정하시면 돼요.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;결과 확인&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;위 결과로 만들어진 syft.sbom.json 파일을 살펴볼까요?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;파일의 양이 많아 전체를 담지는 못했지만, 아래와 같이 사용된 라이브러리와 그 정보들을 담고 있는 것을 확인할 수 있어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;여기서 알아야하는 것은 저희가 사용했다고 생각한 라이브러리(spring boot 등) 뿐 아니라 Container 이미지에서 사용하고 있는 기본 툴들에 대한 정보도 다 포함되어 있다는 거예요.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1590&quot; data-origin-height=&quot;1994&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/x0OMR/btsKnniHqul/e06yCGvJ7MqBN8ThaF5FZ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/x0OMR/btsKnniHqul/e06yCGvJ7MqBN8ThaF5FZ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/x0OMR/btsKnniHqul/e06yCGvJ7MqBN8ThaF5FZ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fx0OMR%2FbtsKnniHqul%2Fe06yCGvJ7MqBN8ThaF5FZ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;586&quot; height=&quot;735&quot; data-origin-width=&quot;1590&quot; data-origin-height=&quot;1994&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;어떻게 만드는걸까요?&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이렇게 SBOM을 만들어보았는데요. 한 가지 궁금증이 들어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;Syft 같은 SBOM 생성 툴들은 단순 Container image로 SBOM을 어떻게 만들 수 있었던 걸까요?&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;아시다시피 Container image는 단순 애플리케이션이 아닌 애플리케이션을 실행하기 위한 환경도 포함하고 있어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이러한 모든 것들은 Container image 내 File system에 존재해요.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;가끔 Container image가 마법 같이 바로 애플리케이션을 실행시켜주는 단순 실행 프로그램으로 아시는 분들이 있어요. Container image는 애플리케이션과 그 실행에 필요한 모든 종속성을 포함하는 완전한 패키지예요. 오해하면 안 돼요.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Syft는 이걸 이용해요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt; Container image 내 파일들을 스캔하고, 패키지 정보를 수집한 뒤 구조화된 SBOM 형태로 변환하여 사용자가 원하는 포맷으로 출력&lt;/b&gt;해요.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;자세히는 Syft 내 Cataloger들이 stereoscope 라이브러리를 이용하여 image 내 파일들을 스캔하고 정보를 수집해요.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이에 대한 자세한 내용은 &lt;a href=&quot;https://github.com/anchore/syft/blob/main/DEVELOPING.md#architecture&quot;&gt;Syft Architecture&lt;/a&gt;를 참고해주세요.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Syft는 binary 파일에 대해서도 분석을 수행해요 (&lt;a href=&quot;https://anchore.com/blog/improve-open-source-sbom-tool-syft-with-binary-detection/&quot;&gt;Improving Syft's Binary Detection&lt;/a&gt;)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;SBOM을 통해 보안취약점 분석하기&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;SBOM을 만들었다고 해볼까요? 그럼 보안 위험이 해결되는 걸까요?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;당연히 아니에요. 이를 보고 이해하고 보안 위험 등 운영상의 문제가 있는 부분을 찾을 수 있는 툴이 필요해요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;생성된 SBOM을 이용하여 보안 취약점을 분석하는 툴들도 여러가지 존재해요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이 글에서는 Grype을 이용하여 분석해볼게요.&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1730134617099&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - anchore/grype: A vulnerability scanner for container images and filesystems&quot; data-og-description=&quot;A vulnerability scanner for container images and filesystems - anchore/grype&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/anchore/grype&quot; data-og-url=&quot;https://github.com/anchore/grype&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/jmnmV/hyXpCmDHLs/M3UkU1Zd65wXjeBtd35OH0/img.png?width=2760&amp;amp;height=1400&amp;amp;face=0_0_2760_1400,https://scrap.kakaocdn.net/dn/gIgJC/hyXpt4jq3Y/HP0Ayv59wofsRZr7Oxum50/img.png?width=2760&amp;amp;height=1400&amp;amp;face=0_0_2760_1400&quot;&gt;&lt;a href=&quot;https://github.com/anchore/grype&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/anchore/grype&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/jmnmV/hyXpCmDHLs/M3UkU1Zd65wXjeBtd35OH0/img.png?width=2760&amp;amp;height=1400&amp;amp;face=0_0_2760_1400,https://scrap.kakaocdn.net/dn/gIgJC/hyXpt4jq3Y/HP0Ayv59wofsRZr7Oxum50/img.png?width=2760&amp;amp;height=1400&amp;amp;face=0_0_2760_1400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - anchore/grype: A vulnerability scanner for container images and filesystems&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;A vulnerability scanner for container images and filesystems - anchore/grype&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Grype는 Syft를 만든 anchore에서 만들었어요.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;설치 방법은 &lt;a href=&quot;https://github.com/anchore/grype?tab=readme-ov-file#installation&quot;&gt;Grype README&lt;/a&gt;를 참고해주세요.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;사실 Syft를 이용하여 SBOM을 만들지 않아도 Grype 내부에서 Syft를 이용하고 있어 SBOM을 만들고 바로 분석까지 수행이 가능해요.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;ex) `grype tree9295/sbom-test-spring:0.0.1`&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;하지만 저희는 만들어 둔 SBOM을 이용해볼게요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;앞선 예제로 사용했던 sbom-test-spring 이미지는 Spring boot 3.2.1을 이용하고 있어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;해당 라이브러리는 spring web 6.1.2 버전을 이용하고 있는데요. 이 버전에서는 High 등급 3개의 보안 취약점이 발견되었어요.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;a href=&quot;https://ossindex.sonatype.org/component/pkg:maven/org.springframework/spring-web@6.1.2&quot;&gt;Spring web 6.1.2 Vulnerabilities&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;a href=&quot;https://spring.io/security&quot;&gt;Spring Security Advisories List&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;만든 SBOM을 Grype에서 분석하여 위 보안취약점이 검출되는지 확인해볼게요.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1730134728747&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ grype syft.sbom.json
 ✔ Scanned for vulnerabilities     [12 vulnerability matches]
   ├── by severity: 0 critical, 6 high, 4 medium, 0 low, 0 negligible (2 unknown)
   └── by status:   12 fixed, 0 not-fixed, 0 ignored
NAME                    INSTALLED  FIXED-IN  TYPE          VULNERABILITY        SEVERITY
libcrypto3              3.3.2-r0   3.3.2-r1  apk           CVE-2024-9143        Unknown
libssl3                 3.3.2-r0   3.3.2-r1  apk           CVE-2024-9143        Unknown
...
spring-web              6.1.2      6.1.5     java-archive  GHSA-hgjh-9rj2-g67j  High
spring-web              6.1.2      6.1.4     java-archive  GHSA-ccgv-vj62-xf9h  High
spring-web              6.1.2      6.1.6     java-archive  GHSA-2wrp-6fg6-hmc5  High
spring-web              6.1.2      6.1.12    java-archive  GHSA-2rmj-mq67-h97g  Medium
...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;위에서 보았던 것처럼 3개의 GHSA High 보안취약점이 확인되는 것을 볼 수 있어요.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;예상하지 못했던 컨테이너에 포함된 다양한 다른 보안취약점까지 확인되는 것을 볼 수 있어요.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;GHSA는 Github에서 관리되는 보안 취약점 데이터베이스예요. CVE와 개념은 같은데, Github에 존재하는 프로젝트와 관련된 취약점에 초점을 맞춘 것이라고 이해하시면 돼요.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;위 결과에서 알 수 있듯 단순 보안취약점 검출을 넘어&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;어떤 타입인지&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;어떤 Vulnerability인지&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;그리고 제일 중요한 어떤 버전에서 fix 되었는지&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;까지 다양한 정보를 보여줘요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;이렇게 분석된 결과를 바탕으로 보안 취약점 등 이슈를 보고하거나 수정해 나갈 수 있어요.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;각 보안취약점을 무조건 수정해야한다는 것은 아니에요.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;문제 발현조건들이 다 다를 수 있으니 위 리포트를 바탕으로 Vulnerability report를 보고 파악해보는 것이 중요해요.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;파이프라인 구성하기&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;SBOM 생성과 분석이 포함된 파이프라인 구성은 인프라 구성상황에 따라 다르기에 여러 예시를 첨부하는 것으로 대신할게요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;예시) &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;a style=&quot;color: #006dd7;&quot; href=&quot;https://www.infracloud.io/blogs/implement-devsecops-secure-ci-cd-pipeline/&quot; data-token-index=&quot;1&quot;&gt;DevSecOps CI/CD&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2048&quot; data-origin-height=&quot;1240&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1xLiF/btsKnbv7ZpF/zS0yMPvkq81HX4kQTz6BKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1xLiF/btsKnbv7ZpF/zS0yMPvkq81HX4kQTz6BKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1xLiF/btsKnbv7ZpF/zS0yMPvkq81HX4kQTz6BKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1xLiF%2FbtsKnbv7ZpF%2FzS0yMPvkq81HX4kQTz6BKK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2048&quot; height=&quot;1240&quot; data-origin-width=&quot;2048&quot; data-origin-height=&quot;1240&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;예시) &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;a style=&quot;color: #006dd7;&quot; href=&quot;https://www.google.com/url?sa=i&amp;amp;url=https%3A%2F%2Fwww.linkedin.com%2Fpulse%2Fempowering-cicd-github-actions-grype-tools-practical-guide-tor-zhowe&amp;amp;psig=AOvVaw0LYWzWIZ61MX_XdNjzbirr&amp;amp;ust=1730218306782000&amp;amp;source=images&amp;amp;cd=vfe&amp;amp;opi=89978449&amp;amp;ved=0CBQQjRxqFwoTCLiOz8-7sYkDFQAAAAAdAAAAABAE&quot; data-token-index=&quot;1&quot;&gt;Grype를 이용한 Github action pipeline 구성&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1005&quot; data-origin-height=&quot;455&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b7C6ok/btsKn6ggHgu/PRYSuzvJUKKPP6VVkSoMT0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b7C6ok/btsKn6ggHgu/PRYSuzvJUKKPP6VVkSoMT0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b7C6ok/btsKn6ggHgu/PRYSuzvJUKKPP6VVkSoMT0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb7C6ok%2FbtsKn6ggHgu%2FPRYSuzvJUKKPP6VVkSoMT0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1005&quot; height=&quot;455&quot; data-origin-width=&quot;1005&quot; data-origin-height=&quot;455&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;예시) &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;a style=&quot;color: #006dd7;&quot; href=&quot;https://anchore.com/sbom/creating-sbom-attestations-using-syft-and-sigstore/&quot; data-token-index=&quot;1&quot;&gt;Syft SBOM, Sigstore 컨테이너 서명을 통한 SBOM 증명(attestation) 과정&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;848&quot; data-origin-height=&quot;446&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmDDNV/btsKlEzdBTj/l41NUOIvCP6U78EJDQpngk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmDDNV/btsKlEzdBTj/l41NUOIvCP6U78EJDQpngk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmDDNV/btsKlEzdBTj/l41NUOIvCP6U78EJDQpngk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbmDDNV%2FbtsKlEzdBTj%2Fl41NUOIvCP6U78EJDQpngk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;848&quot; height=&quot;446&quot; data-origin-width=&quot;848&quot; data-origin-height=&quot;446&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;결론&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이렇게 SBOM을 만들고, SBOM을 분석하여 보안 취약점을 파악해보았어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이는 어떻게 활용될 수 있을까요?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;CI/CD 및 정기적인 보안 프로세스에서 컨테이너 이미지에 대해 보안취약점, 부적격 라이센스 이용 등을 손쉽게 파악해볼 수 있을 거예요.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;가끔 회사 공지 혹은 메일로 오는 것들을 생각해봐요. 'XXX 취약점으로 인한 버전 확인 요청', 'XXX 소프트웨어 라이센스 변경으로 인한 이용 확인 요청' 등 귀찮은 작업들이 수두룩 하지 않나요?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;SBOM을 이용한다면 특정 버전을 사용하고 있는지도, 보안 취약점이 존재하는지도, 라이센스 문제가 있는지도 바로 파악이 가능할 거예요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;보안 부서 입장에서도, 플랫폼 운영 입장에서도, 소프트웨어를 직접 개발하는 개발자 입장에서도 아주 편리한 회사생활이 될 것 같네요 :-)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;여기까지 긴 글 읽어주셔서 감사합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;부록 (끝내기는 아쉽지)&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;글을 작성하며, Spring boot를 주로 사용하는 개발자로서 &quot;Spring boot에서는 SBOM 생성을 지원하는게 없을까?&quot;를 중심으로 먼저 찾아보았었는데요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이대로 간직하긴 아쉬워서&amp;nbsp;관련된 내용들은 부록으로나마 공유드릴게요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Spring boot 3.3 actuator + CycloneDX plugin&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;figure id=&quot;og_1730134985893&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;SBOM support in Spring Boot 3.3&quot; data-og-description=&quot;Spring Boot 3.3.0 has been released, and it contains support for SBOMs. SBOM stands for &amp;quot;Software Bill of Materials&amp;quot; and describes the components used to build a software artifact. In the context of this blog post, that's your Spring Boot application. Thes&quot; data-og-host=&quot;spring.io&quot; data-og-source-url=&quot;https://spring.io/blog/2024/05/24/sbom-support-in-spring-boot-3-3&quot; data-og-url=&quot;https://spring.io/blog/2024/05/24/sbom-support-in-spring-boot-3-3&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bPYJ1d/hyXpzDr3j3/VzSpw5uuLadth5HMrGazCk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/dn0YdY/hyXpAh3Uly/NgcxYz1wFTjifRZ5kZc42K/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://spring.io/blog/2024/05/24/sbom-support-in-spring-boot-3-3&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://spring.io/blog/2024/05/24/sbom-support-in-spring-boot-3-3&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bPYJ1d/hyXpzDr3j3/VzSpw5uuLadth5HMrGazCk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/dn0YdY/hyXpAh3Uly/NgcxYz1wFTjifRZ5kZc42K/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;SBOM support in Spring Boot 3.3&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Spring Boot 3.3.0 has been released, and it contains support for SBOMs. SBOM stands for &quot;Software Bill of Materials&quot; and describes the components used to build a software artifact. In the context of this blog post, that's your Spring Boot application. Thes&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;spring.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Spring boot 3.3부터는 actuator를 통해 SBOM을 출력하는 엔드포인트를 제공하도록 업데이트 되었어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이를 위해서는 아래와 같은 구성이 필요해요.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;CycloneDX plugin 추가 =&amp;gt; &lt;b&gt;id(&quot;org.cyclonedx.bom&quot;)&amp;nbsp;version&amp;nbsp;&quot;1.8.2&quot;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Spring Web, Actuator 의존성 추가&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Actuator SBOM 활성화 및 노출 property 설정&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;위 설정을 완료한 뒤 `/actuator/sbom/application` endpoint에 접속하면&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;CycloneDX format의 SBOM이 노출된 것을 확인할 수 있어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이를 Grype를 통해 분석하고자 한다면, 아래와 같이 해볼 수 있어요.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1730135048925&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ curl http://{host}/actuator/sbom/application | grype&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Cloud Native Buildpacks (CNB)&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Spring boot에서는 CNB를 이용한 플러그인을 통해 손쉽게 Container image를 만들 수 있도록 지원하고 있어요.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;ex) `.gradlew bootBuildImage`&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이와 관련되어 아래 문서들을 참고해보면 좋아요.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;a href=&quot;https://docs.spring.io/spring-boot/gradle-plugin/packaging-oci-image.html&quot;&gt;https://docs.spring.io/spring-boot/gradle-plugin/packaging-oci-image.html&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;a href=&quot;https://docs.spring.io/spring-boot/reference/packaging/container-images/cloud-native-buildpacks.html&quot;&gt;https://docs.spring.io/spring-boot/reference/packaging/container-images/cloud-native-buildpacks.html&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;a href=&quot;https://github.com/paketo-buildpacks/spring-boot&quot;&gt;https://github.com/paketo-buildpacks/spring-boot&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;a href=&quot;https://buildpacks.io/&quot;&gt;https://buildpacks.io/&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이 때 CNB를 이용한 빌드 과정에서 syft가 사용되는 것을 볼 수 있어요.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1730135092903&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ ./gradlew bootBuildImage
...
    [creator]     paketo-buildpacks/syft              2.3.1
...
    [creator]     Paketo Buildpack for Syft 2.3.1
    [creator]       https://github.com/paketo-buildpacks/syft
...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Container Image를 확인해보면, `/layers/sbom/launch` 디렉토리 아래에 빌드 과정에서 만들어진 SBOM 목록이 존재하는 것을 볼 수 있어요.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1730135163876&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ find /layers/sbom/launch -name &quot;*.json&quot;
/layers/sbom/launch/buildpacksio_lifecycle/launcher/sbom.cdx.json
/layers/sbom/launch/buildpacksio_lifecycle/launcher/sbom.spdx.json
/layers/sbom/launch/buildpacksio_lifecycle/launcher/sbom.syft.json
/layers/sbom/launch/paketo-buildpacks_bellsoft-liberica/helper/sbom.syft.json
/layers/sbom/launch/paketo-buildpacks_bellsoft-liberica/jre/sbom.syft.json
/layers/sbom/launch/paketo-buildpacks_ca-certificates/helper/sbom.syft.json
/layers/sbom/launch/paketo-buildpacks_executable-jar/sbom.cdx.json
/layers/sbom/launch/paketo-buildpacks_executable-jar/sbom.syft.json
/layers/sbom/launch/paketo-buildpacks_spring-boot/helper/sbom.syft.json
/layers/sbom/launch/paketo-buildpacks_spring-boot/spring-cloud-bindings/sbom.syft.json
/layers/sbom/launch/sbom.legacy.json&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Buildpack을 이용해 빌드 과정에서 활용되는 라이브러리, 애플리케이션에서 사용되는 라이브러리 등 전체적으로 사용되는 모든 소프트웨어 구성요소를 SBOM로 구성해두고 있는 것을 볼 수 있어요.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Paketo Buildpack 문서를 보면 이에 대해 더 자세히 설명하고 있어요.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;a href=&quot;https://paketo.io/docs/concepts/sbom/&quot;&gt;Paketo buildpack - SBOM&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;a href=&quot;https://paketo.io/docs/howto/sbom/&quot;&gt;Paketo buildpack - How to access the SBOM&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Syft를 통해 해당 이미지를 분석해보면, 위 SBOM 파일들도 분석 대상에 포함되어 전체적인 하나의 SBOM 파일을 만들 것으로 예상돼요.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Development</category>
      <category>BOM</category>
      <category>CVE</category>
      <category>cyclonedx</category>
      <category>ghsa</category>
      <category>grype</category>
      <category>sbom</category>
      <category>software bill of materials</category>
      <category>spdx</category>
      <category>syft</category>
      <category>보안취약점</category>
      <author>KimDoubleB</author>
      <guid isPermaLink="true">https://binux.tistory.com/186</guid>
      <comments>https://binux.tistory.com/186#entry186comment</comments>
      <pubDate>Tue, 29 Oct 2024 07:45:21 +0900</pubDate>
    </item>
  </channel>
</rss>