<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>나라의 IT 잡아먹기</title>
    <link>https://waspro.tistory.com/</link>
    <description>LG CNS AA Cloud Service 나의 한계는 무한하다</description>
    <language>ko</language>
    <pubDate>Tue, 10 Mar 2026 06:53:47 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>GodNR</managingEditor>
    <image>
      <title>나라의 IT 잡아먹기</title>
      <url>https://tistory1.daumcdn.net/tistory/2886875/attach/5e0c15862d1644eca8ae6676a7d4a151</url>
      <link>https://waspro.tistory.com</link>
    </image>
    <item>
      <title>SI 프로젝트와 배포 전략</title>
      <link>https://waspro.tistory.com/787</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;배포 전략&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;비즈니스 환경 변화에 탄력있게 대응하기 위해 많은 기업들이 Agile, DevOps, MSA 등 다양한 기반 기술을 도입하고 있지만, 실상은 많은 시행착오를 겪고 있는 것도 사실이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;서비스는 사용자 경험 향상을 위해 하루에도 수번에서 수십번 버전을 업그레이드하거나, 버그를 픽스하는 등 여러 경우에서 변화가 발생할 수 있다. 이때 사용자가 느끼지 못할 정도로 서비스의 중단 없이 배포를 진행해야 하는 경우가 있고, 때로는 다운타임을 가져가야 할 경우도 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Blue-Green Deploy&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Canary Deployment&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Recreate&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Rolling Update&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;A/B Testing&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Shadow&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;지금부터 어플리케이션을 사용하는 고객 중심에서 이 새로운 버전을 원활하게 배포하는 방법에 대해서 알아보도록 하자. 또한, SI가 진행되는 과정에서 어떤 배포 방식을 선택하는 것이 좋을지도 함께 고민해 보자.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Blue-Green Deploy&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Blue-Green 배포는 동일한 환경을 갖춘 두 개(Blue 환경과 Green 환경)의 버전을 배포하고, 트래픽을 일괄 전환하는 방식이다. 새롭게 출시할 버전이 있는 경우 Green 환경에 배포하고 Blue 환경은 그대로 유지하며 트래픽을 처리한다. Green 환경으로의 전환은 대체로 서비스 절체가 가능한 수준인 도메인 단위가 될 수 있지만, 필요시 Context 단위가 될 수도 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Tester의 테스트 단위는 구간별 로드밸런싱을 처리하는 대상을 기준으로 선정할 수 있다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;외부망 구간 L4&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;DMZ 구간 WEB Server&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;내부망 구간 Ingress&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;외부망 구간 L4&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;DNS 서버의 Domain 분리 방식을 적용하여 외부망 구간을 포함하여 테스트할 경우 End to End Test가 용이하다는 장점이 있다. 특히 차세대 급 SI 프로젝트가 진행되는 경우 전체 인프라부터 망까지 분리하여 구축하는 경우가 있는데, 이때 단순 서비스의 점검만 이루어지는 것이 아닌 구간에 대한 인터페이스 점검, H/W, S/W 점검 역시 진행되어야 한다. 이 경우 E2E 대역을 점검할 수 있어 가장 바람직한 방법이 될 수 있다.&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;1556&quot; data-origin-height=&quot;802&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uOb41/btrUCjjAAJ8/EZRXzSnhQ9lb3dmuS7KzPk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uOb41/btrUCjjAAJ8/EZRXzSnhQ9lb3dmuS7KzPk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uOb41/btrUCjjAAJ8/EZRXzSnhQ9lb3dmuS7KzPk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuOb41%2FbtrUCjjAAJ8%2FEZRXzSnhQ9lb3dmuS7KzPk%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;1556&quot; height=&quot;802&quot; data-origin-width=&quot;1556&quot; data-origin-height=&quot;802&quot;/&gt;&lt;/span&gt;&lt;/figure&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Blue 영역(AS-IS) : stable.waspro.co.kr(예시) &amp;gt; L4 &amp;gt; AS-IS WEB &amp;gt; AS-IS Container Mgmt &amp;gt; DB&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Green 영역(TO-BE) : newer.waspro.co.kr(예시) &amp;gt;&amp;nbsp;L4 &amp;gt; TO-BE WEB &amp;gt; TO-BE Container Mgmt &amp;gt; DB&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;반대로 외부망 대역에 도메인이 노출되어 출시 전 서비스를 외부 대역의 불특정 다수가 접근할 수 있어 보안에&amp;nbsp;문제가 발생할 수 있다. 이를 방어하기 위한 특정 대역의 사용자 또는 특정 ID만 접근 가능하도록 차단하는 어플리케이션 레벨의 방어로직이 필요하지만, 이 역시 완전한 방어책이 될 수는 없다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;DMZ 구간 WEB Server&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;DMZ 구간을 포함하여 테스트 하는 방식은 외부망에 직접적인 노출을 피한다는 점을 제외하고 전체 구간 테스트와 비슷하다. 이 경우 화이트리스트 정책을 적용하여, WEB Server에서 특정 구간의 사용자만 접근이 가능하도록 허용하는 방식을 통해 출시 전 서비스에 대한 보안을 강화할 수 있다. 또한, 필요 시 Tester의 위치에 따라, WEB Server IP를 사용하여 직접 접근하여 테스트할 수도 있다.&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;1556&quot; data-origin-height=&quot;802&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JOaDU/btrUwntS7R3/k9LKLIkKythtZLad26oR11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JOaDU/btrUwntS7R3/k9LKLIkKythtZLad26oR11/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JOaDU/btrUwntS7R3/k9LKLIkKythtZLad26oR11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJOaDU%2FbtrUwntS7R3%2Fk9LKLIkKythtZLad26oR11%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;1556&quot; height=&quot;802&quot; data-origin-width=&quot;1556&quot; data-origin-height=&quot;802&quot;/&gt;&lt;/span&gt;&lt;/figure&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Blue 영역(AS-IS) : stable.waspro.co.kr/stable(예시) &amp;gt; L4 &amp;gt; AS-IS WEB &amp;gt; AS-IS Container Mgmt &amp;gt; DB&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Green 영역(TO-BE) : stable.waspro.co.kr/newer(예시) &amp;gt;&amp;nbsp;TO-BE WEB &amp;gt; TO-BE Container Mgmt &amp;gt; DB&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;단점으로는 실 이행 시 DNS 전환에 대한 면밀한 검토가 필요하다. 예를 들어, DNS 캐시 갱신 주기 등으로 인해 일시적인 오류가 발생할 수도 있고, 이행 절체에 대한 시나리오 수행도 사전 테스트를 통해 진행해 봐야 한다는 점 등이 있지만, 대체로 SI 수행에 적합한 방식이라 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;내부망 구간 Ingress&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;내부망 구간에서 직접 테스트 하는 방식은 서비스 중심의 테스트라고 볼 수 있다. 내부망 구간의 DNS를 통해 Routing 되어야 할 Ingress Node를 결정하거나, hosts 파일을 통해 직접 접근하여 테스트할 수 있다.&amp;nbsp;&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;1556&quot; data-origin-height=&quot;893&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QYk3Q/btrUEvYkBAS/ofankrzRtsKE2bRCJVHCsK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QYk3Q/btrUEvYkBAS/ofankrzRtsKE2bRCJVHCsK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QYk3Q/btrUEvYkBAS/ofankrzRtsKE2bRCJVHCsK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQYk3Q%2FbtrUEvYkBAS%2FofankrzRtsKE2bRCJVHCsK%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;1556&quot; height=&quot;893&quot; data-origin-width=&quot;1556&quot; data-origin-height=&quot;893&quot;/&gt;&lt;/span&gt;&lt;/figure&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Blue 영역(AS-IS) : stable.waspro.co.kr(예시) &amp;gt; L4 &amp;gt; AS-IS WEB &amp;gt; AS-IS Container Mgmt &amp;gt; DB&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Green 영역(TO-BE) : ingress_domain:port(예시) &amp;gt;&amp;nbsp;TO-BE Container Mgmt &amp;gt; DB&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이 경우, 서비스 런칭 전까지 외부 노출없이 안정적으로 테스트 할 수 있지만, 위 두가지 테스트와 다르게 외부 연계에 대한 인터페이스 점검이 어렵다는 단점이 있다. 다만, SI 초기 내부망 구간에서 점검하기 적합한 방식으로 솔루션 간의 인터페이스, Legacy 인터페이스를 점검하는 차원에서 활용된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;배포 및 테스트가 완료되면, Green 환경에 트래픽을 유입하기 위한 서비스 전환 절차를 진행한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NsR7e/btrUuQi6swo/qFRNompCBYGbJcvamlyzNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NsR7e/btrUuQi6swo/qFRNompCBYGbJcvamlyzNK/img.png&quot; style=&quot;width: 33.6808%; margin-right: 10px;&quot; data-origin-width=&quot;1730&quot; data-origin-height=&quot;869&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;34.48&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NsR7e/btrUuQi6swo/qFRNompCBYGbJcvamlyzNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNsR7e%2FbtrUuQi6swo%2FqFRNompCBYGbJcvamlyzNK%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;1730&quot; height=&quot;869&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZsT8W/btrUugoxYk6/fOGyfym6ZgJulfvrTFdtqK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZsT8W/btrUugoxYk6/fOGyfym6ZgJulfvrTFdtqK/img.png&quot; style=&quot;width: 33.6808%; margin-right: 10px;&quot; data-origin-width=&quot;1730&quot; data-origin-height=&quot;869&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;34.48&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZsT8W/btrUugoxYk6/fOGyfym6ZgJulfvrTFdtqK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZsT8W%2FbtrUugoxYk6%2FfOGyfym6ZgJulfvrTFdtqK%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;1730&quot; height=&quot;869&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6QOxg/btrUuQQWKjC/YnyqhxnfpdPisTZVzpkkkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6QOxg/btrUuQQWKjC/YnyqhxnfpdPisTZVzpkkkK/img.png&quot; style=&quot;width: 30.3128%;&quot; data-origin-width=&quot;1557&quot; data-origin-height=&quot;869&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;31.04&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6QOxg/btrUuQQWKjC/YnyqhxnfpdPisTZVzpkkkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6QOxg%2FbtrUuQQWKjC%2FYnyqhxnfpdPisTZVzpkkkK%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;1557&quot; height=&quot;869&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;도메인 전환 이후 정상적으로 테스트가 완료되면, 기존 Blue는 삭제되고, Green이 Blue가 되며, 이후 신규 서비스를 런칭하기 위해 준비하는 과정이 반복된다고 보면 된다.&amp;nbsp;반면에 테스트 과정에서 원하는데로 동작하지 않거나, 크리티컬한 버그가 발견되었을 경우, 2번에서 1번 상태로 신속하게 도메인만 변경하면, 롤백을 완료할 수 있다. 이렇게 하면 EndUser 입장에서는 배포가 발생하지 않은 것처럼 롤백된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;이 전략의 가장 큰 장점은 새로운 애플리케이션 버전의 빠른 업데이트 또는 출시가 가능하다는 점이다. 반면에 새 버전과 이전 버전을 동시에 실행해야 하기 때문에 유지 비용이 많이 든다는 단점이 있다. 이는 매몰비용의 증가로 인해 신속한 출시가 중요한 마이크로서비스 환경과 클라우드 환경 특히 Public 환경의 사용량 기반 비용 지불이 가능한 환경을 활용할 경우 보다 유의미하게 활용할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Canary Deployment&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Canary Deployment는 newer 버전을 전체의 일부에 Production 환경에 배포하고, 점진적으로 비율(트래픽)을 늘려 나가는 방식이다. Blue-Green과는 다르게 두개의 버전이 동시에 운영되는 방식으로, 트래픽을 늘려나가기 위한 성공 기준을 수립하는 것이 중요하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Canary Deployment는 신규 버전의 어플리케이션을 일정 비율로 배포하며, 이는 동시에 동일 도메인을 갖는 서비스가 양쪽으로 분산되는 방식으로 하나의 완전한 버전의 어플리케이션이 배포 된다고 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;배포 분산 방식은 Kubernetes Service를 통한 분산이 일반적이나, Service Mesh 또는 API Gateway를 통해 트래픽을 분산할 수도 있다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;Kubernetes Service 분산&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Service Mesh 분산&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;API Gateway 분산&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Kubernetes Service 분산&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;동일 Domain에 동일 context로 호출하더라도, Kubernetes Service의 Label Selector를 활용하여 multi deployment for single service 형태를 구현할 수 있다.&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;1556&quot; data-origin-height=&quot;802&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ldPd2/btrUujldURg/AxcnrfQdNR3vuiAhNzJ9M0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ldPd2/btrUujldURg/AxcnrfQdNR3vuiAhNzJ9M0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ldPd2/btrUujldURg/AxcnrfQdNR3vuiAhNzJ9M0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FldPd2%2FbtrUujldURg%2FAxcnrfQdNR3vuiAhNzJ9M0%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;1556&quot; height=&quot;802&quot; data-origin-width=&quot;1556&quot; data-origin-height=&quot;802&quot;/&gt;&lt;/span&gt;&lt;/figure&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Kubernetes Canary Serivce Label Selector &amp;gt; Stable Deployment Replicas: 9&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Kubernetes Canary Serivce Label Selector &amp;gt; Newer Deployment Replicas: 1&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 동일 Domain에 동일 context로 호출하더라도, Kubernetes Service의 Label Selector를 활용하여 multi deployment for single service 형태를 구현할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이 경우, 트래픽 비율을 조정하기 어렵기 때문에 대체로 Replicas 수를 통해 트래픽량을 분산한다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Service Mesh 분산&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Service Mesh를 활용하면, 위와 같이 Kubernetes Service로는 제한적인 Routing Rule을 여러 조건으로 분배할 수 있다. 예를 들면 다음과 같다.&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;여러 버전에 가중치 기반 라우팅 처리 가능&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;HTTP 헤더값 기반 라우팅 처리 가능&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Fault Inejction 처리 가능 (Request 중 5%는 HTTP 400 에러 발생하도록 트래픽 리턴)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1556&quot; data-origin-height=&quot;802&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XWeXE/btrUuizOZWS/j8NJnZLa1z6Z6Li3drgKSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XWeXE/btrUuizOZWS/j8NJnZLa1z6Z6Li3drgKSK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XWeXE/btrUuizOZWS/j8NJnZLa1z6Z6Li3drgKSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXWeXE%2FbtrUuizOZWS%2Fj8NJnZLa1z6Z6Li3drgKSK%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;1556&quot; height=&quot;802&quot; data-origin-width=&quot;1556&quot; data-origin-height=&quot;802&quot;/&gt;&lt;/span&gt;&lt;/figure&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Istio VirtualSerivce RoutingRule v1 &amp;amp; Weight 90 &amp;gt; Istio DestinationRule Subset v1 &amp;gt; ENVOY Proxy&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Istio VirtualSerivce RoutingRule v2 &amp;amp; Weight 10 &amp;gt; Istio DestinationRule Subset v2 &amp;gt; ENVOY Proxy&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위는 Service Mesh의 가중치 기반 라우팅 처리 방식이다. subset 기준 1:9의 라우팅 비율로 요청을 분배하여 전달한다. 비율을 확산해 나가는 방법은 대시보드 상 구현되어 있는 것이 효과적이나, Jenkins와 같은 CD 도구를 활용할 수도 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;그 밖에 Header 기반 라우팅 방식은 Client Side의 특정 사용자에게만 접근권한 즉, 특정 Header 정보를 넣어야만 접속이 가능하도록 구성할 수 있다. 이를 통해 라이브 환경에서 사용자 테스트를 수행할 수 있다. 예를 들어, Client Header에 version=v2라는 헤더를 달고 들어올 경우에만 해당 Pod로 라우팅하고, Header가 없는 경우 현재 운영 중인 환경으로 라우팅한다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;API Gateway 분산&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;API Gateway는 VM 또는 Pod로 구성할 수 있다. API Gateway에서 동일한 API를 두개 이상의 서비스로 각각 라우팅할 수 있도록 구성한다.&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;1556&quot; data-origin-height=&quot;876&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cw1819/btrUwnOcCp6/qVZxCr38bpSOgcAzubYbxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cw1819/btrUwnOcCp6/qVZxCr38bpSOgcAzubYbxk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cw1819/btrUwnOcCp6/qVZxCr38bpSOgcAzubYbxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcw1819%2FbtrUwnOcCp6%2FqVZxCr38bpSOgcAzubYbxk%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;1556&quot; height=&quot;876&quot; data-origin-width=&quot;1556&quot; data-origin-height=&quot;876&quot;/&gt;&lt;/span&gt;&lt;/figure&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;API Gateway &amp;gt; Routing A 90 &amp;gt; Service A &amp;gt; Deployment A&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;API Gateway &amp;gt; Routing B 10 &amp;gt; Service B &amp;gt; Deployment B&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;그 밖에 Canary 배포는&amp;nbsp;더 나은 성능 모니터링이 가능하다. 또한 새 버전이 실패할 경우 더 빠르고 더 나은 소프트웨어 롤백을 지원한다. 다만, 점진적인 비율 확장으로 인해 릴리즈 속도가 느리고 배포 주기가 길다는 단점이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Canary Deployment는 크리티컬한 시스템에는 적용할 수 없다. 마케팅 용도의 신규 기능을 정식 출시하기 전 사용자의 반응을 확인하기 위해 일부 사용자를 대상으로만 기능을 오픈하여 테스트 한다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Recreate&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Recreate는 이전 버전의 어플리케이션을 완전히 종료하고 새 버전의 어플리케이션을 배포하는 방식으로 배포 사이에 시스템 중단 시간이 발생한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&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;1556&quot; data-origin-height=&quot;488&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cWbCeo/btrUzmHNpJI/cKkjkirOBMxze9RmGXRKJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cWbCeo/btrUzmHNpJI/cKkjkirOBMxze9RmGXRKJ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cWbCeo/btrUzmHNpJI/cKkjkirOBMxze9RmGXRKJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcWbCeo%2FbtrUzmHNpJI%2FcKkjkirOBMxze9RmGXRKJ0%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;1556&quot; height=&quot;488&quot; data-origin-width=&quot;1556&quot; data-origin-height=&quot;488&quot;/&gt;&lt;/span&gt;&lt;/figure&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1) AS-IS APP CON DOWN&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2) NEWER APP CON BOOT&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;그러나 이 배포방식은 다운 타임으로 인해 사용자에게 큰 영향을 미친다. 따라서 Product 환경에서는 적용이 매우 제한적이거나, 사용하지 않으며, 개발/테스트 환경 기준 버전 별 명확한 테스트를 구분하고자 하는 경우(두 버전이 일시적이라도 중복되지 않도록 해야 하는 경우) 배포 속도가 빠른 서비스를 대상으로 적용하는 것이 바람직하다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Rolling Update&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이 배포 전략은 이전 버전을 새 버전으로 점진적으로 변경하는 방식이다. Canary Deployment와는 다르게 이전 버전의 인스턴스를 한 번에 정해진 수의 인스턴스만큼 새 버전의 인스턴스로 교체하여 전환한다.&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;1556&quot; data-origin-height=&quot;726&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mhQuL/btrUumWKkw9/g9SIQRS6IhAXgyOSGjOgM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mhQuL/btrUumWKkw9/g9SIQRS6IhAXgyOSGjOgM1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mhQuL/btrUumWKkw9/g9SIQRS6IhAXgyOSGjOgM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmhQuL%2FbtrUumWKkw9%2Fg9SIQRS6IhAXgyOSGjOgM1%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;1556&quot; height=&quot;726&quot; data-origin-width=&quot;1556&quot; data-origin-height=&quot;726&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: 'Noto Serif KR'; color: #000000;&quot;&gt;이 배포 방식은 제로 다운타임을 제공하고 성능 모니터링도 가능하다. 다만, 예상치 못한 이벤트가 발생할 경우를 대비하여 롤백 기간이 길다는 단점이 있다. 따라서 이는 Graceful Redeploy와 함께 기동이 오래 걸리는 서비스나 VM 환경에 적용된 서비스에 적용하기 적합하다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Shadow&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Shadow 배포는 이전 버전과 함께 새 버전을 배포하지만, 사용자는 새 버전에 다이렉트로 접속할 수 없으며, 테스트를 위해 이전 버전이 받은 요청을 Shadow 버전으로 포워딩하는 방법을 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1556&quot; data-origin-height=&quot;674&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lSEKI/btrUxozbaYb/i8KvbPNEAmO1lwltmNtrOK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lSEKI/btrUxozbaYb/i8KvbPNEAmO1lwltmNtrOK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lSEKI/btrUxozbaYb/i8KvbPNEAmO1lwltmNtrOK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlSEKI%2FbtrUxozbaYb%2Fi8KvbPNEAmO1lwltmNtrOK%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;1556&quot; height=&quot;674&quot; data-origin-width=&quot;1556&quot; data-origin-height=&quot;674&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;사용자는 기존 트래픽을 처리하되 주황색 라인의 별도 서비스가 호출되는지는 알지 못한다. Shadow 호출을 통해 시스템 성능을 모니터링하고 안정성 테스트를 수행할 수 있다. 반대로 구성이 복잡하고, 비용이 많이 발생하며 때로 이 환경으로 인해 시스템에 심각한 장애를 유발하는 경우도 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;해당 테스트는 SI 수행과정보다는 운영관리 시점의 이행 이후 신규 서비스 출시 시점에 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;A/B Testing&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;A/B 테스트는 Blue/Green 배포와 같이 배포할 버전을 포함하여 두 버전이 동시에 배포된다. 차이점은 Blue/Green 배포가 임의의 사용자에게 비율에 따라 전달된다면, A/B 테스트는 새 버전에 접속하기 위한 조건이 정해져 있다는 점이다. 예를 들어 사용자의 위치, 장치 유형 등을 헤더 정보에 저장하여 라우팅 조건으로 활용할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1557&quot; data-origin-height=&quot;802&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mTD2A/btrUvY8ZdUq/1zSuzJgP59qmk9O5sQDJ3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mTD2A/btrUvY8ZdUq/1zSuzJgP59qmk9O5sQDJ3k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mTD2A/btrUvY8ZdUq/1zSuzJgP59qmk9O5sQDJ3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmTD2A%2FbtrUvY8ZdUq%2F1zSuzJgP59qmk9O5sQDJ3k%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;1557&quot; height=&quot;802&quot; data-origin-width=&quot;1557&quot; data-origin-height=&quot;802&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이 방법은 새로운 기능에 대해 특정 사용자를 대상으로 테스트를 수행함으로써 보다 완전한 테스트를 수행해 볼 수 있지만, Header 정보를 파싱하는 등 L7 Layer의 로드밸런서가 필요하여, 비용 측면, 복잡도 측면에서 고려되어야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;결론&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;통상적으로 운영환경에서는 배포 전략이 간편한 Rolling Update를 사용하는 경우가 많지만, 각각의 배포 전략의 특징을 이해하고 적합한 시나리오와 시점에 활용해야 한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.7855%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #ffffff;&quot;&gt;배포 전략&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 24.2506%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;추천 환경&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10.7882%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;SI&lt;br /&gt;적용&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 5.2067%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;비용&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 5.87857%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;롤백&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 5.87849%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;다운&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;타임&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.83211%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;운영환경&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;테스트여부&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.83207%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;운영환경&lt;br /&gt;테스트대상&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 7.39017%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;구축&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;복잡도&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.7855%; text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Recreate&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 24.2506%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;개발/테스트 환경&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10.7882%; text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;개발단계&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 5.2067%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #006dd7;&quot;&gt;낮음&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 5.87857%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;길다&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 5.87849%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;발생&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.83211%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;-&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.83207%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;-&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 7.39017%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #006dd7;&quot;&gt;낮음&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.7855%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Blue-Green&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 24.2506%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;변경 빈도가 높고, 신속한 롤백이 필요한 중요도가 높은 서비스&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10.7882%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;운영단계&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 5.2067%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;높음&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 5.87857%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #006dd7;&quot;&gt;짧음&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 5.87849%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #006dd7;&quot;&gt;없음&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.83211%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;-&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.83207%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;-&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 7.39017%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;중간&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.7855%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Canary&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 24.2506%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;중요도가 상대적으로&lt;br /&gt;낮은 시스템 대상&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10.7882%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;유지보수&lt;br /&gt;단계&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 5.2067%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;중간&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 5.87857%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;중간&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 5.87849%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #006dd7;&quot;&gt;없음&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.83211%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #006dd7;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;수행&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.83207%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;임의&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;사용자&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 7.39017%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;중간&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.7855%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Rolling Update&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 24.2506%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;개발/테스트 환경&lt;br /&gt;또는 VM 환경&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10.7882%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;개발/테스트&lt;br /&gt;/운영 단계&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 5.2067%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;중간&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 5.87857%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;길다&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 5.87849%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #006dd7;&quot;&gt;없음&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.83211%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;-&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.83207%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;-&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 7.39017%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #006dd7;&quot;&gt;낮음&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.7855%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;A/B Testing&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 24.2506%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;마케팅 등의 용도로&lt;br /&gt;특정 대상을 위한 서비스&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10.7882%; text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;유지보수&lt;br /&gt;단계&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 5.2067%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;중간&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 5.87857%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;중간&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 5.87849%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #006dd7;&quot;&gt;없음&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.83211%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #006dd7;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;수행&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.83207%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #006dd7;&quot;&gt;특정&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #006dd7;&quot;&gt;사용자&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 7.39017%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;높음&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.7855%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Shadow&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 24.2506%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;실 운영환경에서&lt;br /&gt;검증하고자 하는 경우&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 10.7882%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;유지보수&lt;br /&gt;단계&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 5.2067%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;높음&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 5.87857%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #006dd7;&quot;&gt;짧음&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 5.87849%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #006dd7;&quot;&gt;없음&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.83211%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #006dd7;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;수행&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.83207%; text-align: center;&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;모든&lt;br /&gt;사용자&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 7.39017%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;높음&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위 내용은 단순 비교 자료이며, 반드시 위와 같이 적용되는 것은 아니지만, 다음과 같이 정리해 볼 수 있을 듯 하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;u&gt;&lt;i&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&quot;SI 프로젝트를 수행하며, 개발/테스트 단계에서는 Recreate 또는 Rolling Update 방식으로 배포하고, 운영환경은 서비스의 중요도에 따라 Rolling Update 또는 Blue-Green 배포 방식을 적용한다. SI 프로젝트가 종료된 이후 운영사업자는 새로운 서비스 출시를 위해 운영 환경 검증이 가능한 Canary, A/B Testing, Shadow 중 필요에 따라 선택한다.&quot;&lt;/span&gt;&lt;/i&gt;&lt;/u&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Recreate 배포 방식은 비용과 구축 복잡도가 낮아 손쉽게 구축하고, 소규모 프로젝트에서도 활용이 가능하지만, 다운타임 및 롤백 시간이 오래 걸려 비즈니스 중요도가 높은 서비스에 적용할 수 없다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Blue-Green 배포 방식은 짧은 롤백 시간에 따라 중요도가 높고 빈번한 변화가 발생하는 서비스에 적용하기 용이하나, 비용이 많이 발생하여 상대적으로 매몰 비용이 높아질 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Canary 배포 방식은 다운 타임 없이 운영환경에서 사전점검을 수행하고 점진적으로 확장해 나갈 수 있으나, 임의 사용자를 대상으로 테스트를 진행하므로, 사용자 경험 측면이나, 운영 환경 오류에 상대적으로 대응이 어렵다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Rolling Update 배포 방식은 다운타임 없이 신속하게 구축이 가능하지만, 롤백 시간이 오래 걸려 비즈니스 중요도가 높은 서비스에 적용은 어렵다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;A/B Testing 배포 방식은 다운타임 없이 운영환경에서 특정 사용자 또는 사용자 그룹에게만 요청을 전달하여 테스트를 진행하여, 가장 안정적인 테스트 방식이지만, 높은 비용과 높은 구축 복잡도를 갖게 된다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Shadow 배포 방식은 백그라운드 테스트 방식으로 실 운영환경에서 테스트에 목적으로 두고 배포하는 방식이며, 검증을 위해 운영 어플리케이션에 영향을 주어야 하기 때문에, 적용을 신중하게 검토해야 한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;때로는 배포 전략 두개 이상을 조합하여 구성하는 경우도 있다. 위와 같은 각 배포 전략의 특징을 이해하고,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;팀, 프로젝트, 회사의 요구 사항과 비즈니스 목표를 염두에 두고 배포 전략을 선택해야 한다. 특히 민감한 부분이라 할 수 있는 발생 예상되는 비용과 감당할 수 있는 가동 중지 시간에 대해 비교하여 적합한 전략을 찾아보도록 하자.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>⑤ 개발, 데이터베이스/ⓒ CI CD</category>
      <category>a/b testing</category>
      <category>blue green</category>
      <category>canary deploy</category>
      <category>recreate</category>
      <category>rolling update</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/787</guid>
      <comments>https://waspro.tistory.com/787#entry787comment</comments>
      <pubDate>Sun, 25 Dec 2022 21:51:30 +0900</pubDate>
    </item>
    <item>
      <title>Cloud Native DR 설계하기</title>
      <link>https://waspro.tistory.com/784</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;DR 개요&lt;/span&gt;&lt;/h2&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Public Cloud와 Hybrid Cloud의 확대는 최근 IT 판도를 돌려놓고 있다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;수 많은 기업들이 차세대 프로젝트와 함께 어플리케이션 현대화(Application Modernization)를 추구하고 있고, 이를 실현하기 위해 Cloud Native으로 전환을 시도하고 있다. Cloud Native Application은 확장성, 민첩성, 복원성, 유연성, 장애복구성 등을 제공하는 분산 트랜잭션/분산 컴퓨팅 환경에 맞게 어플리케이션을 설계 및 개발하는 방식을 의미하며, 이는 Legacy System과는 다른 요소들을 포함하고 있다. 그 중 하나가 바로 이번 포스팅의 주제인 클라우드 DR의 변화이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Public Cloud는 DR이라는 개념을 Multi AZ(Availiable Zone)으로 상쇄시켰고(Public Cloud는 Availiable Zone을 최소 2개 이상으로 구분하여 운영환경을 Multi AZ 즉 Multi DataCenter 구조로 구성되게 구축한다. 이는 별도 DR 환경이 필요 없는 고 가용성 아키텍처를 제공한다고 볼 수 있다), Private Cloud는 기존 방식과 같은 데이터 센터의 분리(망 분리)는 물론 Public cloud를 활용하는 전략까지 다양해졌다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;우리는 지금부터 이와 같은 다양한 DR 환경에 대한 전략을 살펴보고 재해복구 환경에서 대비해야 할 부분들에 대해 알아보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;DR 전략&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; letter-spacing: 0px; color: #000000;&quot;&gt;DR 환경을 구성함에 따라 얻을 수 있을 것이라 기대하는 비즈니스 목표와 요구사항을 확정하는 것은 매우 중요한 일이다. 현실적으로 비용과 목표(빠른 전환, 낮은 손실 등)는 반비례하게 작용하기 때문에 명확한 비즈니스 목표를 수립하고, 이를 기준으로 적합한 아키텍처를 선정하는 작업이 선행되어야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; letter-spacing: 0px; color: #000000;&quot;&gt;다음은 DR 전략을 수립하는 과정의 리포트이다. (예시)&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1297&quot; data-origin-height=&quot;813&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgQum5/btrRK1ARd2r/limocmLDZCykAZGrKRAXJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgQum5/btrRK1ARd2r/limocmLDZCykAZGrKRAXJ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgQum5/btrRK1ARd2r/limocmLDZCykAZGrKRAXJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbgQum5%2FbtrRK1ARd2r%2FlimocmLDZCykAZGrKRAXJ1%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;1297&quot; height=&quot;813&quot; data-origin-width=&quot;1297&quot; data-origin-height=&quot;813&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1) DR 환경 구축 목표&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;DR 환경을 구축하고자 하는 목표 수준을 정의한다.&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&quot;재해 발생 시&quot; &amp;lt; 재해에 대한 수준 정의 필요&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;재해 복구 환경을 통해 얻고자 하는 목표 정의 필요&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;예를 들어 회사의 수익 감소 대비 재해 복구 시스템 운영 비용의 비율이나, 단순 회사의 이미지에 영향을 줄수 있다는 점 등을 상세히 기입해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;DR 환경 구축 기간에 대한 목표도 제시해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;예를 들어 현 운영 중인 DR 시스템의 복구 시간이 얼마나 걸리고 이를 개선하기 위해 어떠한 인프라와 솔루션을 도입하여 얼마의 기간동안 구축하겠다는 명시적인 목표를 상세히 기입한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2) DR 환경 대상 선정&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&quot;DR 대상 서비스&quot;를 선정하는 기준 정의 필요&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;예를 들어 비용 관점의 서비스는 Critical 기준을 수립하고, 사용자 관점에서 긴급하게 확인이 필요한 정보, 판매자 관점에서 긴급하게 변경이 필요한 정보 등을 대상으로 선정함 등의 상세한 기준 수립이 필요하다.&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&quot;DR 대상 서비스 데이터 복제&quot; 방식 기준 정의 필요&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;예를 들어 비용관점의 정보는 유실이 발생하지 않아야 하므로, 미러링 방식을 선택하고, 배송정보나, 판매중인 상품 변경 서비스는 소급 적용 등을 통해 변경이 가능하여 비용/성능 관점에서 이점을 갖기 위해 DataSync를 사용&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;3) DR&amp;nbsp;복제&amp;nbsp;환경&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;선택하게 된 기준에 대한 기준을 정의한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;- 비용 관점에서 DRaaS를 이용할 경우, DR Center 운영 또는 Public Cloud 운영 대비 어떤 이득이 있는지?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;- 데이터 유실 관점에서 DRaaS를 사용할 경우 비용정보 서비스의 디스크 미러링에는 대응할 수 없는데 어떤 방안이 있는지&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;4) DR&amp;nbsp;복구&amp;nbsp;시간&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;RTO 시간은 재해를 선언하는데 소요되는 시간을 포함하지 않기 때문에 그 시간에 대한 정의는 온전히 다음 절차만의 시간을 포함해야 한다.&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;재해 발생 선언 이후 인프라 기동, 솔루션 기동, 어플리케이션 배포에 소요되는 시간&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;어플리케이션 검증 시간&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;데이터 검증 시간&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;네트워크 절체 시간 (DNS 라우팅 처리 등)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;즉&amp;nbsp;RTO는&amp;nbsp;빠를&amp;nbsp;수록&amp;nbsp;좋지만,&amp;nbsp;정확한&amp;nbsp;검증&amp;nbsp;없는&amp;nbsp;DR&amp;nbsp;서비스&amp;nbsp;오픈은&amp;nbsp;Side-Effect를&amp;nbsp;나타낼&amp;nbsp;수&amp;nbsp;있기&amp;nbsp;때문에,&amp;nbsp;현실적인&amp;nbsp;목표를&amp;nbsp;정의하는&amp;nbsp;것이&amp;nbsp;중요하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;5) DR&amp;nbsp;복구&amp;nbsp;데이터&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;RPO에 대한 시간은 서비스 유실이 발생해도 되는지 여부, 발생가능하다면, 얼마까지 허용가능한지에 대한 여부를 통해 정의한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;핵심서비스의 경우 데이터 손실은 허용되지 않음.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;중요서비스는 10분의 데이터 손실을 허용하되 다음 날 운영환경 복원 시 일괄 복구 절차를 진행 (배치 처리, 소급 적용)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;비핵심서비스는 데이터 손실을 8시간으로 정의&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;정보성서비스는 데이터 복제를 수행하지 않음&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;와&amp;nbsp;같은&amp;nbsp;서비스&amp;nbsp;별&amp;nbsp;데이터&amp;nbsp;복제&amp;nbsp;방식을&amp;nbsp;정의할&amp;nbsp;필요가&amp;nbsp;있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;6) DR&amp;nbsp;복구&amp;nbsp;절차&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;DR 복구 절차는 실 고객이 수행해야 하는 절차서로 최대한 상세하게 작성해야 하며, 절차에 대한 수행 테스트 즉 재해복구 테스트가 정기적으로 수행되어 변화 사항에 대응할 수 있어야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;특히 현재 대부분의 내용은 PROD to DR 환경에 대한 복제에 대해서만 다루고 있지만, 결국 PROD 환경은 복원 될 것이고, 복원된 이후 DR 환경의 데이터를 반영하는 방법에 대한 정의 역시 고려되어야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;MariaDB Replication 복제 방식에 대한 역 방향 복제&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;DataSync 파일 역 방향 복제&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;그 밖의 솔루션 레벨의 역 방향 복제 기능 검증 (GitLab, Harbor 이미지 Replication 등)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같은 DR 전략을 수립한 이후 DR 환경에 대한 세부 설계에 들어가게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; letter-spacing: 0px; color: #000000;&quot;&gt;7) DR 환경 구축 성공 여부 측정&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;마지막으로 DR 전략에 대한 성공 판단 여부를 수립해야 한다.&amp;nbsp;&lt;/span&gt;성공적인 DR 전략을 수립하려면 조직에서 성공적인 전략이 무엇인지 정의하고 명확하게 설명해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;DR은 서로 다른 비즈니스 및 아키텍처 목표로 인해 서로 다른 목표를 갖을 수 있다.&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;구현을 위해 정의된 예산, 시간에 대한 달성 여부&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;중요 비즈니스 서비스 또는 어플리케이션에 대한 복구 전략&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;특정 시간까지 복구 대상 아플리케이션에 대한 구현 및 테스트&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;DR 고려사항&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;최근 차세대 프로젝트를 Cloud Native로 진행했던 사이트는 재해복구 환경을 구성하기 위해 많은 고민을 했을 것이다. As-Is 시스템의 경우 운영환경과 DR환경에 대한 망 분리 규칙에 따라 데이터센터 분리를 우선적으로 고려하여 On-Premise 환경에 구성하였다. 이와 더불어 Public Cloud를 DR 환경으로 선택하는 것은 최선의 선택이 될 수 있지만, 아래와 같은 고려사항들에 대해 고민해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1512&quot; data-origin-height=&quot;1096&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dcaXUZ/btrRNVlGaF2/CPpdaDfJsl4L8U6UCK5xL1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dcaXUZ/btrRNVlGaF2/CPpdaDfJsl4L8U6UCK5xL1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dcaXUZ/btrRNVlGaF2/CPpdaDfJsl4L8U6UCK5xL1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdcaXUZ%2FbtrRNVlGaF2%2FCPpdaDfJsl4L8U6UCK5xL1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1512&quot; height=&quot;1096&quot; data-origin-width=&quot;1512&quot; data-origin-height=&quot;1096&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;바로 어디로 어떻게 복제할 것인지에 대한 부분을 고려해야 하며, 서두에서 이야기 했듯이 Public Cloud는 이미 AZ에 대한 고가용성을 확보하고 있고, Private Cloud의 DR에 대한 부분을 고려한다는 점을 인지하고 다음을 참고하기 바란다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; letter-spacing: 0px; color: #000000;&quot;&gt;※ 3rd Party 솔루션 구축 제약&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;먼저, 퍼블릭클라우드에 적용 가능한 3rd party 솔루션의 제약사항이 있다. On-premise에 적용된 솔루션들은 때때로 해당 도메인에서 충족해야 하는 컨플라이언스를 구현한 기능들을 탑재하고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;예를 들어 금융기관의 금융감독원에 제출하기 위한 자료를 추출하기 위해 형상관리 솔루션에 운영이관 이력, 감사 로그, 승인 여부, 체크인/체크아웃 이력 등을 저장하는 기능을 만들었다고 했을때, 해당 솔루션이 public cloud 환경을 지원하지 않는다면, 대체하는 솔루션을 찾아내는 것은 쉽지 않을 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이는 특정 국가의 특정 도메인에 특정 기능을 커스터마이징한 것이기 때문에 범용 기능이라 보기 어렵고, 오랜 기간 누적된 기술에 대한 분석 및 커스터마이징에 적지 않은 시간이 소모될 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; letter-spacing: 0px; color: #000000;&quot;&gt;※&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;RTO / RPO Zero&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;RTO/RPO 제로를 요구하는 시스템의 경우 적합하지 않다. Cloud DR을 사용할 경우 복구 시간과 복구 데이터에 대한 유실이 제로로 유지될 수 있는가? 이를 달성하기 위해서는 아래와 같은 조건이 만족되어야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;DR 시스템은 상시 기동된 상태로 유지되어야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;DR로&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;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Rto/rpo 제로를 달성하기 위해서는 위과 같은 선행 조건이 필요하지만, 이는 public cloud가 추구하는 지향점과는 거리가 멀다. On-Premise와 Public Cloud DR 사이에는 몇가지 조건에 따라 복구 시간과 복구 데이터에 대한 유실을 최소화 할 수 있지만, 이는 Public Cloud를 DR 환경으로 사용하는 비용효율성 측면(매몰 비용 감소)에 반대되는 설계가 될 것이고, 그럴 경우 굳이 Public Cloud를 사용해야 하는가에 대한 의문이 발생할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; letter-spacing: 0px; color: #000000;&quot;&gt;※&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;대규모 환경 구축&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;비용 효율적인 측면에서 Public Cloud가 장점이 있다고 했지만, 이는 일반적인 상황이며, 수백/수천대의 VM 환경이 필요한 시스템의 경우 Public Cloud를 사용하면, 그 비용이 예상치를 뛰어 넘을 수 있다. Public Cloud의 매몰비용이라는 측면은 온전히 EC2와 같은 VM에 대한 비용적인 이점이 있지만, 사용량 기반의 비용을 지불해야하기 때문에 규모에 따라 비용이 증가할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; letter-spacing: 0px; color: #000000;&quot;&gt;※&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;운영 방식의 변화&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;결국은 퍼블릭 클라우드의 도입은 운영 방식의 다변화를 의미한다. 결과론적으로 비용을 감소하는 만큼 운영관리하는 인력의 증가를 의미하며, 이는 인력적인 측면의 비용 감소를 감안해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;DR 재해복구 환경은 단순하게 운영 환경의 복제 환경이 아니다. 운영하고 있는 환경을 얼마나 빠르게 동일한 환경으로 복구해 낼 수 있는가를 평가의 가치로 생각하기 때문에 고려되어야 할 부분이 다수 존재한다. 지금부터는 DR를 설계하기 위해 고려해야 할 부분과 DR의 대상은 어떤 것들이 포함되어야 하는지 고민해 보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; letter-spacing: 0px; color: #000000;&quot;&gt;※&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;DR 고려사항&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;비즈니스 영향도 분석 : 비즈니스에서 허용하는 범위와 이를 실현할 수 있는지 고민해야 한다. 예를 들어 데이터에 대한 정합성과 데이터 실시간 복제가 필요하지 않은 서비스를 위해 불필요한 데이터 복제에 비용을 낭비할 필요가 없으며, 반대로 반드시 이를 준수해야 하는 시스템에는 이를 구현할 수 있는지를 고민하여 설계해야 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;클라이언트의 변화 최소화 : 가능한 클라이언트의 변화 즉 클라이언트가 인지할 수 없는 수준의 변화를 통해 DR을 구성해야 한다. 예를 들어, 주 센터가 무너지고, DR 센터가 가동된다고 했을때 이를 연결하는 도메인의 변화는 발생하지 않아야 한다. 이를 위해 라우터의 변동 방식에 대한 정의가 필요하며, 도메인을 지원하는 인증서에 대한 동기화 역시 사전에 이루어져야 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;비용 효율적인 접근 : DR 시스템은 필수요소이지만, 현실적으로 DR이 가동되는 현상은 매우 드물다. 즉 DR은 어찌보면 필수 아키텍처이자, 매몰 비용으로 작용하는 것이 현실이다. 이와 같이 매몰비용을 최소화 할 수 있는 방안 마련이 시급하다. 이는 Public Cloud를 DR로 활용하는 것이 최선의 선택지가 될 수 있으며, 이를 구현하기 위한 DR 환경 복제 방안과 오케스트레이션 방안을 마련해야 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;자동화 방안 마련 : 클라우드 기술은 복잡도가 높다. 현재 국내 사용되는 대부분의 재해복구자동화 솔루션(대체로 베리타스와 같은 DR 복제 솔루션과 사전 정의된 스크립트를 실행하는 솔루션, 그리고 디스크 복제 솔루션 등이 있다.)을 적용하여 DR 상황 발생 시 절체 과정을 간소화 하고 있지만, 클라우드 기술에는 아직 이를 적용하기 어려운 것이 사실이다. 따라서 가능한 간소화할 수 있는 작업들이 선행되어야 한다. 이는 스크립트화 할 수도 있고, multi cluster를 관리하는 대시보드를 통해 구현할 수도 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;지속적인 테스트 : DR 재해복구 테스트의 경우 시스템의 SLA가 중요한 서비스를 운영하는 사이트는 최소 연 1회 이상 시행하고 있다. 이는 환경적인 요소, 네트워크적인 요소, External Service의 변화적인 측면 등 서비스 내적인 부분이외의 부분을 검증하기 위해 반드시 시행되어야 한다. 또한, DR 테스트를 통해 복제 데이터에 대한 정합성을 검증하고, 네트워크, 스토리지에 대한 장애 복구 능력을 검증하기 위한 용도로써 활용되어야 한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; letter-spacing: 0px; color: #000000;&quot;&gt;※&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;DR 서비스의 대상&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;DR 서비스의 대상은 운영 관리하는 모든 시스템이 대상이 되겠지만, 긴급성과 RTO/RPO에 따라 범위는 변경될 수 있다. 즉, DR 서비스의 대상은 DR 재해복구를 통해 달성할 것이라 기대하는 기회비용의 가치에 달려 있다고 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;결국 DR 시스템은 비용과 직결되는 시스템으로 DR 시스템에 포함해야 하는 어플리케이션을 다음과 같은 조건을 가지고 평가하여 대상 선정해야 한다.&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;비즈니스 영속성이 얼마나 중요한 서비스인가?&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;허용 가능한 데이터 손실 범위 (시간 또는 데이터 사이즈)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Critical 시스템의 정의 (우선순위 정의 즉 RTO에 대한 순서의 정의)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;결과적으로 금융권 시스템의 경우 비용과 관련된 서비스의 우선순위가 높고, 플랫폼 기업의 경우 개인정보에 대한 정보의 복구가 우선순위가 높을 것이며, 이를 다루는 서비스가 Critical 서비스로 운영되는 것이 현실적이다. 반대로 고객의 경험치를 향상 시키기 위해 도입된 서비스의 경우 약간의 불편함을 감수하지만, 서비스 처리에 영향을 주지 않는 서비스를 하위 복구 절차에 포함할 수 있다. 또한, 재해 상황이 복원된 이후 데이터 복원이 필요하지 않은 (DR 환경의 데이터를 다시 운영환경으로 복원할 필요가 없는)서비스는 재해복구 서비스 대상에서 제외할 수도 있다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;DR 상세 설계&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;지금까지 DR 재해복구 환경을 선택하는 기준에 대해 알아보았다면, 이제 본격적인 DR 아키텍처에 대해 알아보자. DR 환경은 서비스의 중요도에 따라 다양한 설계 요소를 반영할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;특히나 이는 단순히 Infra Architecture를 선택하는것 뿐만 아니라, 솔루션에 대한 선정을 포함한다. 지금부터 아래 두가지 케이스에 대해 알아보도록 하자.&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Case 1: On-Premise 데이터 센터 &amp;rarr; On-Premise 데이터 센터로의 DR&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Case 2: On-Premise 데이터 센터 &amp;rarr; Public Cloud DR&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; letter-spacing: 0px; color: #000000;&quot;&gt;※&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Case 1: On-Premise 데이터 센터 &amp;rarr; On-Premise 데이터 센터로의 DR&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;대부분의 조직은 여전히 ​​자체 데이터 센터 또는 코로케이션을 기반으로 기존의 온-프레미스 인프라를 배포한다. DR을 다른 온-프레미스 데이터 센터로 구성하는 것은 가장 일반적이고 잘 알려져 있다. 메인프레임 및 UNIX 플랫폼을 포함하여 사용 가능한 모든 애플리케이션 및 플랫폼에 대한 DR 솔루션을 지원하며, 다중 복제 기술도 지원한다. 또한, 데이터 유실 제로 달성을 위한 디스크 미러링 기술 역시 지원한다. 이는 Active-Active 구성을 통해 완전한 데이터 동기화 환경을 구성할 수 있다. 이와 반대로 데이터 센터를 유지 관리하기 위해 비용(매몰 비용), 유지보수 인력 확보가 필요하다.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1512&quot; data-origin-height=&quot;1096&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c7ZhmG/btrRJP8u5GC/iVHwC5RFJ6rbcUR6MdFayk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c7ZhmG/btrRJP8u5GC/iVHwC5RFJ6rbcUR6MdFayk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c7ZhmG/btrRJP8u5GC/iVHwC5RFJ6rbcUR6MdFayk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc7ZhmG%2FbtrRJP8u5GC%2FiVHwC5RFJ6rbcUR6MdFayk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1512&quot; height=&quot;1096&quot; data-origin-width=&quot;1512&quot; data-origin-height=&quot;1096&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;On-Premise to On-Premise Data Center의 경우 가장 많은 사례를 기반으로 안정성 측면에서 가장 큰 장점이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;lt;장점&amp;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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;베어메탈 및 VM을 포함한 모든 플랫폼, 엔터프라이즈 애플리케이션 및 운영 체제를 지원하는 광범위한 애플리케이션 및 인프라 호환성과 다양한 공급업체에서 검증된 솔루션 지원&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;엔터프라이즈 애플리케이션에 필요한 고성능, 고대역폭 스토리지 기반 동기식 복제 지원 (매우 강력한 장점)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;DR을 구현하기 위해 하이퍼바이저 마이그레이션 또는 운영 환경 변경이 필요하지 않다는 점은 운영 유지보수의 복잡도를 감소시키는 매우 강력한 장점. 특히 운영환경의 축소된 자원으로 구성된 완전히 미러링된 환경을 생성하여, 긴급 재해 복구 발생 시 RPO Zero를 지원&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;동일한&amp;nbsp;환경과&amp;nbsp;동일한&amp;nbsp;구성으로&amp;nbsp;이루어져&amp;nbsp;있기&amp;nbsp;때문에&amp;nbsp;운영환경과&amp;nbsp;DR&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;동시에&amp;nbsp;제어할&amp;nbsp;수&amp;nbsp;있음&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이와 같은 장점을 제공하는 반면 다음과 같은 단점도 존재한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;lt;단점&amp;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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;인프라, 유지관리 인력 등 On-Premise를 운영하기 위한 대규모 선행 투자 및 망 분리 관리를 위한 또 다른 데이터 센터가 필요&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;DR 센터의 데이터를 동기화하는데 필요한 운영 오버헤드 발생&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;재해 발생 시 DNS 라우팅 설정, L4 라우팅 설정 등은 수동 절체 과정을 거쳐야 함&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;DR 환경을 성공적으로 구축하였는가에 대한 부분은 크게 두가지 측면으로 평가할 수 있다. 그 첫번째는 얼마나 고가용성이 높고 성능을 최대한 확보한 환경을 빠르게 회복할 수 있는가이며, 두번째는 바로 데이터에 대한 정합성을 높이고 유실을 최소화 할 수 있는가이다. 바로 RTO / RPO에 대한 내용에서부터 접근해 볼 수 있을 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이 중 고가용성과 성능에 대한 부분은 솔루션 디펜드한 내용들이 많이 포함되어야 하므로, 본 포스팅에서는 제외하도록 하고, 데이터 유실을 최소화 하기 위한 데이터 복제 방식에 대해 알아보도록 하자.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;On-Premise&amp;nbsp;데이터&amp;nbsp;센터&amp;nbsp;간&amp;nbsp;복제에는&amp;nbsp;사용&amp;nbsp;가능한&amp;nbsp;많은&amp;nbsp;기술&amp;nbsp;옵션이&amp;nbsp;존재한다.&amp;nbsp;결국&amp;nbsp;DR&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; letter-spacing: 0px; color: #000000;&quot;&gt;&lt;span&gt;&amp;lt;On Premise&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;데이터 복제 방안&amp;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: 'Noto Serif KR'; color: #000000;&quot;&gt;호스트 기반 복제 : 호스트 기반 복제는 개별 로컬 스토리지에 데이터를 적재하기 때문에, 별도 공유 볼륨에 대한 고려가 필요하지 않다. 호스트 기반 복제는 &quot;단일&quot; 하이퍼바이저 수준, 볼륨 수준 또는 파일 수준에서 발생한다. 이를 구현하기 위한 호스트 기반 복제 소프트웨어는 DR Fail-Over 및 Fail-Back 기능을 추가하여 보다 완전한 형태의 솔루션으로 성장하고 있다. 다만, 호스트 기반 복제의 경우 공유 볼륨이 필요하지 않은 단일 호스트 내 Object를 활용한다는 제약 조건이 존재하여 클라우드 환경에서 그 활용성은 매우 떨어진다.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;애플리케이션 기반 확장 클러스터 : 애플리케이션 기반 확장 클러스터는 데이터 센터 장애를 극복하기 위해 두 데이터 센터에 걸쳐 애플리케이션 클러스터 기술을 구현한다. 애플리케이션 기반 클러스터는 솔루션에 따라 동기 및 비동기 장애 조치 기능을 모두 지원할 수 있으므로 Critical 시스템 복구에 적합하다. 그러나 이들은 특정 애플리케이션에만 적합한 솔루션이고, 개발/유지보수 비용이 적지않게 발생한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;애플리케이션 기반 복제 : 기존 애플리케이션, 특히 데이터베이스는 항상 다른 데이터베이스로 복제 및 장애 조치하는 기술을 제공했다. 그러나 동기식 복제 기능이 부족하여 중요 시스템 복구에만 적용하는 것이 적합하다. 애플리케이션 기반 복제 솔루션은 복제가 애플리케이션을 인식하므로 스냅샷 및 기타 유사한 인스턴스를 스크립팅할 필요 없이 애플리케이션 상태 일관성이 유지된다는 장점이 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;스토리지 기반 복제 : 가장 많은 경우에서 선택되고 있는 Critical 시스템 복제에 적합한 스토리지 기반 복제이다. 이는 동기식 복제를 지원한다. 다만, 동기 복제는 자동화 구성이 어려워 관리 오버헤드를 증가 시킬 수 있다. 복제 중단 및 볼륨 re-마운트와 같은 작업이 필요에 따라 수동으로 실행해야 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;확장된 저장소 클러스터 : 확장된 스토리지 클러스터는 고급 스토리지 어레이 미러링 및 장애 조치 기능을 활용하여 2개의 물리적 데이터 센터에 분산된 단일 논리적 데이터 센터를 생성한다. 확장된 스토리지 클러스터는 호스트 중단 없이 다운타임 및 디스크 어레이 장애를 견뎌내고 데이터 센터 간 가상 머신의 라이브 마이그레이션 및 HA와 같은 가상화 기능과 함께 사용된다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;백업 기반 : 디스크 백업 또는 테이프로 DR을 수행하는 기존 백업 방식은&amp;nbsp;&amp;nbsp;RTO/RPO가 시간 또는 일 단위로 측정되는 DR 시나리오에만 적합하다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; letter-spacing: 0px; color: #000000;&quot;&gt;※&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Case 2: On-Premise 데이터 센터 &amp;rarr; Public Cloud DR&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;퍼블릭 클라우드는 탄력적인 컴퓨팅 및 스토리지를 갖춘 데이터 센터를 제공하기 때문에 DR 위치에 대한 새로운 옵션으로 떠오르고 있다. DR로서의 퍼블릭 클라우드는 매몰 비용을 줄이고, 특히 망 분리 원칙에 따른 두 번째 데이터 센터를 구축 및 유지 관리할 필요가 없다는 점에서 최근 많은 각광을 받고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;또한 퍼블릭 클라우드의 사용량 기반 비용 차지 방식은 DR로 부터 발생하는 유지 관리 비용을 최소화 할 수 있다.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Public Cloud DR 환경을 구성하기 위해 먼저 다음사항에 대해 검토해 보도록 하자.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;첫째, 클라우드 서비스를 제공하는 업체(Cloud Service Provider &amp;gt; AWS, Azure, GCP 등 이하 CSP)는 주로 가상화된 Windows 및 Linux 운영 체제를 지원한다. 즉, 일부 애플리케이션 및 플랫폼은 먼저 온프레미스에서 호환 가능한 플랫폼으로 마이그레이션 및 가상화가 선행되어야 한다.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;둘째, 대부분의 CSP는 온프레미스 하이퍼바이저와 다른 하이퍼바이저를 활용하므로 재해 복구 시점에 하이퍼바이저 마이그레이션이 필요하다. 여러 DR 솔루션은 이를 복제 기술의 내장된 일부로 제공하여 복제 및 장애 조치 프로세스 중에 가상화된 시스템을 변환해야 한다.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;셋째, 온-프레미스 VM을 CSP 상에서 제공하는 인스턴스로 복제하는데 사용할 수 있는 복제 기술이 여러 가지 있지만 모두 비동기 복제 기능만 제공한다. 이는 퍼블릭 클라우드 제공자에게 DR을 수행할 때 항상 약간의 데이터 손실이 있음을 의미한다.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;넷째, VM을 CSP로 마이그레이션하기 위해 네트워킹 도구 및 NAS(Network-Attached Storage)와 같은 인프라의 DR을 위한 복제를 구성할 경우 CSP에서는 동일한 기능 제공하지 않을 수 있다.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1512&quot; data-origin-height=&quot;1096&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nfDVp/btrRK18Hssf/bKscWfrJttiuuDtJDWF8z1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nfDVp/btrRK18Hssf/bKscWfrJttiuuDtJDWF8z1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nfDVp/btrRK18Hssf/bKscWfrJttiuuDtJDWF8z1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnfDVp%2FbtrRK18Hssf%2FbKscWfrJttiuuDtJDWF8z1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1512&quot; height=&quot;1096&quot; data-origin-width=&quot;1512&quot; data-origin-height=&quot;1096&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;On-Premise to Public Cloud의 경우 비용 측면에서 가장 큰 장점이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&amp;lt;장점&amp;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;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;하드웨어 및 데이터 센터가 유틸리티로 제공되기 때문에 초기 설비 투자가 필요하지 않고, 비용 역시 사용량 기반 차지한다.&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;보조 데이터 센터에 대한 하드웨어 또는 데이터 센터 유지 관리 비용이 없다.&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;복제, DR 오케스트레이션 및 하이퍼바이저 변환에 여러 옵션을 사용할 수 있다.&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;데이터 센터와 서비스는 CSP을 통해 즉시 사용할 수 있으므로 DR 프로젝트 실현 시간을 최소화할 수 있다. 또한 자체 DR용 데이터 센터를 구축할 필요가 없다.&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;반대로 플랫폼에 대한 제약이나, CSP에서 제공하는 서비스에 한정적으로 접근해야 한다는 점이 단점이 될 수 있다. 예를 들어 JEUS/WebtoB/Tibero와 같은 국내 솔루션을 사용하는 기업의 경우 Public Cloud로 전환 시 해당 서비스를 클라우드에 올리기 위한 작업을 별도로 진행해야 한다.&amp;nbsp;&lt;/span&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;최근 Naver Cloud에서는 해당 솔루션이 Managed Service로 추가되었는데, 이와 같이 솔루션의 제약 사항은 Public Cloud로의 전환에 걸림돌이 될 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;lt;단점&amp;gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;CSP에서 제공하는 OS는 대부분 Windows 또는 Linux에서 실행되는 가상화된 워크로드만 지원하기 때문에 대부분의 DR 시나리오에는 하이퍼바이저 마이그레이션이 필요하다. UNIX 또는 메인프레임은 지원하지 않는다.&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;CSP에 대한 네트워킹 및 파일 서비스(NAS)와 같은 인프라의 DR에는 더 많은 주의가 필요하다.&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;온-프레미스에서 CSP로 데이터를 복제하는데는 비동기식 복제 기술만 사용할 수 있으며, 이는 데이터 손실이 필요하지 않은 애플리케이션에 영향을 준다.&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;온-프레미스에서 CSP까지의 네트워크 대역폭이 제한될 수 있다.&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;장애 조치(failover) 후 퍼블릭 환경을 운영하기 위한 운영자가 필요하다. 이는 운영자가 관리해야 하는 플랫폼이 두배로 늘어 나기 때문에 운영조직의 부담으로 작용할 수 있다. (평시에는 운영 비용이 감소하지만, 실제 장애 조치 발생 시 운영할 수 있는 인력이 필수적으로 필요하다.)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;CSP로의 데이터 복제 기술은 여러가지 방법으로 접근해 볼 수 있다. 다음은 여러 기술 셋에 대한 복제 방법들이다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; letter-spacing: 0px; color: #000000;&quot;&gt;&lt;span&gt;&amp;lt;Public Cloud&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;데이터 복제 방안&amp;gt;&lt;/span&gt;&lt;/p&gt;
&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: 'Noto Serif KR'; color: #000000;&quot;&gt;DR 복제 소프트웨어 : 기존 DR 및 데이터 복제 솔루션을 납품하는 업체에서 퍼블릭 클라우드 환경 상에서 호스트 또는 하이퍼바이저 기반 복제 기능을 제공한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;CSP가 제공하는 Managed Service를 활용한 DR 복제 : CSP는 클라우드에 DR을 제공하기 위해 기본 SaaS 솔루션을 제공한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;하이퍼바이저에서 제공하는 하이브리드 클라우드 모델 : 하이퍼바이저 전환 및 운영 환경 변경 없이 온프레미스 환경을 CSP상에 확장하고 기존 온프레미스 DR 솔루션을 CSP로 복제 및 마이그레이션 할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;하이브리드 클라우드 스토리지 파일 시스템 : 스토리지 공급업체는 스토리지 기반 복제를 활용하여 CSP에 DR을 제공함으로써 온프레미스 데이터 센터와 CSP 간의 하이브리드 아키텍처로 소프트웨어 정의 스토리지(SDS) 소프트웨어를 배포한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;CSP에 대한 백업 기반 DR : 기존 백업 소프트웨어 제공 업체는 온프레미스와 CSP 모두에 백업 소프트웨어를 배포하여 DR 서비스를 제공하기 위해 백업 이미지를 CSP에 복제한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;letter-spacing: normal; color: #000000;&quot;&gt;Public Cloud DR vs On Premise DR 비교&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;DR 환경에 대한 Public vs On Premise를 비교해 보자. (장점&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;파란색&lt;/span&gt;, 단점&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;빨간색&lt;/span&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 105px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 17.5194%; height: 21px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 38.6821%; height: 21px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #ffffff;&quot;&gt;Public Cloud DR&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 43.7984%; height: 21px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #ffffff;&quot;&gt;On Premise DR&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 17.5194%; height: 21px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;안정성 (사례)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 38.6821%; height: 21px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #ee2323;&quot;&gt;적음&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 43.7984%; height: 21px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #006dd7;&quot;&gt;매우 많은&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 17.5194%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;비용&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 38.6821%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;사용량 기반 비용을 차지하며,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;매몰비용이 낮음&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 43.7984%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;별도 데이터 센터가 필요하며,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;매몰비용이 매우 높음&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 17.5194%; height: 21px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;데이터 복제&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 38.6821%; height: 21px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;네트워크 대역폭에 대한 한계가 발생할 수 있음&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 43.7984%; height: 21px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;고성능, 고대역폭 스토리지 기반 동기식 복제 지원&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 17.5194%; height: 21px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;구축 효율성&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 38.6821%; height: 21px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;DR 데이터 센터는 구축할 필요가 없지만 솔루션 구축에 비용이 발생함 (대체 솔루션 등)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 43.7984%; height: 21px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;손쉬운 구축 및 이전 가능&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 17.5194%; height: 21px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;유지보수&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 38.6821%; height: 21px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;운영 사업자 관점에서 관리해야 할 환경이 두배로 늘어나기 때문에 인력 관점의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;비용 증가&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 43.7984%; height: 21px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;운영 환경과 동일한 환경으로 운영관리&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;비용 감소&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 17.5194%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;RPO&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 38.6821%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;데이터 유실 발생&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(최소화 방안 수립 필요)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 43.7984%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;RPO 제로&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;가능&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 17.5194%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;통합관리&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 38.6821%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;불가능&lt;br /&gt;(클라우드 인프라 관리포털 별도 개발 가능)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 43.7984%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;네트워크 연동이 가능할 경우 통합 대시보드 구축 가능&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;결론적으로 인프라에 대한 매몰 비용을 최소화 할 수 있다는 점에서 Public Cloud DR 환경이 각광받고 있지만, 데이터 유실이 발생할 수 있으며, 아키텍처에 대한 충분한 검토가 진행되어야 한다는 점을 충분히 고려하고 선택해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;결론&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;재해 발생 후 비즈니스 연속성 및 기술적 대응성을 유지하는 것은 비즈니스의 최우선 순위 중 하나여야 한다. 재해 복구 전략이 누락되거나 실패할 경우 단순 비용적인 손해 뿐만 아니라, 고객의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;평판 및 점유율 하락등에 직면할 수도 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이를 위해 DR 환경을 구성하는 것은 중요하고 상세한 전략을 통해 구축되어야 할 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;※ 참조&lt;/span&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;DR 관련 용어&lt;/span&gt;&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: 'Noto Serif KR'; color: #000000;&quot;&gt;최대 허용 중단 (MAO -&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;Maximum Acceptable Outage&lt;/span&gt;) : 허용 가능한 최대 서비스 중단 시간&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;복구 지점 목표 (RPO - Recovery Point Objective) : 오류 또는 오류로 인해 데이터가 손실될 수 있는 최대 기간을 정의. 복구 지점은 재해 발생 후 견딜 수 있는 잠재적인 데이터 손실의 양을 나타냄.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;복구 시간 목표 (&lt;span style=&quot;color: #000000;&quot;&gt;RTO - Recovery&amp;nbsp;Time&amp;nbsp;Objective&lt;/span&gt;) : 재해 선언 후 비즈니스 또는 애플리케이션이 복구 절차를 시작하여 서비스를 사용할 수 있을 때까지의 시간.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;RTO/RPO 선정기준 (예시)&lt;/span&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 336px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 42px;&quot;&gt;
&lt;td style=&quot;width: 6.39535%; text-align: center; height: 42px;&quot;&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #ffffff;&quot;&gt;순번&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 11.5116%; text-align: center; height: 42px;&quot;&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #ffffff;&quot;&gt;중요도&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 7.67442%; text-align: center; height: 42px;&quot;&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #ffffff;&quot;&gt;복구&lt;br /&gt;시간&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 10.2326%; text-align: center; height: 42px;&quot;&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #ffffff;&quot;&gt;데이터&lt;br /&gt;유실허용&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 64.1861%; text-align: center; height: 42px;&quot;&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #ffffff;&quot;&gt;&amp;nbsp;상세 내용&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 63px;&quot;&gt;
&lt;td style=&quot;width: 6.39535%; text-align: center; height: 63px;&quot;&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;0&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 11.5116%; height: 63px;&quot;&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;중요한&lt;br /&gt;IT 인프라&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 7.67442%; height: 63px;&quot;&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;0-15분&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 10.2326%; height: 63px;&quot;&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;0분&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 64.1861%; height: 63px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;. 비즈니스 기능 이전에 복원할 기본 인프라 및 공통 서비스&lt;br /&gt;- 사전 구축 및 기동 시간 소요 수준&lt;br /&gt;- 환경 정보는 실시간 복제&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 42px;&quot;&gt;
&lt;td style=&quot;width: 6.39535%; text-align: center; height: 42px;&quot;&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 11.5116%; height: 42px;&quot;&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;제로다운&lt;br /&gt;타임&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 7.67442%; height: 42px;&quot;&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;0-15분&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 10.2326%; height: 42px;&quot;&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1 시간&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 64.1861%; height: 42px;&quot;&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;. 지속적으로 사용할 수 있어야 하는 중요한 비즈니스 기능&lt;br /&gt;- 이러한 애플리케이션은 장애에 대해 광범위하게 복원할 수 있도록 설계&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 63px;&quot;&gt;
&lt;td style=&quot;width: 6.39535%; text-align: center; height: 63px;&quot;&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 11.5116%; height: 63px;&quot;&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;미션&lt;br /&gt;크리티컬&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 7.67442%; height: 63px;&quot;&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;lt;1시간&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 10.2326%; height: 63px;&quot;&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;8 시간&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 64.1861%; height: 63px;&quot;&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;. 고객 대면 및 수익 창출 응용 프로그램과 같이 회사의 지속적인 운영에 가장 큰 영향을 미치는 비즈니스 기능&lt;br /&gt;- 지속적으로 사용할 수 있도록 설계되지는 않았지만 신속하게 복구할 수 있어야 함&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 42px;&quot;&gt;
&lt;td style=&quot;width: 6.39535%; text-align: center; height: 42px;&quot;&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;3&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 11.5116%; height: 42px;&quot;&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;비즈니스&lt;br /&gt;크리티컬&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 7.67442%; height: 42px;&quot;&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;lt;24시간&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 10.2326%; height: 42px;&quot;&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;24 시간&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 64.1861%; height: 42px;&quot;&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;. 복구가 필요하지만 덜 중요한 고객 대면 또는 수익에 영향을 미치는 애플리케이션&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 42px;&quot;&gt;
&lt;td style=&quot;width: 6.39535%; text-align: center; height: 42px;&quot;&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;4&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 11.5116%; height: 42px;&quot;&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;중요&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 7.67442%; height: 42px;&quot;&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;lt;1주&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 10.2326%; height: 42px;&quot;&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;일주&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 64.1861%; height: 42px;&quot;&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;. 중요한 비즈니스 프로세스를 지원하지만 즉시 복구하는 것이 중요하지 않은 애플리케이션&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 42px;&quot;&gt;
&lt;td style=&quot;width: 6.39535%; text-align: center; height: 42px;&quot;&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;5&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 11.5116%; height: 42px;&quot;&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;연기&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 7.67442%; height: 42px;&quot;&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt;1주&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 10.2326%; height: 42px;&quot;&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;마지막&lt;br /&gt;백업&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 64.1861%; height: 42px;&quot;&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;. 중요한 비즈니스 프로세스를 지원하지만 즉시 필요하지 않은 비즈니스 애플리케이션&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>③ 클라우드</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/784</guid>
      <comments>https://waspro.tistory.com/784#entry784comment</comments>
      <pubDate>Tue, 22 Nov 2022 05:17:09 +0900</pubDate>
    </item>
    <item>
      <title>AWS CodeSeries 파이프라인 구성하기 (buildspec.yml)</title>
      <link>https://waspro.tistory.com/780</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;개요&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;이번 포스팅은 AWS Code Series 파이프라인 구성 과정에 대해 알아보도록 하자.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;① AWS EKS 환경에 MariaDB 구축&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;b&gt;② AWS Code Series 파이프라인 구축&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;AWS Code Series 파이프라인 구축&lt;/span&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;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;AWSCLI &amp;amp; AWS CodeCommit&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Eclipse AWS Toolkit &amp;amp; AWS CodeCommit&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;주요 Configuration File 확인&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;AWS CodeBuild&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;AWS CodePipeline&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;AWSCLI &amp;amp; AWS CodeCommit&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;먼저 AWS CodeCommit과의 통합을 위해 Windows 환경에 AWS Credential을 연결해야 한다. AWS Credential을 연결하는 방법은 Eclipse에서 직접 연결하는 방법과 Windows CLI에서 git cli를 사용하기 위해 aws configure를 이용하는 방법이 있다. 먼저 AWS Configure를 이용하여 Windows CLI에서 CodeCommit에 접근하는 과정을 살펴보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1) aws configure&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;▶&amp;nbsp;windows에서 aws command line interface를 사용하기 위해서는 아래와 같이 windows 용 installer를 설치해야 한다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;AWSCLI 설치 :&amp;nbsp;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://awscli.amazonaws.com/AWSCLIV2.msi&quot;&gt;https://awscli.amazonaws.com/AWSCLIV2.msi&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이와 함께 GRC(git-remote-codecommit)을 사용하기 위해 python과 git을 설치한다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;Python 설치 :&amp;nbsp;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://www.python.org/&quot;&gt;https://www.python.org/&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Git 설치 :&amp;nbsp;&lt;a style=&quot;color: #000000;&quot; href=&quot;http://git-scm.com/downloads&quot;&gt;http://git-scm.com/downloads&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;설치가 완료되면 다음과 같이 aws configre 명령어를 통해 aws credential을 연결한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1662849507800&quot; class=&quot;routeros&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;C:\Users\user&amp;gt;aws configure
AWS Access Key ID [None]: AAAAAAAAAAAAA
AWS Secret Access Key [None]: BBBBBBBBBBBBBBBBBBBBBBBBB
Default region name [None]: ap-northeast-2
Default output format [None]: json

C:\Users\user&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2) GRC 설치&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;▶&amp;nbsp;git-remote-codecommit을 설치하기 위해 pip install git-remote-codecommit을 CLI 창에서 실행한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1662849507801&quot; class=&quot;angelscript&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;C:\Users\user&amp;gt;pip install git-remote-codecommit
Collecting git-remote-codecommit
  Downloading git-remote-codecommit-1.16.tar.gz (7.0 kB)
  Preparing metadata (setup.py) ... done
Collecting botocore&amp;gt;=1.17.0
  Downloading botocore-1.27.66-py3-none-any.whl (9.1 MB)
     ---------------------------------------- 9.1/9.1 MB 30.6 MB/s eta 0:00:00
Collecting python-dateutil&amp;lt;3.0.0,&amp;gt;=2.1
  Downloading python_dateutil-2.8.2-py2.py3-none-any.whl (247 kB)
     ---------------------------------------- 247.7/247.7 kB ? eta 0:00:00
Collecting jmespath&amp;lt;2.0.0,&amp;gt;=0.7.1
  Downloading jmespath-1.0.1-py3-none-any.whl (20 kB)
Collecting urllib3&amp;lt;1.27,&amp;gt;=1.25.4
  Downloading urllib3-1.26.12-py2.py3-none-any.whl (140 kB)
     ---------------------------------------- 140.4/140.4 kB 8.7 MB/s eta 0:00:00
Collecting six&amp;gt;=1.5
  Downloading six-1.16.0-py2.py3-none-any.whl (11 kB)
Using legacy 'setup.py install' for git-remote-codecommit, since package 'wheel' is not installed.
Installing collected packages: urllib3, six, jmespath, python-dateutil, botocore, git-remote-codecommit
  Running setup.py install for git-remote-codecommit ... done
Successfully installed botocore-1.27.66 git-remote-codecommit-1.16 jmespath-1.0.1 python-dateutil-2.8.2 six-1.16.0 urllib3-1.26.12

[notice] A new release of pip available: 22.2.1 -&amp;gt; 22.2.2
[notice] To update, run: python.exe -m pip install --upgrade pip

C:\Users\user&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;3) Code Commit Repository 생성&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;▶ CodeCommit - Repository &amp;gt; 리포지토리 생성&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_2. code commit.png&quot; data-origin-width=&quot;1915&quot; data-origin-height=&quot;935&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cak7lF/btrLQmWZGYu/fsHRF1cWxFBDaOuWhPxZSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cak7lF/btrLQmWZGYu/fsHRF1cWxFBDaOuWhPxZSK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cak7lF/btrLQmWZGYu/fsHRF1cWxFBDaOuWhPxZSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcak7lF%2FbtrLQmWZGYu%2FfsHRF1cWxFBDaOuWhPxZSK%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;1915&quot; height=&quot;935&quot; data-filename=&quot;edited_2. code commit.png&quot; data-origin-width=&quot;1915&quot; data-origin-height=&quot;935&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: 'Noto Serif KR'; color: #000000;&quot;&gt;Repository가 생성되면, URL 복제 - HTTPS(GRC) 복제를 선택하여 URL 정보를 복사한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;4) git init &amp;amp; push&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;▶&amp;nbsp;git init - git remote add - git add - git commit - git push 순으로 동일하게 git repository를 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1662849507801&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;D:\[NRSon] 개발관련\cospro_workspace\hikariTest\springboot-hikari-jdbc-mysql&amp;gt;git init
Initialized empty Git repository in D:/[NRSon] 개발관련/cospro_workspace/hikariTest/springboot-hikari-jdbc-mysql/.git/

D:\[NRSon] 개발관련\cospro_workspace\hikariTest\springboot-hikari-jdbc-mysql&amp;gt;git remote add origin codecommit::ap-northeast-2://nrson-repository

D:\[NRSon] 개발관련\cospro_workspace\hikariTest\springboot-hikari-jdbc-mysql&amp;gt;git add .

D:\[NRSon] 개발관련\cospro_workspace\hikariTest\springboot-hikari-jdbc-mysql&amp;gt;git commit -m &quot;first commit&quot;
[master (root-commit) a60f3e5] first commit
 20 files changed, 2627 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 LICENSE
 create mode 100644 ReadMe.md
 create mode 100644 bin/pom.xml
 create mode 100644 pom.xml
 ...
 create mode 100644 src/main/resources/application.properties

D:\[NRSon] 개발관련\cospro_workspace\hikariTest\springboot-hikari-jdbc-mysql&amp;gt;git push origin master
Enumerating objects: 35, done.
Counting objects: 100% (35/35), done.
Delta compression using up to 12 threads
Compressing objects: 100% (27/27), done.
Writing objects: 100% (35/35), 22.77 KiB | 1.75 MiB/s, done.
Total 35 (delta 2), reused 0 (delta 0), pack-reused 0
To codecommit::ap-northeast-2://nrson-repository
 * [new branch]      master -&amp;gt; master

D:\[NRSon] 개발관련\cospro_workspace\hikariTest\springboot-hikari-jdbc-mysql&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;앞서 복사한 GRC URL을 이용하여 push를 진행한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;5) repository 확인&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_3. git push.png&quot; data-origin-width=&quot;1916&quot; data-origin-height=&quot;936&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zUGew/btrLLiouH2I/rB4XuhvAnGuTTgwJXtqc21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zUGew/btrLLiouH2I/rB4XuhvAnGuTTgwJXtqc21/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zUGew/btrLLiouH2I/rB4XuhvAnGuTTgwJXtqc21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzUGew%2FbtrLLiouH2I%2FrB4XuhvAnGuTTgwJXtqc21%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;1916&quot; height=&quot;936&quot; data-filename=&quot;edited_3. git push.png&quot; data-origin-width=&quot;1916&quot; data-origin-height=&quot;936&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: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 nrson-repository에 push된 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Eclipse AWS Toolkit &amp;amp; AWS CodeCommit&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이번에는 Eclipse AWS Toolkit을 이용하여 AWS CodeCommit에 접근해 보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1) AWS Toolkit Install&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;▶&amp;nbsp;Eclipse - Help - Install New Software - Work With 입력 (&lt;a style=&quot;color: #000000;&quot; href=&quot;http://aws.amazon.com/eclipse)&quot;&gt;http://aws.amazon.com/eclipse)&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l1AMC/btrLNqMAEAG/G5hO3llvQrqrxEYQ6jo6C1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l1AMC/btrLNqMAEAG/G5hO3llvQrqrxEYQ6jo6C1/img.png&quot; style=&quot;width: 49.2993%; margin-right: 10px;&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;867&quot; data-origin-height=&quot;703&quot; data-filename=&quot;edited_4. eclipse aws toolkit.png&quot; data-widthpercent=&quot;49.88&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l1AMC/btrLNqMAEAG/G5hO3llvQrqrxEYQ6jo6C1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl1AMC%2FbtrLNqMAEAG%2FG5hO3llvQrqrxEYQ6jo6C1%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;867&quot; height=&quot;703&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PvJgf/btrLR9pyX5t/1lY0kCWOkhuvEwSdl4yktK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PvJgf/btrLR9pyX5t/1lY0kCWOkhuvEwSdl4yktK/img.png&quot; style=&quot;width: 49.5379%;&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;865&quot; data-origin-height=&quot;698&quot; data-filename=&quot;5. eclipse aws toolkit.png&quot; data-widthpercent=&quot;50.12&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PvJgf/btrLR9pyX5t/1lY0kCWOkhuvEwSdl4yktK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPvJgf%2FbtrLR9pyX5t%2F1lY0kCWOkhuvEwSdl4yktK%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;865&quot; height=&quot;698&quot;/&gt;&lt;/span&gt;&lt;/div&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;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;AWS Core Management Tools - AWS Toolkit for Eclipse Core (Required)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;AWS Developer Tools - AWS CodeCommit Plugin&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위 두개 패키지 선택 후 Next - 동의 - Finash - Restart Now 순으로 Install을 진행한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2) AWS Explorer&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;▶&amp;nbsp;재기동 후 AWS Credential을 입력하면 다음과 같이 AWS Explorer를 통해 AWS Resource에 접근할 수 있다.&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;1920&quot; data-origin-height=&quot;1034&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rfJEf/btrLPekBSql/jUl2WyTyrzkf68KFjAJkxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rfJEf/btrLPekBSql/jUl2WyTyrzkf68KFjAJkxk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rfJEf/btrLPekBSql/jUl2WyTyrzkf68KFjAJkxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrfJEf%2FbtrLPekBSql%2FjUl2WyTyrzkf68KFjAJkxk%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;1034&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1034&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: 'Noto Serif KR'; color: #000000;&quot;&gt;Eclipse의 [Window] &amp;gt; [Show View] &amp;gt; [Other] &amp;gt; [AWS Toolkit] &amp;gt; [AWS Explorer]&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;571&quot; data-origin-height=&quot;231&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ciyvkP/btrLTV5CxFI/cc50v7FV8AbFd1kRcTNL71/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ciyvkP/btrLTV5CxFI/cc50v7FV8AbFd1kRcTNL71/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ciyvkP/btrLTV5CxFI/cc50v7FV8AbFd1kRcTNL71/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FciyvkP%2FbtrLTV5CxFI%2Fcc50v7FV8AbFd1kRcTNL71%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;571&quot; height=&quot;231&quot; data-origin-width=&quot;571&quot; data-origin-height=&quot;231&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: 'Noto Serif KR'; color: #000000;&quot;&gt;3) AWS CodeCommit Repository Clone &amp;amp; Commit&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;433&quot; data-origin-height=&quot;493&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cIcR9m/btrLR76lqeg/zmo62XZBQhDFkAfqhU2LDk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cIcR9m/btrLR76lqeg/zmo62XZBQhDFkAfqhU2LDk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cIcR9m/btrLR76lqeg/zmo62XZBQhDFkAfqhU2LDk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcIcR9m%2FbtrLR76lqeg%2Fzmo62XZBQhDFkAfqhU2LDk%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;433&quot; height=&quot;493&quot; data-origin-width=&quot;433&quot; data-origin-height=&quot;493&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: 'Noto Serif KR'; color: #000000;&quot;&gt;▶&amp;nbsp;git clone repostiroy&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;6. clone repository.png&quot; data-origin-width=&quot;1917&quot; data-origin-height=&quot;1037&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ouB18/btrLOgJLbut/dD8xihNHCEs0tYvO9he4N0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ouB18/btrLOgJLbut/dD8xihNHCEs0tYvO9he4N0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ouB18/btrLOgJLbut/dD8xihNHCEs0tYvO9he4N0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FouB18%2FbtrLOgJLbut%2FdD8xihNHCEs0tYvO9he4N0%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;1917&quot; height=&quot;1037&quot; data-filename=&quot;6. clone repository.png&quot; data-origin-width=&quot;1917&quot; data-origin-height=&quot;1037&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: 'Noto Serif KR'; color: #000000;&quot;&gt;▶&amp;nbsp;import project&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;7. clone repository.png&quot; data-origin-width=&quot;1914&quot; data-origin-height=&quot;1036&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bi0Wjh/btrLPd6290E/z4KyNyjgLvZ861HwkQkaek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bi0Wjh/btrLPd6290E/z4KyNyjgLvZ861HwkQkaek/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bi0Wjh/btrLPd6290E/z4KyNyjgLvZ861HwkQkaek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbi0Wjh%2FbtrLPd6290E%2Fz4KyNyjgLvZ861HwkQkaek%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;1914&quot; height=&quot;1036&quot; data-filename=&quot;7. clone repository.png&quot; data-origin-width=&quot;1914&quot; data-origin-height=&quot;1036&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: 'Noto Serif KR'; color: #000000;&quot;&gt;▶&amp;nbsp;commit datasource url 변경 후 commit &amp;amp; push&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;8. clone repository.png&quot; data-origin-width=&quot;1914&quot; data-origin-height=&quot;1035&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/R5wy6/btrLPoncrWs/xOmCYmyDuCempKhqKRnOqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/R5wy6/btrLPoncrWs/xOmCYmyDuCempKhqKRnOqk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/R5wy6/btrLPoncrWs/xOmCYmyDuCempKhqKRnOqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FR5wy6%2FbtrLPoncrWs%2FxOmCYmyDuCempKhqKRnOqk%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;1914&quot; height=&quot;1035&quot; data-filename=&quot;8. clone repository.png&quot; data-origin-width=&quot;1914&quot; data-origin-height=&quot;1035&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: 'Noto Serif KR'; color: #000000;&quot;&gt;▶&amp;nbsp;CodeCommit 변경 반영 확인&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;9. clone repository.png&quot; data-origin-width=&quot;1916&quot; data-origin-height=&quot;961&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dSuRVa/btrLTCSzh4P/ns8GaogMLokFbdcZoTMXk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dSuRVa/btrLTCSzh4P/ns8GaogMLokFbdcZoTMXk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dSuRVa/btrLTCSzh4P/ns8GaogMLokFbdcZoTMXk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdSuRVa%2FbtrLTCSzh4P%2Fns8GaogMLokFbdcZoTMXk0%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;1916&quot; height=&quot;961&quot; data-filename=&quot;9. clone repository.png&quot; data-origin-width=&quot;1916&quot; data-origin-height=&quot;961&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: 'Noto Serif KR'; color: #000000;&quot;&gt;CodeCommit에 변경된 datasource url이 반영된 것을 알 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;주요 Configuration File 확인&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;다음으로 AWS CodeBuild를 수행하기 이전 Application Package에 포함해야 할 Configuration File에 대해 알아보자. 일반적으로 yaml 파일 형태로 구성한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;[Eclipse Project]&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;1169&quot; data-origin-height=&quot;756&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIBOEu/btrLPc1pHTT/KKttIlxm0Yz7htxCkICCVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIBOEu/btrLPc1pHTT/KKttIlxm0Yz7htxCkICCVk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIBOEu/btrLPc1pHTT/KKttIlxm0Yz7htxCkICCVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIBOEu%2FbtrLPc1pHTT%2FKKttIlxm0Yz7htxCkICCVk%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;1169&quot; height=&quot;756&quot; data-origin-width=&quot;1169&quot; data-origin-height=&quot;756&quot;/&gt;&lt;/span&gt;&lt;/figure&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;buildspec.yml&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;deployment.yaml&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;service.yaml&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Dockerfile&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;pom.xml&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;application.properties&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;▶ buildspec.yml&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1662851230990&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;version: 0.2
phases:
  install:
    runtime-versions:
      docker: 18
    commands:
      - echo Install Kubectl
      - echo ---------------------------------
      - curl -o kubectl https://amazon-eks.s3.us-west-2.amazonaws.com/1.19.6/2021-01-05/bin/linux/amd64/kubectl
      - chmod +x ./kubectl
      - mv ./kubectl /usr/local/bin/kubectl
      - mkdir ~/.kube
      - aws sts get-caller-identity
      - aws eks --region ap-northeast-2 update-kubeconfig --name NRSON-EKS-CLUSTER
      - kubectl get po -n kube-system
      - echo ---------------------------------
  pre_build:
    commands:
      - echo ENV Values
      - echo ---------------------------------
      - echo $AWS_DEFAULT_REGION
      - echo $IMAGE_REPO_NAME
      - echo $IMAGE_TAG
      - echo $AWS_ACCOUNT_ID
      - echo ---------------------------------
      - echo Logging in to Amazon ECR...
      - docker login -u AWS -p $(aws ecr get-login-password --region ap-northeast-2) &amp;lt;AWS_ACCOUNT_ID&amp;gt;.dkr.ecr.ap-northeast-2.amazonaws.com
  build:
    commands:
      - echo Build Docker Image
      - echo ---------------------------------
      - echo Build Starting on `date`
      - echo Building with maven...
      - mvn install
      - echo Building the Docker image...
      - docker build -t $IMAGE_REPO_NAME:$IMAGE_TAG .
      - docker tag $IMAGE_REPO_NAME:$IMAGE_TAG $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG
      - docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG
      - echo ---------------------------------
  post_build:
    commands:
      - echo Deploy Application
      - echo ---------------------------------
      - AWS_ECR_URI=$AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG
      - DATE=`date`
      - echo Build completed on $DATE
      - sed -i.bak 's#AWS_ECR_URI#'&quot;$AWS_ECR_URI&quot;'#' ./k8s/deployment.yaml
      - sed -i.bak 's#DATE_STRING#'&quot;$DATE&quot;'#' ./k8s/deployment.yaml
      - cat ./k8s/deployment.yaml
      - export KUBECONFIG=$KUBECONFIG:~/.kube/config
      - kubectl apply -f ./k8s/deployment.yaml
      - kubectl apply -f ./k8s/service.yaml
      - echo ---------------------------------&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;buildspec은 Phase 별로 나뉘어 진행된다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;① install : kubectl download, kubeconfig update&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;② pre_build : env setting, docker login&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;③ build : maven install, docker image build, docker image tagging, docker image push&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;④ post_build : kubernetes deploy (deployment, service)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;▶ deployment.yaml&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1662851325774&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: hikari-test-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: hikari-test
  template:
    metadata:
      labels:
        app: hikari-test
    spec:
      containers:
        - name: hikari-test
          image: AWS_ECR_URI
          ports:
            - containerPort: 8080
          imagePullPolicy: Always
          env:
            - name: DATE
              value: 'DATE_STRING'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;▶ service.yaml&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1662851338694&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: v1
kind: Service
metadata:
  name: hikari-test-service
spec:
  ports:
    - name: &quot;8080&quot;
      port: 8081
      targetPort: 8080
  selector:
    app: hikari-test
  type: LoadBalancer
#  type: ClusterIP&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;▶ Dockerfile&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1662851362630&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FROM openjdk:11.0-jdk
VOLUME /tmp
ADD ./target/springboot-hikari-jdbc-mysql.jar app.jar
ENV JAVA_OPTS=&quot;&quot;
ENTRYPOINT [&quot;java&quot;,&quot;-jar&quot;,&quot;/app.jar&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;deploymnet.yaml, service.yaml, Dockerfile은 kubernetes에 배포하는 일반적인 yaml 파일과 동일하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;▶ pom.xml&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1662852192269&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd&quot;&amp;gt;
	&amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;
	&amp;lt;parent&amp;gt;
		&amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
		&amp;lt;artifactId&amp;gt;spring-boot-starter-parent&amp;lt;/artifactId&amp;gt;
		&amp;lt;version&amp;gt;2.5.3&amp;lt;/version&amp;gt;
	&amp;lt;/parent&amp;gt;

	&amp;lt;groupId&amp;gt;com.mysql.springboot&amp;lt;/groupId&amp;gt;
	&amp;lt;artifactId&amp;gt;springboot-hikari-jdbc-mysql&amp;lt;/artifactId&amp;gt;
	&amp;lt;packaging&amp;gt;jar&amp;lt;/packaging&amp;gt;
	&amp;lt;version&amp;gt;1.0&amp;lt;/version&amp;gt;
	&amp;lt;name&amp;gt;springboot-hikari-jdbc-mysql&amp;lt;/name&amp;gt;
	&amp;lt;url&amp;gt;http://maven.apache.org&amp;lt;/url&amp;gt;

	&amp;lt;developers&amp;gt;
		&amp;lt;developer&amp;gt;
			&amp;lt;name&amp;gt;Metanoia&amp;lt;/name&amp;gt;
		&amp;lt;/developer&amp;gt;
	&amp;lt;/developers&amp;gt;

	&amp;lt;dependencies&amp;gt;
		&amp;lt;dependency&amp;gt;
			&amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
			&amp;lt;artifactId&amp;gt;spring-boot-starter-web&amp;lt;/artifactId&amp;gt;
		&amp;lt;/dependency&amp;gt;
		&amp;lt;dependency&amp;gt;
			&amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
			&amp;lt;artifactId&amp;gt;spring-boot-starter-test&amp;lt;/artifactId&amp;gt;
			&amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
		&amp;lt;/dependency&amp;gt;
		&amp;lt;dependency&amp;gt;
			&amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
			&amp;lt;artifactId&amp;gt;spring-boot-starter-jdbc&amp;lt;/artifactId&amp;gt;
			&amp;lt;exclusions&amp;gt;
				&amp;lt;exclusion&amp;gt;
					&amp;lt;groupId&amp;gt;org.apache.tomcat&amp;lt;/groupId&amp;gt;
					&amp;lt;artifactId&amp;gt;tomcat-jdbc&amp;lt;/artifactId&amp;gt;
				&amp;lt;/exclusion&amp;gt;
			&amp;lt;/exclusions&amp;gt;
		&amp;lt;/dependency&amp;gt;
		&amp;lt;dependency&amp;gt;
			&amp;lt;groupId&amp;gt;org.mariadb.jdbc&amp;lt;/groupId&amp;gt;
			&amp;lt;artifactId&amp;gt;mariadb-java-client&amp;lt;/artifactId&amp;gt;
		&amp;lt;/dependency&amp;gt;
	&amp;lt;/dependencies&amp;gt;

	&amp;lt;build&amp;gt;
		&amp;lt;finalName&amp;gt;springboot-hikari-jdbc-mysql&amp;lt;/finalName&amp;gt;
		&amp;lt;plugins&amp;gt;
			&amp;lt;plugin&amp;gt;
				&amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
				&amp;lt;artifactId&amp;gt;spring-boot-maven-plugin&amp;lt;/artifactId&amp;gt;
			&amp;lt;/plugin&amp;gt;
			&amp;lt;plugin&amp;gt;
				&amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;
				&amp;lt;artifactId&amp;gt;maven-compiler-plugin&amp;lt;/artifactId&amp;gt;
				&amp;lt;configuration&amp;gt;
					&amp;lt;source&amp;gt;11&amp;lt;/source&amp;gt;
					&amp;lt;target&amp;gt;11&amp;lt;/target&amp;gt;
				&amp;lt;/configuration&amp;gt;
			&amp;lt;/plugin&amp;gt;
		&amp;lt;/plugins&amp;gt;
	&amp;lt;/build&amp;gt;

	&amp;lt;dependencyManagement&amp;gt;
		&amp;lt;dependencies&amp;gt;
			&amp;lt;dependency&amp;gt;
				&amp;lt;groupId&amp;gt;com.zaxxer&amp;lt;/groupId&amp;gt;
				&amp;lt;artifactId&amp;gt;HikariCP&amp;lt;/artifactId&amp;gt;
				&amp;lt;version&amp;gt;5.0.0&amp;lt;/version&amp;gt;
			&amp;lt;/dependency&amp;gt;
		&amp;lt;/dependencies&amp;gt;
	&amp;lt;/dependencyManagement&amp;gt;
&amp;lt;/project&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;pom.xml은 spring-boot-starter와 mariadb-java-client를 포함하여 빌드하며, finalName으로 jar 파일 이름을 결정할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;▶ application.properties&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1662852214725&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# DATASOURCE (DataSourceAutoConfiguration &amp;amp; DataSourceProperties)
#spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.driverClassName=org.mariadb.jdbc.Driver
#spring.datasource.url=jdbc:mysql://&amp;lt;MARIADBIP&amp;gt;:&amp;lt;MARIADBPORT&amp;gt;/institute?useSSL=false
spring.datasource.url=jdbc:mysql://mariadb/institute?useSSL=false
spring.datasource.username=root
spring.datasource.password=DB_PASSWORD
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect

# HikariCP DataSource Properties
spring.datasource.hikari.connectionTimeout=30000
spring.datasource.hikari.minimumIdle=10
spring.datasource.hikari.maximumPoolSize=10 
spring.datasource.hikari.idleTimeout=100000 
spring.datasource.hikari.maxIdleTime=100000
spring.datasource.hikari.maxLifetime=110000
spring.datasource.hikari.poolName=HikariCP
#spring.datasource.hikari.connection-init-sql=set wait_timeout=105

#Spring Boot 2.0 includes HikariDataSource by default
## spring.datasource.type=com.zaxxer.hikari.HikariDataSource

# LOGGING
logging.level.root=ERROR
logging.level.com.mysql.springboot=INFO
logging.pattern.console=%-5level %logger{36} - %msg%n&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;application.properties는 hikari 관련 timeout과 DB 연결정보, 로깅정보를 포함하고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;AWS CodeBuild&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;AWS CodeBuild를 통해 CodeCommit에 Push 된 Application과 yaml 파일 등을 기반으로 AWS EKS에 배포할 수 있다. 이때 AWS CodeDeploy는 AWS EKS를 지원하지 않아 AWS CodeBuild로 배포해야 함에 유의한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;1) ECR Repository 생성&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Container(Docker Image) Image를 저장할 Elastic Container Registry 생성&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;1292&quot; data-origin-height=&quot;748&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/u7GO0/btrLTVR5qfI/xVKuxE4Xg2eI99NrskJX50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/u7GO0/btrLTVR5qfI/xVKuxE4Xg2eI99NrskJX50/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/u7GO0/btrLTVR5qfI/xVKuxE4Xg2eI99NrskJX50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fu7GO0%2FbtrLTVR5qfI%2FxVKuxE4Xg2eI99NrskJX50%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;1292&quot; height=&quot;748&quot; data-origin-width=&quot;1292&quot; data-origin-height=&quot;748&quot;/&gt;&lt;/span&gt;&lt;/figure&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;리포지토리 이름 : nrson-image-repository&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;2) 프로젝트 만들기&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;1291&quot; data-origin-height=&quot;917&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SxcrK/btrLLXjMY5W/2nzijKgGl0Ayk3mcNTLujk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SxcrK/btrLLXjMY5W/2nzijKgGl0Ayk3mcNTLujk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SxcrK/btrLLXjMY5W/2nzijKgGl0Ayk3mcNTLujk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSxcrK%2FbtrLLXjMY5W%2F2nzijKgGl0Ayk3mcNTLujk%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;1291&quot; height=&quot;917&quot; data-origin-width=&quot;1291&quot; data-origin-height=&quot;917&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: 'Noto Serif KR'; color: #000000;&quot;&gt;3) 빌드 프로젝트 생성&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;▶&amp;nbsp;프로젝트 구성&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;1309&quot; data-origin-height=&quot;700&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b1VARU/btrLTCygl69/4vBvo1k7H78liVJi9KyaD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b1VARU/btrLTCygl69/4vBvo1k7H78liVJi9KyaD0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b1VARU/btrLTCygl69/4vBvo1k7H78liVJi9KyaD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb1VARU%2FbtrLTCygl69%2F4vBvo1k7H78liVJi9KyaD0%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;1309&quot; height=&quot;700&quot; data-origin-width=&quot;1309&quot; data-origin-height=&quot;700&quot;/&gt;&lt;/span&gt;&lt;/figure&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;프로젝트 이름 : 이름 입력 (ex - NRSON-CODEBUILDER-HIKARI)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;설명 : Description&amp;nbsp;(ex - NRSON-CODEBUILDER-HIKARI)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;동시 빌드 제한 활성화 :&amp;nbsp; 동시에 빌드 가능한 수를 입력 (ex - 1)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;▶&amp;nbsp;소스&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;1306&quot; data-origin-height=&quot;916&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDondF/btrLMzbVPsT/xlo7E2ryVESfRTzWdv9hk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDondF/btrLMzbVPsT/xlo7E2ryVESfRTzWdv9hk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDondF/btrLMzbVPsT/xlo7E2ryVESfRTzWdv9hk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDondF%2FbtrLMzbVPsT%2Fxlo7E2ryVESfRTzWdv9hk0%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;1306&quot; height=&quot;916&quot; data-origin-width=&quot;1306&quot; data-origin-height=&quot;916&quot;/&gt;&lt;/span&gt;&lt;/figure&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;소스 공급자 : Amazon S3, AWS CodeCommit, GitHub, BitBucket, GitHub Enterprise 등을 지원하며, Repository를 선택 (ex - AWS CodeCommit)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;리포지토리 : 해당 소스 공급자에 등록되어 있는 Repository를 선택 (ex - nrson-repository)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;참조 유형 : 브랜치, Git Tag, Commit ID 중 배포 단위 선택 (ex - 브랜치)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;브랜치 : 선택한 Repository 중 Branch를 선택 (ex - master)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;커밋ID : Commit ID를 선택할 경우 보다 빠르게 배포가 가능하지만, 매번 새로운 버전을 배포하기 위해 변경이 필요함 (ex - commitID)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;소스 버전 : 최종 반영될 소스 버전 확인&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;▶&amp;nbsp;환경&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;1305&quot; data-origin-height=&quot;900&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/R9HYS/btrLPoOg0km/AFB0aSo4lnZZ7hsDeG0DU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/R9HYS/btrLPoOg0km/AFB0aSo4lnZZ7hsDeG0DU1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/R9HYS/btrLPoOg0km/AFB0aSo4lnZZ7hsDeG0DU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FR9HYS%2FbtrLPoOg0km%2FAFB0aSo4lnZZ7hsDeG0DU1%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;1305&quot; height=&quot;900&quot; data-origin-width=&quot;1305&quot; data-origin-height=&quot;900&quot;/&gt;&lt;/span&gt;&lt;/figure&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;환경이미지 : 관리형 이미지 또는 직접 생성한 사용자 지정 이미지 선택 (ex - 관리형 이미지)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;운영체제 : Amazon Linux 2 또는 Ubuntu 선택 (ex - Amazon Linux 2)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;런타임 (ex - Standard)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이미지 (ex - aws/codebuild/amazonlinux2-x86_64-standard:2.0)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이미지 버전 (ex - 이 런타임 버전에 항상 최신 이미지 사용)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;환경 유형 : Linux 또는 Windows 선택 (ex - Linux)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;권한이 있음 : Container 환경에 도커 이미지를 생성해야 하는 경우 활성화 (ex - 체크)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;서비스 역할 : 역할을 생성할 경우 새 서비스 역할, 기존 서비스를 사용할 경우 기존 서비스 역할 선택&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;▶&amp;nbsp;&lt;/span&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: 'Noto Serif KR'; color: #000000;&quot;&gt;AWSCodeCommitFullAccess&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;AmazonEKSClusterPolicy&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;AmazonEKSWorkerNodePolicy&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;AdministratorAccess&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;AmazonEKSServicePolicy&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;AWSCodePipelineFullAccess&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;AmazonEKS_CNI_Policy&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;AmazonEKSFargatePodExecutionRolePolicy&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;AmazonEKSVPCResourceController&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;▶&amp;nbsp;&lt;/span&gt;역할을 configmap에 추가&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;a. &lt;/span&gt;추가&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1662910430781&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    - rolearn: arn:aws:iam::&amp;lt;AWS_ACCOUNT_ID&amp;gt;:role/codebuild-EKS-DEPLOY-service-role
      username: codebuild-EKS-DEPLOY-service-role
      groups:
        - system:masters&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;b. &lt;/span&gt;완성된 형태&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1662910403054&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-10-192-10-183 EKS]# kubectl edit configmap aws-auth -n kube-system
# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: v1
data:
  mapRoles: |
    - groups:
      - system:bootstrappers
      - system:nodes
      rolearn: arn:aws:iam::&amp;lt;AWS_ACCOUNT_ID&amp;gt;:role/EKS-WORKERNODE-ROLE
      username: system:node:{{EC2PrivateDNSName}}
    - rolearn: arn:aws:iam::&amp;lt;AWS_ACCOUNT_ID&amp;gt;:role/codebuild-EKS-DEPLOY-service-role
      username: codebuild-EKS-DEPLOY-service-role
      groups:
        - system:masters
kind: ConfigMap
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {&quot;apiVersion&quot;:&quot;v1&quot;,&quot;data&quot;:{&quot;mapRoles&quot;:&quot;- groups:\n  - system:bootstrappers\n  - system:nodes\n  rolearn: arn:aws:iam::&amp;lt;AWS_ACCOUNT_ID&amp;gt;:role/EKS-WORKERNODE-ROLE\n  username: system:node:{{EC2PrivateDNSName}}\n- rolearn: arn:aws:iam::&amp;lt;AWS_ACCOUNT_ID&amp;gt;:role/service-role/codebuild-hikari-service-service-role\n  username: codebuild-hikari-service-service-role\n  groups:\n    - system:masters\n&quot;},&quot;kind&quot;:&quot;ConfigMap&quot;,&quot;metadata&quot;:{&quot;annotations&quot;:{},&quot;creationTimestamp&quot;:&quot;2022-09-02T04:44:12Z&quot;,&quot;managedFields&quot;:[{&quot;apiVersion&quot;:&quot;v1&quot;,&quot;fieldsType&quot;:&quot;FieldsV1&quot;,&quot;fieldsV1&quot;:{&quot;f:data&quot;:{&quot;.&quot;:{},&quot;f:mapRoles&quot;:{}}},&quot;manager&quot;:&quot;vpcLambda&quot;,&quot;operation&quot;:&quot;Update&quot;,&quot;time&quot;:&quot;2022-09-02T04:44:12Z&quot;}],&quot;name&quot;:&quot;aws-auth&quot;,&quot;namespace&quot;:&quot;kube-system&quot;,&quot;resourceVersion&quot;:&quot;1740&quot;,&quot;uid&quot;:&quot;cb95d265-05e3-4c37-880c-97fb57b3664c&quot;}}
  creationTimestamp: &quot;2022-09-09T21:34:16Z&quot;
  managedFields:
  - apiVersion: v1
    fieldsType: FieldsV1
    fieldsV1:
      f:data:
        .: {}
        f:mapRoles: {}
      f:metadata:
        f:annotations:
          .: {}
          f:kubectl.kubernetes.io/last-applied-configuration: {}
    manager: kubectl
    operation: Update
    time: &quot;2022-09-09T21:34:16Z&quot;
  name: aws-auth
  namespace: kube-system
  resourceVersion: &quot;3482&quot;
  uid: cc0ee350-2a4c-4d0d-ac9b-df8dafb3dee0
  [root@ip-10-192-10-183 EKS]#&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1306&quot; data-origin-height=&quot;613&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/twlrZ/btrLPnV8ex7/mIJnbROEr9n1PtFBXmllck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/twlrZ/btrLPnV8ex7/mIJnbROEr9n1PtFBXmllck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/twlrZ/btrLPnV8ex7/mIJnbROEr9n1PtFBXmllck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtwlrZ%2FbtrLPnV8ex7%2FmIJnbROEr9n1PtFBXmllck%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;1306&quot; height=&quot;613&quot; data-origin-width=&quot;1306&quot; data-origin-height=&quot;613&quot;/&gt;&lt;/span&gt;&lt;/figure&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;역할 이름 : 새로 생성할 역할 이름 (ex - codebuild-NRSON-CODEBUILDER-HIKARI-service-role)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;제한시간 :&amp;nbsp; 빌드 소요 시간에 대한 제한 (ex - default 빌드 1시간, 대기 8시간 제한)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;인증서 : 필요서 S3 버킷에서 인증서 설치 (ex - 인증서 설치 안함)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1307&quot; data-origin-height=&quot;615&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wVl9W/btrLLjAW3g6/y6m1p9klSxH4hDbiFpqbo1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wVl9W/btrLLjAW3g6/y6m1p9klSxH4hDbiFpqbo1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wVl9W/btrLLjAW3g6/y6m1p9klSxH4hDbiFpqbo1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwVl9W%2FbtrLLjAW3g6%2Fy6m1p9klSxH4hDbiFpqbo1%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;1307&quot; height=&quot;615&quot; data-origin-width=&quot;1307&quot; data-origin-height=&quot;615&quot;/&gt;&lt;/span&gt;&lt;/figure&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;VPC : AWS CodeBuild가 엑세스 할 (EKS가 구축된) VPC 선택 (ex - vpc-xxxxxxxxxx)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;서브넷 : AWS CodeBuild가 VPC를 구성하는데 사용해야 하는 Private Subnet을 선택. 여러개의 AZ에 걸쳐 있는 서브넷을 선택하는 것이 가용성에 유리하며, 서브넷에는 NAT 게이트웨이가 포함되어 있어야 함 (ex - subnet-aaaaaaaaaa, subnet-bbbbbbbbbb)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;보안 그룹 : AWS CodeBuild가 VPC를 구성하는데 사용해야 하는 보안 그룹을 선택 (ex - sg-ccccccccccc)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1308&quot; data-origin-height=&quot;802&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bEl7r3/btrLLi9RuQd/PSgDOnNIfzus0QRklNvWSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bEl7r3/btrLLi9RuQd/PSgDOnNIfzus0QRklNvWSK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bEl7r3/btrLLi9RuQd/PSgDOnNIfzus0QRklNvWSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbEl7r3%2FbtrLLi9RuQd%2FPSgDOnNIfzus0QRklNvWSK%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;1308&quot; height=&quot;802&quot; data-origin-width=&quot;1308&quot; data-origin-height=&quot;802&quot;/&gt;&lt;/span&gt;&lt;/figure&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;컴퓨팅 : CodeBuild를 수행할 EC2 인스턴스의 타입을 선택&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;환경변수 : AWS_DEFAULT_REGION (ap-northeast-2), IMAGE_REPO_NAME (1번에서 생성한 ECR Repository Name), IMAGE_TAG (Image Version), AWS_ACCOUNT_ID (Account Id)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;▶&amp;nbsp;Buildspec&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;1307&quot; data-origin-height=&quot;385&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/v1aiK/btrLQxxprGJ/ksKAAYSsRDJLB15HadEtE0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/v1aiK/btrLQxxprGJ/ksKAAYSsRDJLB15HadEtE0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/v1aiK/btrLQxxprGJ/ksKAAYSsRDJLB15HadEtE0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fv1aiK%2FbtrLQxxprGJ%2FksKAAYSsRDJLB15HadEtE0%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;1307&quot; height=&quot;385&quot; data-origin-width=&quot;1307&quot; data-origin-height=&quot;385&quot;/&gt;&lt;/span&gt;&lt;/figure&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Buildspec : 빌드 사양을 정의하는 buildspec 파일을 사용하는 방법과 빌드 명령을 삽입하는 방법. 대체로 Project 내에 포함하여 buildspec.yml 파일 형태로 반영&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;4) 프로젝트 빌드&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;▶&amp;nbsp;CodeBuild 프로젝트 빌드 메인 화면&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;생성한 CodeBuild의 주요 항목을 살펴보자면 다음과 같다.&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;1307&quot; data-origin-height=&quot;925&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dg62db/btrLMxE90SZ/jGlp6X6McQ7G6DExSAJ1vk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dg62db/btrLMxE90SZ/jGlp6X6McQ7G6DExSAJ1vk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dg62db/btrLMxE90SZ/jGlp6X6McQ7G6DExSAJ1vk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdg62db%2FbtrLMxE90SZ%2FjGlp6X6McQ7G6DExSAJ1vk%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;1307&quot; height=&quot;925&quot; data-origin-width=&quot;1307&quot; data-origin-height=&quot;925&quot;/&gt;&lt;/span&gt;&lt;/figure&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;빌드 시작 : 정의한 CodeCommit &amp;amp; buildspec에 따라 처리&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;빌드 기록 : 빌드 Num 별로 빌드 수행 결과 메시지 확인 (성공, 실패 확인 및 세부 빌드 차수 별 상세 화면 이동)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;▶&amp;nbsp;빌드 시작 버튼 클릭 시 전환되는 화면&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&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;1307&quot; data-origin-height=&quot;922&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0Y9re/btrLNvNQySM/t6PyTYc396zSTEYrEtkoi0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0Y9re/btrLNvNQySM/t6PyTYc396zSTEYrEtkoi0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0Y9re/btrLNvNQySM/t6PyTYc396zSTEYrEtkoi0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0Y9re%2FbtrLNvNQySM%2Ft6PyTYc396zSTEYrEtkoi0%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;1307&quot; height=&quot;922&quot; data-origin-width=&quot;1307&quot; data-origin-height=&quot;922&quot;/&gt;&lt;/span&gt;&lt;/figure&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;빌드 로그 : buildspec.yml의 처리 과정이 로그로 나타나며, 전체 로그 보기는 CloudWatch, 테일 로그는 CodeBuild 내에서 로그의 변화를 모니터링할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;단계 세부 정보 : 각 단계 별 상태 (성공/실패)를 확인할 수 있으며, 수행 시간을 확인할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;환경 변수 : 앞서 생성한 환경 변수 정보를 확인할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;▶&amp;nbsp;빌드 모니터링&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;빌드 모니터링은 크게 두 화면에서 진행할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ez3tmD/btrLLxr7smX/OhsQS5K5RC9pCpSwkuRHUk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ez3tmD/btrLLxr7smX/OhsQS5K5RC9pCpSwkuRHUk/img.png&quot; style=&quot;width: 49.4988%; margin-right: 10px;&quot; data-origin-width=&quot;1307&quot; data-origin-height=&quot;923&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;50.08&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ez3tmD/btrLLxr7smX/OhsQS5K5RC9pCpSwkuRHUk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fez3tmD%2FbtrLLxr7smX%2FOhsQS5K5RC9pCpSwkuRHUk%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;1307&quot; height=&quot;923&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uTfo1/btrLLA3sD0f/7ze0AyprVAVkwLQi0w3DYk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uTfo1/btrLLA3sD0f/7ze0AyprVAVkwLQi0w3DYk/img.png&quot; style=&quot;width: 49.3384%;&quot; data-origin-width=&quot;1307&quot; data-origin-height=&quot;926&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;49.92&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uTfo1/btrLLA3sD0f/7ze0AyprVAVkwLQi0w3DYk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuTfo1%2FbtrLLA3sD0f%2F7ze0AyprVAVkwLQi0w3DYk%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;1307&quot; height=&quot;926&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;빌드 로그 : 해당 화면에서는 빌드 시 로그를 확인할 수 있다. 다만, 로그가 많이 발생되는 경우 테일 로그를 클릭하여 모니터링하는 것이 편리하다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;빌드 세부 정보 : 빌드 세부 정보에서는 각 Stage 별로 성공/실패, 실패 시 원인 등을 확인할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;▶ Kubernetes 배포 확인&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1662856346246&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-10-192-10-183 CODESERIES]# kubectl get service
NAME                  TYPE           CLUSTER-IP       EXTERNAL-IP                                                                    PORT(S)          AGE
hikari-test-service   LoadBalancer   172.20.131.243   &amp;lt;ALB_DNS&amp;gt;									    8081:32319/TCP   115s
kubernetes            ClusterIP      172.20.0.1       &amp;lt;none&amp;gt;                                                                          443/TCP          15h
mariadb               NodePort       172.20.41.53     &amp;lt;none&amp;gt;                                                                         3306:30306/TCP   14h
[root@ip-10-192-10-183 CODESERIES]# kubectl get pods
NAME                                      READY   STATUS    RESTARTS       AGE
hikari-test-deployment-56855ccff7-cq847   1/1     Running   1 (112s ago)   118s
mariadb-65b58c446c-qhqd5                  1/1     Running   0              14h
[root@ip-10-192-10-183 CODESERIES]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 hikari-test-service와 hikari-test-deployment pod가 기동된 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;AWS CodePipeline&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;AWS CodePipeline은 여러 Build/Deploy Task를 하나로 통합하여 실행해 주는 서비스이다. 쉽게 Jenkins Pipeline Job과 동일하다고 생각하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1) CodePipeline 생성&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;1309&quot; data-origin-height=&quot;925&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Eidhh/btrLR8Edikv/Y60CHC5sOyn8c8jcSye5t1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Eidhh/btrLR8Edikv/Y60CHC5sOyn8c8jcSye5t1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Eidhh/btrLR8Edikv/Y60CHC5sOyn8c8jcSye5t1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEidhh%2FbtrLR8Edikv%2FY60CHC5sOyn8c8jcSye5t1%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;1309&quot; height=&quot;925&quot; data-origin-width=&quot;1309&quot; data-origin-height=&quot;925&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: 'Noto Serif KR'; color: #000000;&quot;&gt;CodePipeline에 파이프라인 생성을 선택한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2) 파이프라인 설정 선택&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;1309&quot; data-origin-height=&quot;927&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lwAX1/btrLStIkekR/oZosEIStLrA0nD6ssbKkKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lwAX1/btrLStIkekR/oZosEIStLrA0nD6ssbKkKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lwAX1/btrLStIkekR/oZosEIStLrA0nD6ssbKkKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlwAX1%2FbtrLStIkekR%2FoZosEIStLrA0nD6ssbKkKK%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;1309&quot; height=&quot;927&quot; data-origin-width=&quot;1309&quot; data-origin-height=&quot;927&quot;/&gt;&lt;/span&gt;&lt;/figure&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;파이프라인 이름 : 이름 입력 (ex - hikari-test-pipeline)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;서비스 역할 : 새 서비스 역할을 생성하거나, 기존 서비스 역할을 사용 (ex - default)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;3) 소스 스테이지 추가&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;1309&quot; data-origin-height=&quot;927&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cYvQ4D/btrLMAhFcXJ/iRXsmaIRbXbqScIQ1xHMVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cYvQ4D/btrLMAhFcXJ/iRXsmaIRbXbqScIQ1xHMVk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cYvQ4D/btrLMAhFcXJ/iRXsmaIRbXbqScIQ1xHMVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcYvQ4D%2FbtrLMAhFcXJ%2FiRXsmaIRbXbqScIQ1xHMVk%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;1309&quot; height=&quot;927&quot; data-origin-width=&quot;1309&quot; data-origin-height=&quot;927&quot;/&gt;&lt;/span&gt;&lt;/figure&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;소스 공급자 : Amazon S3, AWS CodeCommit, GitHub, BitBucket, GitHub Enterprise 등을 지원하며, Repository를 선택 (ex - AWS CodeCommit)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;리포지토리 이름 : 해당 소스 공급자에 등록되어 있는 Repository를 선택 (ex - nrson-repository)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;브랜치 이름 : 선택한 Repository 중 Branch를 선택 (ex - master)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;변경 감지 옵션 : 소스 코드에서 변경이 감지되면 파이프라인을 자동으로 시작하도록 하는 감지 모드로 Amazon Cloud Watch와 AWS CodePipeline에서 정기적으로 감지하는 방법 선택 (ex - Amazon Cloud Watch)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;출력 아티팩트 형식 : CodePipeline 기본값, 전체 복제 방식 선택. .git 등을 제외하고 배포하기 위해 CodePipeline 기본값 선택 (ex - CodePipeline 기본값)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;4) 빌드 스테이지 추가&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;1308&quot; data-origin-height=&quot;807&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lBzfe/btrLLZu9TJx/2Y5vNjGtuM33MPUWqfmkK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lBzfe/btrLLZu9TJx/2Y5vNjGtuM33MPUWqfmkK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lBzfe/btrLLZu9TJx/2Y5vNjGtuM33MPUWqfmkK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlBzfe%2FbtrLLZu9TJx%2F2Y5vNjGtuM33MPUWqfmkK1%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;1308&quot; height=&quot;807&quot; data-origin-width=&quot;1308&quot; data-origin-height=&quot;807&quot;/&gt;&lt;/span&gt;&lt;/figure&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;빌드 공급자 : 빌드 공급자로 AWS CodeBuild 뿐만 아니라, Jenkins를 추가할 수 있다. (ex - AWS CodeBuild)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;리전 (ex - 아시아 태평양 (서울))&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;프로젝트 이름 : AWS CodeBuild 프로젝트 이름 (ex - NRSON-CODEBUILDER-HIKARI)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;빌드 유형 : 단일 빌드 또는 배치 빌드 선택 (ex - 단일 빌드)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;5) 배포 스테이지 추가&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;1307&quot; data-origin-height=&quot;452&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YHVNM/btrLLzQ6XiW/vGAv2s83HT8vPgqmf6EtTk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YHVNM/btrLLzQ6XiW/vGAv2s83HT8vPgqmf6EtTk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YHVNM/btrLLzQ6XiW/vGAv2s83HT8vPgqmf6EtTk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYHVNM%2FbtrLLzQ6XiW%2FvGAv2s83HT8vPgqmf6EtTk%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;1307&quot; height=&quot;452&quot; data-origin-width=&quot;1307&quot; data-origin-height=&quot;452&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: 'Noto Serif KR'; color: #000000;&quot;&gt;앞서 이야기한 바와 같이 &lt;span style=&quot;color: #000000;&quot;&gt;AWS CodeDeploy는 AWS EKS를 지원하지 않아&lt;span&gt; 배포 스테이지는 건너뛰기 한다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;6) 파이프라인 실행&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bANHSv/btrLR8RLOkK/3BAk188BhSQwKpfmeKEpl0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bANHSv/btrLR8RLOkK/3BAk188BhSQwKpfmeKEpl0/img.png&quot; data-origin-width=&quot;1308&quot; data-origin-height=&quot;925&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5263%; margin-right: 10px;&quot; data-widthpercent=&quot;33.3&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bANHSv/btrLR8RLOkK/3BAk188BhSQwKpfmeKEpl0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbANHSv%2FbtrLR8RLOkK%2F3BAk188BhSQwKpfmeKEpl0%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;1308&quot; height=&quot;925&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uLkFv/btrLOfD4KD1/LsoS70OnLf4kM7j95pqwDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uLkFv/btrLOfD4KD1/LsoS70OnLf4kM7j95pqwDK/img.png&quot; data-origin-width=&quot;1308&quot; data-origin-height=&quot;922&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.6321%; margin-right: 10px;&quot; data-widthpercent=&quot;33.41&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uLkFv/btrLOfD4KD1/LsoS70OnLf4kM7j95pqwDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuLkFv%2FbtrLOfD4KD1%2FLsoS70OnLf4kM7j95pqwDK%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;1308&quot; height=&quot;922&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/D1bap/btrLOnvihgb/U5GbNs5ZYAanKHtG0LMOS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/D1bap/btrLOnvihgb/U5GbNs5ZYAanKHtG0LMOS0/img.png&quot; data-origin-width=&quot;1309&quot; data-origin-height=&quot;926&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.516%;&quot; data-widthpercent=&quot;33.29&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/D1bap/btrLOnvihgb/U5GbNs5ZYAanKHtG0LMOS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FD1bap%2FbtrLOnvihgb%2FU5GbNs5ZYAanKHtG0LMOS0%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;1309&quot; height=&quot;926&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;파이프라인 생성이 완료되면, 자동으로 파이프라인이 동작된다. 이때 위와 같이 Stage가 Source, Build로 구분되며, 두 단계가 하나의 파이프라인 안에서 동작한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;7) Kubernetes 배포 확인&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1662858003676&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-10-192-10-183 CODESERIES]# kubectl get pods
NAME                                      READY   STATUS    RESTARTS        AGE
hikari-test-deployment-577475764f-t5mqz   1/1     Running   1 (2m20s ago)   2m26s
mariadb-65b58c446c-qhqd5                  1/1     Running   0               25h
[root@ip-10-192-10-183 CODESERIES]# kubectl get service
NAME                  TYPE           CLUSTER-IP       EXTERNAL-IP                                                                    PORT(S)          AGE
hikari-test-service   LoadBalancer   172.20.131.243   &amp;lt;ALB_DNS&amp;gt;   8081:32319/TCP   11h
kubernetes            ClusterIP      172.20.0.1       &amp;lt;none&amp;gt;                                                                         443/TCP          27h
mariadb               NodePort       172.20.41.53     &amp;lt;none&amp;gt;                                                                         3306:30306/TCP   25h
[root@ip-10-192-10-183 CODESERIES]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 Kubernetes Service와 Pod가 배포된 것을 확인할 수 있다. 특히 파이프라인의 변경 감지 옵션에 따라 소스코드가 AWS CodeCommit에 배포되면 자동으로 파이프라인이 동작하게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;결론&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;지금까지 AWS Code Series 중 CodeCommit, CodeBuild, CodePipeline을 활용하여 AWS EKS 환경에 배포를 진행해 보았다. CodeCommit의 경우 GitHub와 같은 소스 리포지토리로써 AWS Resource와 통합 관리에 용이하다는 장점이 있다. CodeBuild는 Image를 생성하기 위한 Base(OS, JDK 등)를 제공하지만, 경량 이미지 등은 부족한 편이다. CodePipeline은 배포의 이점보다는 WebHook 연동 등을 통해 자동 배포 체계를 구축할 수 있다는 장점이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;다만 이와 같은 CodeSeries를 사용하지 않고 오픈소스로 충분히 구현이 가능하며, 비용 역시 절감할 수 있다는 측면, 외부 요소와의 연계가 어렵다는 측면 등을 고려할 때 크게 메리트가 있는 구성이라 보기는 어려울 듯 하다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>③ 클라우드/ⓐ AWS</category>
      <category>codebuild</category>
      <category>CodeCommit</category>
      <category>codepipeline</category>
      <category>CodeSeries</category>
      <category>EKS</category>
      <category>Hikari</category>
      <category>hikariCP</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/780</guid>
      <comments>https://waspro.tistory.com/780#entry780comment</comments>
      <pubDate>Sun, 11 Sep 2022 07:39:23 +0900</pubDate>
    </item>
    <item>
      <title>AWS EKS에 MariaDB 설치하기 (using EFS)</title>
      <link>https://waspro.tistory.com/778</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;개요&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이번 포스팅에서는 &lt;span style=&quot;color: #000000;&quot;&gt;AWS EKS 환경에 배포되어 있는 어플리케이션과 연동하기 위해 MariaDB를 Kubernetes에 배포해 보자.&lt;/span&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;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;① AWS EKS 환경에 MariaDB 구축&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;② AWS Code Series 파이프라인 구축&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;AWS EKS 환경에 MariaDB 구축&lt;/span&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;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Amazon EFS CIS 드라이버 배포 및 테스트&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Amazon EFS CIS 드라이버 설치&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Amazon EFS CIS 드라이버 배포&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Amazon EFS CSI 드라이버 테스트&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;AWS EKS에 MariaDB 설치&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;MariaDB 테스트&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 id=&quot;Option_B.3A_Deploy_and_test_the_Amazon_EFS_CSI_driver&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Amazon EFS CSI 드라이버 배포 및 테스트&lt;/span&gt;&lt;/h2&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;CSI 드라이버의 서비스 계정이 AWS API를 호출할 수 있도록 허용하는 IAM ROLE을 생성한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1. GitHub에서 IAM 정책 문서 다운로드&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div data-lb-comp=&quot;code&quot; data-lb-comp-registered=&quot;true&quot;&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;curl -o iam-policy-example.json https://raw.githubusercontent.com/kubernetes-sigs/aws-efs-csi-driver/v1.2.0/docs/iam-policy-example.json&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;2. IAM 정책 생성 (create-policy)&lt;/span&gt;&lt;/p&gt;
&lt;div data-lb-comp=&quot;code&quot; data-lb-comp-registered=&quot;true&quot;&gt;
&lt;pre class=&quot;dsconfig&quot;&gt;&lt;code&gt;aws iam create-policy \
    --policy-name AmazonEKS_EFS_CSI_Driver_Policy \
    --policy-document file://iam-policy-example.json&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&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: 'Noto Serif KR'; color: #000000;&quot;&gt;생성한 IAM 정책 중 Issuer 확인&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div data-lb-comp=&quot;code&quot; data-lb-comp-registered=&quot;true&quot;&gt;
&lt;pre class=&quot;dsconfig&quot;&gt;&lt;code&gt;aws eks describe-cluster --name your_cluster_name --query &quot;cluster.identity.oidc.issuer&quot; --output text&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&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: 'Noto Serif KR'; color: #000000;&quot;&gt;your_cluster_name - 클러스터 이름으로 변경&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1662170667853&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-109-4 ~]# aws eks describe-cluster --name NRSON-EKS-CLUSTER --query &quot;cluster.identity.oidc.issuer&quot; --output text
https://oidc.eks.ap-northeast-2.amazonaws.com/id/abcdefghijklmnopqrstuvwxyz
[root@ip-192-168-109-4 ~]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;3. IAM Trust Policy 생성&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: 'Noto Serif KR'; color: #000000;&quot;&gt;IAM 신뢰 정책을 생성한 다음 Kubernetes 서비스 계정에 AssumeRoleWithWebIdentity 작업 부여&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div data-lb-comp=&quot;code&quot; data-lb-comp-registered=&quot;true&quot;&gt;
&lt;pre class=&quot;html xml&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;cat &amp;lt;&amp;lt;EOF &amp;gt; trust-policy.json
{
  &quot;Version&quot;: &quot;2012-10-17&quot;,
  &quot;Statement&quot;: [
    {
      &quot;Effect&quot;: &quot;Allow&quot;,
      &quot;Principal&quot;: {
        &quot;Federated&quot;: &quot;arn:aws:iam::AWS_ACCOUNT_ID:oidc-provider/oidc.eks.AWS_DEFAULT_REGION.amazonaws.com/id/&amp;lt;XXXXXXXXXXAAAAAXXXXXXXXXX&amp;gt;&quot;
      },
      &quot;Action&quot;: &quot;sts:AssumeRoleWithWebIdentity&quot;,
      &quot;Condition&quot;: {
        &quot;StringEquals&quot;: {
          &quot;oidc.eks.AWS_DEFAULT_REGION.amazonaws.com/id/&amp;lt;XXXXXXXXXXAAAAAXXXXXXXXXX&amp;gt;:sub&quot;: &quot;system:serviceaccount:kube-system:efs-csi-controller-sa&quot;
        }
      }
    }
  ]
}
EOF&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&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: 'Noto Serif KR'; color: #000000;&quot;&gt;AWS_ACCOUNT_ID - account id로 변경&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;AWS_DEFAULT_REGION - 해당 AWS 리전으로 변경&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;XXXXXXXXXXAAAAAXXXXXXXXXX - 2단계에서 반환된 값으로 변경&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;4. IAM 역할 생성&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div data-lb-comp=&quot;code&quot; data-lb-comp-registered=&quot;true&quot;&gt;
&lt;pre class=&quot;html xml&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;aws iam create-role \
  --role-name AmazonEKS_EFS_CSI_DriverRole \
  --assume-role-policy-document file://&quot;trust-policy.json&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;5. 새 IAM 정책을 역할에 연결&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div data-lb-comp=&quot;code&quot; data-lb-comp-registered=&quot;true&quot;&gt;
&lt;pre class=&quot;haml&quot;&gt;&lt;code&gt;aws iam attach-role-policy \
  --policy-arn arn:aws:iam::&amp;lt;AWS_ACCOUNT_ID&amp;gt;:policy/AmazonEKS_EFS_CSI_Driver_Policy \
  --role-name AmazonEKS_EFS_CSI_DriverRole&lt;/code&gt;&lt;/pre&gt;
&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: 'Noto Serif KR'; color: #000000;&quot;&gt;AWS_ACCOUNT_ID - account id로 변경&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Amazon EFS CIS 드라이버 설치&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1. CIS 드라이버 설치&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;매니페스트를 다운로드하여 퍼블릭 Amazon ECR 레지스트리에 저장된 이미지를 사용해 드라이버를 설치한다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div data-lb-comp=&quot;code&quot; data-lb-comp-registered=&quot;true&quot;&gt;
&lt;pre class=&quot;actionscript&quot;&gt;&lt;code&gt;$ kubectl kustomize &quot;github.com/kubernetes-sigs/aws-efs-csi-driver/deploy/kubernetes/overlays/stable/?ref=release-1.3&quot; &amp;gt; public-ecr-driver.yaml &amp;lt;br&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;2. public-ecr-driver.yaml 편집 (ServiceAccount annotation 추가)&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;public-ecr-driver.yaml 파일을 편집하고 생성한 IAM 역할의 ARN으로 'efs-csi-controller-sa' Kubernetes ServiceAccount Object에 annotations을 추가한다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div data-lb-comp=&quot;code&quot; data-lb-comp-registered=&quot;true&quot;&gt;
&lt;pre class=&quot;html xml&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    app.kubernetes.io/name: aws-efs-csi-driver
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::&amp;lt;AWS_ACCOUNT_ID&amp;gt;:role/AmazonEKS_EFS_CSI_DriverRole
  name: efs-csi-controller-sa
  namespace: kube-system&lt;/code&gt;&lt;/pre&gt;
&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: 'Noto Serif KR'; color: #000000;&quot;&gt;AWS_ACCOUNT_ID - account id로 변경&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;/span&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Amazon EFS CSI 드라이버를 배포한다. Amazon EFS CSI 드라이버를 사용하면 ReadWriteMany 모드를 사용하여 여러 Pod를 동시에 볼륨에 쓸 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;/span&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;3. public-ecr-driver.yaml 배포&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div data-lb-comp=&quot;code&quot; data-lb-comp-registered=&quot;true&quot;&gt;
&lt;pre class=&quot;actionscript&quot;&gt;&lt;code&gt;$ kubectl apply -f public-ecr-driver.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;4. Amazon EKS 클러스터에 대한 VPC ID 확인&lt;/span&gt;&lt;/div&gt;
&lt;div data-lb-comp=&quot;code&quot; data-lb-comp-registered=&quot;true&quot;&gt;
&lt;pre class=&quot;html xml&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;aws eks describe-cluster --name &amp;lt;CLUSTER_NAME&amp;gt; --query &quot;cluster.resourcesVpcConfig.vpcId&quot; --output text&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: 'Noto Serif KR'; color: #000000;&quot;&gt;CLUSTER_NAME - EKS CLUSTER로 변경&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1662246883764&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-109-4 EFS]# aws eks describe-cluster --name your_cluster_name --query &quot;cluster.resourcesVpcConfig.vpcId&quot; --output text
vpc-vpcidddddddddd
[root@ip-192-168-109-4 EFS]#&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;5. VPC 클러스터에 대한 CIDR 범위 확인&lt;/span&gt;&lt;/p&gt;
&lt;div data-lb-comp=&quot;code&quot; data-lb-comp-registered=&quot;true&quot;&gt;
&lt;pre class=&quot;dsconfig&quot;&gt;&lt;code&gt;aws ec2 describe-vpcs --vpc-ids YOUR_VPC_ID --query &quot;Vpcs[].CidrBlock&quot; --output text&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: 'Noto Serif KR'; color: #000000;&quot;&gt;YOUR_VPC_ID - 4번에서 확인한 vpc id로 변경&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1662246983002&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-109-4 EFS]# aws ec2 describe-vpcs --vpc-ids vpc-vpcidddddddddd --query &quot;Vpcs[].CidrBlock&quot; --output text
192.168.0.0/16
[root@ip-192-168-109-4 EFS]#&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;6. Security Group 생성&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; Amazon EFS 탑재 지점에 대한 인바운드 네트워크 파일 시스템(NFS) 트래픽을 허용하는 보안 그룹 생성&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div data-lb-comp=&quot;code&quot; data-lb-comp-registered=&quot;true&quot;&gt;
&lt;pre class=&quot;dsconfig&quot;&gt;&lt;code&gt;aws ec2 create-security-group --description efs-test-sg --group-name efs-sg --vpc-id YOUR_VPC_ID&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;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;YOUR_VPC_ID - 4번에서 확인한 vpc id로 변경&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;7. VPC의 리소스가 Amazon EFS 파일 시스템과 통신할 수 있도록 NFS 인바운드 규칙 추가&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div data-lb-comp=&quot;code&quot; data-lb-comp-registered=&quot;true&quot;&gt;
&lt;pre class=&quot;brainfuck&quot;&gt;&lt;code&gt;aws ec2 authorize-security-group-ingress --group-id sg-xxx --protocol tcp --port 2049 --cidr YOUR_VPC_CIDR&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: 'Noto Serif KR'; color: #000000;&quot;&gt;YOUR_VPC_CIDR - 5번에서 확인한 vpc cidr로 변경&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;sg-xxx - 6번에서 생성한 security group id로 변경&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;8. Amazon EKS 클러스터에 대한 Amazon EFS 파일 시스템 생성&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div data-lb-comp=&quot;code&quot; data-lb-comp-registered=&quot;true&quot;&gt;
&lt;pre class=&quot;html xml&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;aws efs create-file-system --creation-token eks-efs&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;참고:&amp;nbsp;나중에 사용하기 위해&amp;nbsp;FileSystemId를 저장합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1662804866709&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-10-192-10-183 EFS]# aws efs create-file-system --creation-token eks-efs
{
    &quot;SizeInBytes&quot;: {
        &quot;ValueInIA&quot;: 0, 
        &quot;ValueInStandard&quot;: 0, 
        &quot;Value&quot;: 0
    }, 
    &quot;FileSystemArn&quot;: &quot;arn:aws:elasticfilesystem:ap-northeast-2:&amp;lt;AWS_ACCOUNT_ID&amp;gt;:file-system/fs-029c93b311a237e4e&quot;, 
    &quot;ThroughputMode&quot;: &quot;bursting&quot;, 
    &quot;CreationToken&quot;: &quot;eks-efs&quot;, 
    &quot;Encrypted&quot;: false, 
    &quot;Tags&quot;: [], 
    &quot;CreationTime&quot;: 1662763838.0, 
    &quot;PerformanceMode&quot;: &quot;generalPurpose&quot;, 
    &quot;FileSystemId&quot;: &quot;fs-aaaabbbb00001111&quot;, 
    &quot;NumberOfMountTargets&quot;: 0, 
    &quot;LifeCycleState&quot;: &quot;creating&quot;, 
    &quot;OwnerId&quot;: &quot;&amp;lt;AWS_ACCOUNT_ID&amp;gt;&quot;
}
[root@ip-10-192-10-183 EFS]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;9. Amazon EFS mount target 생성&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div data-lb-comp=&quot;code&quot; data-lb-comp-registered=&quot;true&quot;&gt;
&lt;pre class=&quot;dsconfig&quot;&gt;&lt;code&gt;aws efs create-mount-target --file-system-id FileSystemId --subnet-id SubnetID --security-group sg-xxx&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&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: 'Noto Serif KR'; color: #000000;&quot;&gt;FileSystemId - 8번에서 생성한 file-system의 FileSystemId로 변경&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;SubnetID - Kubernetes WorkerNode에서 사용하는 Subnet으로 변경&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;sg-xxx - 6번에서 생성한 security group id로 변경.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;여러 서브넷에 mount target을 생성하려면 각 서브넷 ID에 대해 해당 과정을 반복 수행한다. mount targe이 있는 가용 영역의 모든 Amazon Elastic Compute Cloud(Amazon EC2) 인스턴스가 파일 시스템을 사용할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Amazon EFS CSI 드라이버 테스트&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;지금부터는 동일한 로그 파일에 write하는 두 개의 Pod를 배포하여 Amazon EFS CSI 드라이버를 테스트해 보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1. AWS GitHub에서 aws-efs-csi-driver 리포지토리 복제&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div data-lb-comp=&quot;code&quot; data-lb-comp-registered=&quot;true&quot;&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;git clone https://github.com/kubernetes-sigs/aws-efs-csi-driver.git&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2. 작업 디렉터리를 Amazon EFS CSI 드라이버 테스트 파일이 포함된 폴더로 변경한다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div data-lb-comp=&quot;code&quot; data-lb-comp-registered=&quot;true&quot;&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;cd aws-efs-csi-driver/examples/kubernetes/multiple_pods/&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;3. 이전에 생성한 Amazon EFS 파일 시스템 ID를 검색한다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div data-lb-comp=&quot;code&quot; data-lb-comp-registered=&quot;true&quot;&gt;
&lt;pre class=&quot;sas&quot;&gt;&lt;code&gt;aws efs describe-file-systems --query &quot;FileSystems[*].FileSystemId&quot; --output text&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;4. specs/pv.yaml 파일에서 spec.csi.volumeHandle 값을 이전 단계의 Amazon EFS FileSystemId로 변경한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1662251930129&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: v1
kind: PersistentVolume
metadata:
  name: efs-pv
spec:
  capacity:
    storage: 5Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  storageClassName: efs-sc
  csi:
    driver: efs.csi.aws.com
    volumeHandle: fs-aaaaaaaaaaaaaa&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;5. 테스트에 필요한 Kubernetes 리소스를 생성한다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div data-lb-comp=&quot;code&quot; data-lb-comp-registered=&quot;true&quot;&gt;
&lt;pre class=&quot;coq&quot;&gt;&lt;code&gt;kubectl apply -f specs/&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;6. 기본 네임 스페이스에 영구 볼륨을 나열하고 default/efs-claim 클레임이 있는 영구 볼륨을 찾는다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div data-lb-comp=&quot;code&quot; data-lb-comp-registered=&quot;true&quot;&gt;
&lt;pre class=&quot;maxima&quot;&gt;&lt;code&gt;kubectl get pv -w&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;7. 생성한 pv를 확인한다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div data-lb-comp=&quot;code&quot; data-lb-comp-registered=&quot;true&quot;&gt;
&lt;pre class=&quot;maxima&quot;&gt;&lt;code&gt;kubectl describe pv efs-pv&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;8. 두 개의 Pod가 동일한 파일에 데이터를 쓰고 있는지 테스트한다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div data-lb-comp=&quot;code&quot; data-lb-comp-registered=&quot;true&quot;&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;kubectl exec -it app1 -- tail /data/out1.txt 
kubectl exec -it app2 -- tail /data/out1.txt&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;AWS EKS에 MariaDB 설치&lt;/span&gt;&lt;/h2&gt;
&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;다음으로 생성한 EFS CIS Driver를 활용하여 MariaDB를 설치해 보도록 하자.&lt;/span&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1.&amp;nbsp;Persistent&amp;nbsp;Volume&amp;nbsp;생성&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: 'Noto Serif KR'; color: #000000;&quot;&gt;db-pv.yaml 생성&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1662133620311&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: v1
kind: PersistentVolume
metadata:
  name: db-pv-volume
spec:
  capacity:
    storage: 10Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: efs-sc
  csi:
    driver: efs.csi.aws.com
    volumeHandle: fs-0e018b9e35d8b8c83&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: 'Noto Serif KR'; color: #000000;&quot;&gt;db-pv.yaml 파일 반영&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1662133683327&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-109-4 specs]# kubectl apply -f db-pv.yaml 
persistentvolume/db-pv-volume created
[root@ip-192-168-109-4 specs]#&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: 'Noto Serif KR'; color: #000000;&quot;&gt;kubectl describe pv db-pv-volume &lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1662133751559&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Name:            db-pv-volume
Labels:          &amp;lt;none&amp;gt;
Annotations:     kubectl.kubernetes.io/last-applied-configuration:
                   {&quot;apiVersion&quot;:&quot;v1&quot;,&quot;kind&quot;:&quot;PersistentVolume&quot;,&quot;metadata&quot;:{&quot;annotations&quot;:{},&quot;name&quot;:&quot;db-pv-volume&quot;},&quot;spec&quot;:{&quot;accessModes&quot;:[&quot;ReadWriteOnce&quot;],&quot;...
Finalizers:      [kubernetes.io/pv-protection]
StorageClass:    efs-sc
Status:          Available
Claim:           
Reclaim Policy:  Retain
Access Modes:    RWO
VolumeMode:      Filesystem
Capacity:        10Gi
Node Affinity:   &amp;lt;none&amp;gt;
Message:         
Source:
    Type:              CSI (a Container Storage Interface (CSI) volume source)
    Driver:            efs.csi.aws.com
    VolumeHandle:      fs-0e018b9e35d8b8c83
    ReadOnly:          false
    VolumeAttributes:  &amp;lt;none&amp;gt;
Events:                &amp;lt;none&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2. Persistent Volume Claim 생성&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: 'Noto Serif KR'; color: #000000;&quot;&gt;db-claim.yaml 생성&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1662133844105&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: db-pv-claim
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: efs-sc
  resources:
    requests:
      storage: 10Gi&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: 'Noto Serif KR'; color: #000000;&quot;&gt;db-claim.yaml 파일 반영&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1662133885800&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-109-4 specs]# kubectl apply -f db-claim.yaml 
persistentvolumeclaim/db-pv-claim created
[root@ip-192-168-109-4 specs]#&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: 'Noto Serif KR'; color: #000000;&quot;&gt;kubectl describe pvc db-pv-claim&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1662134036151&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Name:          db-pv-claim
Namespace:     default
StorageClass:  efs-sc
Status:        Bound
Volume:        db-pv-volume
Labels:        &amp;lt;none&amp;gt;
Annotations:   kubectl.kubernetes.io/last-applied-configuration:
                 {&quot;apiVersion&quot;:&quot;v1&quot;,&quot;kind&quot;:&quot;PersistentVolumeClaim&quot;,&quot;metadata&quot;:{&quot;annotations&quot;:{},&quot;name&quot;:&quot;db-pv-claim&quot;,&quot;namespace&quot;:&quot;default&quot;},&quot;spec&quot;:{&quot;access...
               pv.kubernetes.io/bind-completed: yes
               pv.kubernetes.io/bound-by-controller: yes
Finalizers:    [kubernetes.io/pvc-protection]
Capacity:      10Gi
Access Modes:  RWO
VolumeMode:    Filesystem
Mounted By:    mariadb-66457b6967-7h788
Events:        &amp;lt;none&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;3. DB 정보 k8s Secret 생성&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: 'Noto Serif KR'; color: #000000;&quot;&gt;DB PASSWORD base64 암호화&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1662134162367&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-109-4 specs]# echo -n 'DB_PASSWORD' | base64
dbpasswordencryptiondata
[root@ip-192-168-109-4 specs]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;DB_PASSWORD를 base64로 암호화 하여 secret에 저장한다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;db-secret.yaml 생성&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1662134270823&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;---
apiVersion: v1
kind: Secret
metadata:
  name: mariadb-secret
data:
  password: dbpasswordencryptiondata&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;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;db-secret.yaml 반영&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1662134347547&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-109-4 specs]# kubectl apply -f db-secret.yaml
secret/mariadb-secret created
[root@ip-192-168-109-4 specs]#&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: 'Noto Serif KR'; color: #000000;&quot;&gt;secret 조회&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1662134564095&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-109-4 specs]# kubectl get secret
NAME                  TYPE                                  DATA   AGE
default-token-v242p   kubernetes.io/service-account-token   3      10h
mariadb-secret        Opaque                                1      11m
[root@ip-192-168-109-4 specs]#&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: 'Noto Serif KR'; color: #000000;&quot;&gt;kubectl describe secret mariadb-secret &lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1662134612392&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: db-pv-claim
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: efs-sc
  resources:
    requests:
      storage: 10Gi
[root@ip-192-168-109-4 MARIADB]# kubectl describe secret mariadb-secret
Name:         mariadb-secret
Namespace:    default
Labels:       &amp;lt;none&amp;gt;
Annotations:  &amp;lt;none&amp;gt;

Type:  Opaque

Data
====
password:  11 bytes&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;4. MariaDB k8s Service 생성&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: 'Noto Serif KR'; color: #000000;&quot;&gt;mariadb-svc.yaml 파일 생성&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1662134656920&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;---
apiVersion: v1
kind: Service
metadata:
  name: mariadb
spec:
  ports:
  - nodePort: 30306
    port: 3306
    protocol: TCP
    targetPort: 3306
  selector:
    app: mariadb
  type: NodePort&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: 'Noto Serif KR'; color: #000000;&quot;&gt;mariadb-svc.yaml 반영&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1662134777144&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-109-4 specs]# kubectl apply -f db-claim.yaml 
service/mariadb created
[root@ip-192-168-109-4 specs]#&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: 'Noto Serif KR'; color: #000000;&quot;&gt;kubectl describe service mariadb&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1662134846639&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Name:              mariadb
Namespace:         default
Labels:            &amp;lt;none&amp;gt;
Annotations:       &amp;lt;none&amp;gt;
Selector:          app=mariadb
Type:              ClusterIP
IP:                10.100.173.172
Port:              &amp;lt;unset&amp;gt;  3306/TCP
TargetPort:        3306/TCP
Endpoints:         192.168.158.23:3306
Session Affinity:  None
Events:            &amp;lt;none&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;5. MariaDB k8s Deployment 생성&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: 'Noto Serif KR'; color: #000000;&quot;&gt;mariadb-deployment.yaml 파일 생성&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1662134900951&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mariadb
spec:
  selector:
    matchLabels:
      app: mariadb
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: mariadb
    spec:
      containers:
      - image: mariadb:10.4
        name: mariadb
        ports:
        - containerPort: 3306
          name: mariadb
        volumeMounts:
        - name: mariadb-persistent-storage
          mountPath: /var/lib/mysql
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mariadb-secret
              key: password
      volumes:
      - name: mariadb-persistent-storage
        persistentVolumeClaim:
          claimName: db-pv-claim&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;- spec.template.spec.comtainers.env.valueFrom.secretKeyRef의 key: [VALUE]의 VALUE는 secret에 등록한 data.[VALUE] 값을 매핑한다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;mariadb-svc.yaml 반영&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1662135118863&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-109-4 MARIADB]# kubectl apply -f mariadb-deployment.yaml
deployment.apps/mariadb created
[root@ip-192-168-109-4 MARIADB]#&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: 'Noto Serif KR'; color: #000000;&quot;&gt;kubectl describe deployment mariadb &lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1662135184071&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Name:               mariadb
Namespace:          default
CreationTimestamp:  Fri, 02 Sep 2022 15:16:11 +0000
Labels:             &amp;lt;none&amp;gt;
Annotations:        deployment.kubernetes.io/revision: 1
                    kubectl.kubernetes.io/last-applied-configuration:
                      {&quot;apiVersion&quot;:&quot;apps/v1&quot;,&quot;kind&quot;:&quot;Deployment&quot;,&quot;metadata&quot;:{&quot;annotations&quot;:{},&quot;name&quot;:&quot;mariadb&quot;,&quot;namespace&quot;:&quot;default&quot;},&quot;spec&quot;:{&quot;selector&quot;:{&quot;matc...
Selector:           app=mariadb
Replicas:           1 desired | 1 updated | 1 total | 1 available | 0 unavailable
StrategyType:       Recreate
MinReadySeconds:    0
Pod Template:
  Labels:  app=mariadb
  Containers:
   mariadb:
    Image:      mariadb:10.7
    Port:       3306/TCP
    Host Port:  0/TCP
    Environment:
      MYSQL_ROOT_PASSWORD:  &amp;lt;set to the key 'password' in secret 'mariadb-secret'&amp;gt;  Optional: false
    Mounts:
      /var/lib/mysql from mariadb-persistent-storage (rw)
  Volumes:
   mariadb-persistent-storage:
    Type:       PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
    ClaimName:  db-pv-claim
    ReadOnly:   false
Conditions:
  Type           Status  Reason
  ----           ------  ------
  Available      True    MinimumReplicasAvailable
  Progressing    True    NewReplicaSetAvailable
OldReplicaSets:  &amp;lt;none&amp;gt;
NewReplicaSet:   mariadb-66457b6967 (1/1 replicas created)
Events:
  Type    Reason             Age   From                   Message
  ----    ------             ----  ----                   -------
  Normal  ScalingReplicaSet  56m   deployment-controller  Scaled up replica set mariadb-66457b6967 to 1&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: 'Noto Serif KR'; color: #000000;&quot;&gt;kubectl get pods -l app=mariadb &lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1662135223551&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-109-4 MARIADB]# kubectl get pods -l app=mariadb
NAME                       READY   STATUS    RESTARTS   AGE
mariadb-66457b6967-7h788   1/1     Running   0          57m
[root@ip-192-168-109-4 MARIADB]#&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;MariaDB 테스트&lt;/span&gt;&lt;/h2&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;410&quot; data-origin-height=&quot;403&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0bLU6/btrLk4vkDC8/e9fBitepM6OKnHgakDSCFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0bLU6/btrLk4vkDC8/e9fBitepM6OKnHgakDSCFK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0bLU6/btrLk4vkDC8/e9fBitepM6OKnHgakDSCFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0bLU6%2FbtrLk4vkDC8%2Fe9fBitepM6OKnHgakDSCFK%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;410&quot; height=&quot;403&quot; data-origin-width=&quot;410&quot; data-origin-height=&quot;403&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1. MariaDB Pod 접속&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1662135737247&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-109-4 MARIADB]# kubectl exec -it mariadb-66457b6967-7h788 -- bash
root@mariadb-66457b6967-7h788:/#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2. mysql 접속&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: 'Noto Serif KR'; color: #000000;&quot;&gt;pod에 접속하여 직접 mysql client에 접속&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1662135765279&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;root@mariadb-66457b6967-7h788:/# mysql -u root -p                   
Enter password: 
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 10
Server version: 10.7.5-MariaDB-1:10.7.5+maria~ubu2004 mariadb.org binary distribution

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]&amp;gt; show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.020 sec)

MariaDB [(none)]&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Enter password는 secret에 등록한 'DB_PASSWORD'이다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;remote에서 mariadb-client로 접속 (--mysql -h [POD_IP])&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1662136424319&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-109-4 specs]# kubectl run -it --rm --image=mariadb:10.7 --restart=Never mariadb-client -- mysql -h 192.168.158.23 -p'DB_PASSWORD'
If you don't see a command prompt, try pressing enter.
MariaDB [(none)]&amp;gt; show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.031 sec)

MariaDB [(none)]&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;결론&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;지금까지 EFS를 활용하여 EKS 환경에 MariaDB를 구축해 보았다. 기업에서는 AWS 환경에서 RDB를 구축, 운영할 때 RDS를 사용할 것인지, 아니면 EC2 인스턴스에 사용 중인 데이터베이스를 직접 설치하는 방식을 선택할 것인지 결정해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;이를 선택하는 기준은 몇 가지가 있겠지만, 대표적으로 비용, 종속성 (벤더 Lock-In), 유지보수, 업그레이드, 보안 등이 선택의 기준이 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Amazon RDS는 유지보수 효율성, 업그레이드 편의성 측면에서 강력한 기능을 지원하며, 특히 온프레미스 RDS를 AWS 환경 내 마이그레이션할 수 있는 도구도 다양하게 지원한다. (MySQL, Oracle, SQL Server, PostgreSQL, MariaDB, Aurora(MySQL과 호환) 등 지원)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;EC2에 RDB를 직접 설치하는 경우 비용 측면에서 확연히 강점이 있다. 또한, 타 클라우드 환경으로 이전할 경우 손쉽게 이전이 가능하다. 다만, 기 구축되어 있는 RDB가 존재하고 이를 운영하는 조직이 있으며, 데이터 사이즈가 크지 않을 경우에는 EC2 인스턴스에 구축하는 것이 비용을 절감할 수 있겠지만, 신규 구축되는 조직의 경우 운영 유지보수를 직접 수행 할 경우 반대의 효과가 날수도 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;또한, 보안 측면에서 강력한 RDS이지만, 때로는 기업에서 관리하는 소프트웨어를 설치하여 운영해야 하는 경우도 발생할 수 있다. 특히 이는 보안 뿐만 아니라 메트릭을 측정하는 솔루션이거나, 알람을 알려주는 솔루션 등 시스템 통합 측면의 솔루션들의 유연한 관리가 필요할 수 있다. 이 경우 RDS보다는 EC2 기반의 관리가 효율적일 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;인프라 운영을 위한 어플리케이션, 제대로 설계된 자동화 그리고 데이터베이스 전문 관리 팀이 있는 기업의 경우 RDS가 꼭 필요하지 않을 수 있다. 따라서 반드시 라기보다는 RDS의 기능, 장단점 그리고 비용 요소를 정확히 파악하여 구축 방법에 대해 결정하는 것이 바람직할 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;# 참조 (StatefulSet vs Deployment)&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;- StatefulSet 적용이 용이한 환경&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: 'Noto Serif KR'; color: #000000;&quot;&gt;IP 변경없이 직접 접근해야 하는 서비스 (Database, Redis, Kafka 등)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;데이터 유실이 발생하지 않아야 하는 서비스 (데이터 영속성을 유지해야 하는 경우)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;빈번한 업데이트와 다운타임이 발생되지 않아야 하는 중요한 서비스 (Rolling Update)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;- StatefulSet의 특징&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: 'Noto Serif KR'; color: #000000;&quot;&gt;스토리지 영속성을 유지하기 위해 Pod의 Storage는 PersistentVolume 또는 StorageClass로 프로비저닝해야 함&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Pod의 네트워크ID를 유지하기 위해 headless service 필요&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;# 참조 (Headless Service)&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Headless service란 .spec.clusterIP가 None으로 구성된 서비스를 의미한다. 서비스의 로드밸런싱 기능을 수행하지 않는 서비스이다. StatefulSet의 경우 Pod 별 개별 네트워크가 구성되어 있고 이와 통신하기 위한 DNS 정보를 할당하기 위한 용도로 Headless Service가 사용된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Pod DNS는 POD_NAME.SERVICE_NAME.NAMESPACE_NAME.svc.DNS_NAME으로 구성되며, 일반적으로는 mariadbpoda.mariadb.default.svc.cluster.local로 DNS가 구성된다. 따라서 이와 같은 DNS 정보를 유지하기 위해 Service 생성이 필요하다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;</description>
      <category>③ 클라우드/ⓐ AWS</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/778</guid>
      <comments>https://waspro.tistory.com/778#entry778comment</comments>
      <pubDate>Sat, 3 Sep 2022 00:59:27 +0900</pubDate>
    </item>
    <item>
      <title>Kubernetes Node 가용성 검증</title>
      <link>https://waspro.tistory.com/777</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;개요&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;클라우드 환경에서의 가용성 테스트는 레가시 환경과는 다르다. 직접 테스트를 수행하면서 알게된 Lessons learned을 통해 Kubernetes Node Failover에 대한 가용성 검증 과정에 대해 알아보자. Kubernetes가 관리하는 클러스터 내의 노드 장애 발생 시 어떻게 빠르게 인지하고 대응할 것인지 과정에 대해 검증해 보고, 최적 구성에 대해 알아보자.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Kubernetes 노드 가용성 관련 구성&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;1) kubelet&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: 'Noto Serif KR'; color: #000000;&quot;&gt;node-status-update-frequency : default 10s (api-server에 노드의 상태를 게시하는 주기) / &lt;span style=&quot;color: #ee2323;&quot;&gt;recommand 4s&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;node-status-report-frequency : default 5m (node-status-update-frequency가 구성될 경우 대체)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;2) controller-manager&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: 'Noto Serif KR'; color: #000000;&quot;&gt;node-monitor-period : default 5s (nodecontroller에서 node status를 동기화하는 시간) / &lt;span style=&quot;color: #ee2323;&quot;&gt;etcd 노드가 분리된 경우 recommand 2s, master node 통합 구성 시 5s 유지&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;node-monitor-grace-period : default 40s (node로부터 해당 시간 동안 응답을 받지 못한 경우 상태를 Not Ready 상태로 변경, node-monitor-grace-period = (N &amp;mdash; 1) * node-status-update-frequency #N은 kubelet Node Staus Retry Count) / &lt;span style=&quot;color: #ee2323;&quot;&gt;recommand 20s&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;pod-eviction-timeout : default 5m (노드에서 Pod를 삭제하기 위한 대기 시간)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;3) api-server&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: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;default-not-ready-toleration-seconds / &lt;/span&gt;default-unreachable-toleration-seconds : default 5m (toleration 지정되지 않은(default toleration - unreachable:NoExecute) Pod에 toleration을 적용하기 위한 tolerationSeconds)&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;/&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;recommand 30s&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&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;1695&quot; data-origin-height=&quot;741&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b84RpL/btrJSmSaf5z/q2OP5Ch4hWZhWKkKlZv3Q0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b84RpL/btrJSmSaf5z/q2OP5Ch4hWZhWKkKlZv3Q0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b84RpL/btrJSmSaf5z/q2OP5Ch4hWZhWKkKlZv3Q0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb84RpL%2FbtrJSmSaf5z%2Fq2OP5Ch4hWZhWKkKlZv3Q0%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;1695&quot; height=&quot;741&quot; data-origin-width=&quot;1695&quot; data-origin-height=&quot;741&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: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 노드가 중지되면, default 구성&amp;nbsp; 시 노드의 가용성을 확보하는데 5분 40초&lt;span style=&quot;color: #000000;&quot;&gt;(node-monitor-grace-period + pod-eviction-timeout)&lt;/span&gt;의 시간이 소요된다. 5분 40초라는 시간이 프로젝트 마다 다르겠지만, 가용할 수도 불가할 수도 있다. 따라서 각 프로젝트에 맞게 node-monitor-grace-period와 pod-eviction-timeout을 조정할 수 있도록 구성하는 것이 중요하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;i&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;## 특히 노드 가용성을 확보하기 위해 무작정 default 시간을 줄일 경우 역효과가 날 수 있다. node unhealty &amp;amp; endpoint에서 제거되면, 해당 pod는 타 노드에서 requires 수 많큼의 pod를 유지하기 위해 기동된다. 이는 scaling이 발생되며, pod 기동 시 발생하는 load와 일시적인 지연 현상이 발생될 수 있다. pod-eviction-timeout은 이를 방지하기 위해 해당 시간 내 node의 상태가 복구되면, 해당 pod를 다시 서비스에 포함하는 역할을 한다.&lt;/span&gt;&lt;/i&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1) kubelet 변경 (&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;node-status-update-frequency 변경)&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: 'Noto Serif KR'; color: #000000;&quot;&gt;모든 노드 대상으로 /var/lib/kubelet/kubeadm-flags.env 파일 수정&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&quot;--node-status-update-frequency=5s &quot; 옵션 추가 (KUBELET_KUBEADM_ARGS=&quot;...... --node-status-update-frequency=5s&quot;)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;파일 저장 후 kubelet 재시작&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2) kube-controller node-monitor-period 및 node-monitor-grace-period 변경&lt;br /&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: 'Noto Serif KR'; color: #000000;&quot;&gt;모든 master node에서 /etc/kubernetes/manifests/kube-controller-manager.yaml&amp;nbsp;수정&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;kube-controller-manager) &lt;/span&gt;--node-monitor-period=3s, --node-monitor-grace-period=20s&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;docker restart&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;3) kube-controller pod-eviction-timeout 변경&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: 'Noto Serif KR'; color: #000000;&quot;&gt;모든 master node의 /etc/kubernetes/manifests 하위에 kubeadm-apiserver-update.yaml 파일 생성&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1660661124779&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: kubeadm.k8s.io/v1beta2
kind: ClusterConfiguration
kubernetesVersion: v1.18.3
apiServer:
	extraArgs:
		enable-admission-plugins: DefaultTolerationSeconds
		default-not-ready-toleration-seconds: &quot;20&quot;
		default-unreachable-toleration-seconds: &quot;20&quot;&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: 'Noto Serif KR'; color: #000000;&quot;&gt;kubeadm init phase control-plane apiserver --config=kubeadm-apiserver-update.yaml 실행&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;/etc/kubernetes/manifests/kube-apiserver.yaml 변경 사항 적용 여부 확인&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Recommendations Case 구성&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1) 높은 노드 가용성 확보&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: 'Noto Serif KR'; color: #000000;&quot;&gt;--node-status-update-frequency=4s&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;--node-monitor-period=2s&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;--node-monitor-grace-period=20s&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;--default-not-ready-ready-readeration-seconds=30s&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;--default-readable-readeration-seconds=30s&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;node 다운 20s (&lt;span style=&quot;color: #000000;&quot;&gt;node-monitor-grace-period&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;pod 다운 50s (&lt;span style=&quot;color: #000000;&quot;&gt;node-monitor-grace-period&lt;/span&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt; + &lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;default-not-ready-tolleration-seconds or default-unreachable-tolleration-seconds&lt;/span&gt;&lt;/span&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;# 권고사항&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;모든 노드가 2초마다 상태를 업데이트하려고 하기 때문에 etcd에 오버헤드 발생 가능. &lt;/span&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;etcd 전용 노드 구성 필요.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2) 일반적인 구성&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: 'Noto Serif KR'; color: #000000;&quot;&gt;--node-status-update-frequency=20s&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;--node-monitor-grace-period=2m&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;--default-not-ready-tolleration-seconds=60s&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;node 다운 2m (&lt;span style=&quot;color: #000000;&quot;&gt;node-monitor-grace-period&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;pod 다운 3m (&lt;span style=&quot;color: #000000;&quot;&gt;node-monitor-grace-period&lt;/span&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;&amp;nbsp;+&lt;span&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;default-not-ready-tolleration-seconds or default-unreachable-tolleration-seconds&lt;/span&gt;&lt;/span&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;# 권고사항&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;nodeStatusUpdateFrequency에 따라 Pod 당(분당) 3번의 etcd 업데이트를 필요로 하기 때문에 중간 규모의 환경에 적합.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;3) 안정적인 구성과 pod 복원 고려&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: 'Noto Serif KR'; color: #000000;&quot;&gt;--node-status-update-frequency=1m&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;--node-monitor-grace-period=5m&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;--default-not-ready-tolleration-seconds=60&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;node 다운 5m (&lt;span style=&quot;color: #000000;&quot;&gt;node-monitor-grace-period&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;pod 다운 6m (node-monitor-grace-period&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;&amp;nbsp;+&amp;nbsp;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;default-not-ready-tolleration-seconds or default-unreachable-tolleration-seconds&lt;/span&gt;&lt;/span&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;# 권고사항&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;master node내 etcd를 함께 구성하는 경우 적합. Pod eviction 처리 보다 재 사용성을 고려한 환경 구성.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;결론&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Kubernetes 노드의 가용성은 프로젝트의 요구사항에 따라 달라질 수 있다. 구성의 변경은 민감하게 작용할 수 있기 때문에 그 역할과 SideEffect는 없는지 다시한번 확인할 필요가 있을 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;특히, 가장 중요한 점은 바로 해당 노드 위에 운영되는 어플리케이션의 특성을 이해하고 구성해야 한다는 점이다. &lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;빠른 노드 복원력과 안정적인 운영의 니즈에 맞게 Kubernetes를 변경하여 실 운영환경에 적용해 보도록 하자.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>③ 클라우드/ⓚ Kubernetes</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/777</guid>
      <comments>https://waspro.tistory.com/777#entry777comment</comments>
      <pubDate>Wed, 10 Aug 2022 01:21:17 +0900</pubDate>
    </item>
    <item>
      <title>Kubernetes Multi Container Design Pattern</title>
      <link>https://waspro.tistory.com/775</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;개요&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Pod는 Kubernetes의 최소 배포 단위이다. 어플리케이션은 Container로 구성되지만, Kubernetes에 배포하여 서비스하기 위해서는 Pod의 일부로 동작해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Kubernetes Object는 다음과 같은 종속성을 갖고&amp;nbsp;동작한다.&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;619&quot; data-origin-height=&quot;531&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pT1PH/btrFLCesktf/In0KADCZ9jZcGK8Gu8wEVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pT1PH/btrFLCesktf/In0KADCZ9jZcGK8Gu8wEVk/img.png&quot; data-alt=&quot;Deployment &amp;amp;gt; Replica &amp;amp;gt; Pod &amp;amp;gt; Container의 종속 관계&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pT1PH/btrFLCesktf/In0KADCZ9jZcGK8Gu8wEVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpT1PH%2FbtrFLCesktf%2FIn0KADCZ9jZcGK8Gu8wEVk%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;619&quot; height=&quot;531&quot; data-origin-width=&quot;619&quot; data-origin-height=&quot;531&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Deployment &amp;gt; Replica &amp;gt; Pod &amp;gt; Container의 종속 관계&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Pod는 컨테이너 Spec을 포함하여 선언되며, 하나 이상의 컨테이너를 선언할 수 있다. 이때 각 컨테이너는 독립된 어플리케이션으로 구성되며, 독립된 Process로 기동된다. 이로 인해 가능하면 Pod 당 1개의 Container 구성을 권고하지만, 때로 Multi Container 구성이 필요한 경우가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;지금부터 Multi Container를 설계하는 프로젝트에서 고려해야 할 사항에 대해 알아보자.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Multi Container 설계 고려 사항&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1 Pod - 1 Container 정책은 관행화된 규칙처럼 Kubernetes를 구축하고 운영하는 엔지니어들 사이의 불문율로 지켜지고 있다. 이와 같이 설계하는 이유 중 하나는 Kubernetes의 원활한 관리를 위해서이다. Kubernetes는 init process를 기준으로 container의 lifecycle을 관리하기 때문에 여러 container가 기동될 경우 Pod를 관리하는 것이 복잡해지고, 장애를 인지하기 어려운 점이 있다. 그럼에도 불구하여 때때로 Multi Container 구성으로 Pod를 설계해야 하는 경우가 있는데 이를 이해하기 위해 먼저 Pod 내 Container들의 동작 방식과 공유 방법에 대해 알아볼 필요가 있다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;Pod에는 IP가 할당된다. Pod의 모든 컨테이너는 동일한 IP를 공유한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Pod에 볼륨이 생성되면 Pod의 일부인 모든 컨테이너가 스토리지를 공유할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Container간 localhost를 통해 통신할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1375&quot; data-origin-height=&quot;780&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbx85X/btrFTcUiS1Z/nUxsHwSKVC7PMMBMvRYeik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbx85X/btrFTcUiS1Z/nUxsHwSKVC7PMMBMvRYeik/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbx85X/btrFTcUiS1Z/nUxsHwSKVC7PMMBMvRYeik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbbx85X%2FbtrFTcUiS1Z%2FnUxsHwSKVC7PMMBMvRYeik%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;1375&quot; height=&quot;780&quot; data-origin-width=&quot;1375&quot; data-origin-height=&quot;780&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: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 컨테이너 간 공유 서비스가 손쉽게 동작하지만, 왜 Pod 당 1 Container를 선호하는지 고민해 보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;약간 극단적인 예시이긴 하지만, 위와 같이 WEB SERVER, WAS SERVER, DATABASE 및 MESSAGE QUEUE Layer를 갖는 웹 애플리케이션을 살펴보자. &lt;/span&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;왼쪽은 4개 Layer 모두를 단일 Pod에 구현하였다. 각 Layer 별 주요 워크로드를 다음과 같이 정의해 보자.&lt;/span&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: 'Noto Serif KR'; color: #000000;&quot;&gt;WEB SERVER의 경우 Server Side에서 정적 이미지 처리를 중점적으로 담당하며, 외부 서비스와 직접 통신하는 Back-end For Front-end Pattern을 지원한다. 이로 인해 I/O 사용량이 높다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;WAS SERVER의 경우 API 중심 서비스를 제공하며, 데이터베이스를 조회하거나, 또 다른 클라우드 내 마이크로서비스, 미니서비스 또는 레거시 서비스의 인터페이스 역할을 함께 담당한다. 이로 인해 네트워크 소모값이 크고, 웹 어플리케이션의 특성에 따라 메모리 사용량이 높다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;DATABASE의 경우 솔루션 영역으로 확장되지 않는 StatefulSet 구조로 구성된다. 연산처리를 위해 CPU 사용량이 높다. 또한, 자동 확장 구성을 지원하지 않는 솔루션이 설치되어 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Message Queue의 경우 솔루션 영역으로 확장되지 않는 StatefulSet 구조로 구성된다. 클러스터로 구성되어 있어 Pod간 전달해야 할 네트워크 비용이 높고, 메모리 상에 점유하는 메시지에 의해 Memory 사용량이 높다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;위와 같을 경우 &lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;각 Layer는 요구하는 리소스, 구성방식이 모두 다르기 때문에 &lt;/span&gt;각 Layer가 갖고 있는 특성을 살린 컨테이너 환경 구성이 어렵다. 또한 이 경우 Layer 별 확장이 불가능하여 불필요한 리소스를 낭비해야 한다. 특히 확장이 불가능한 Container가 포함되어 있을 경우 확장 자체가 불가능할 수도 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;예를 들어 WAS SERVER에 병목이 발생하여 확장이 필요할 경우 WEB SERVER, DATABASE 및 MESSAGE QUEUE의 컨테이너도 함께 확장되어야 한다. 이는 불필요한 서비스 확장으로 이어진다. 이와 같은 이유로 각&lt;/span&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt; Pod 당 독립적인 어플리케이션이 동작할 수 있도록 1 Container 구성 및 이를 확장할 수 있도록 관리하는 것을 선호한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;그렇다면 동일한 Pod에서 여러 컨테이너를 사용할 수 있는 경우는 언제일까?&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: 'Noto Serif KR'; color: #000000;&quot;&gt;사례 1 - 컨테이너의 LifeCycle이 동일한 경우&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;위 예시에서 이야기한 것 처럼 컨테이너가 여러개 동작 할 경우 lifecycle이 서로 다른 process의 동작에 의해 container management platform(kubernetes)에서 관리 컨트롤이 어렵다는 점에서 컨테이너 lifecycle이 동일한 container의 경우 예외적인 multi container 사용이 가능하다. 이는 대체로 솔루션 영역에 종속되는 경우가 많으며, 단일 솔루션 내 여러 프로세스가 기동되고 각 프로세스는 하나가 종료되었을때 전체가 동일하게 동작할 수 있도록 내부 매커니즘이 설계되어 있는 경우 LifeCycle이 동일하다고 판단할 수 있다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;사례 2 - 두 개의 컨테이너가 매우 높은 결합도를 보이는 경우&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;컨테이너 간 높은 결합도가 있는 서비스의 경우 오히려 위에 제시한 ip, 볼륨, 네트워크의 공유로 인해 성능 및 비용 효율성 측면에서 하나의 Pod에 구성하는 것이 효과적일 수 있다. 불필요한 network hop을 줄이고, 업무 영향도를 줄이기 위해 multi container 구성이 가능하다. 물론 이는 서비스 결합도를 낮출 수 있는 여러 개발 패턴으로도 해소할 수 있지만, 단납기 프로젝트의 경우 이를 적용하여 빠르게 개발을 완료하고 서비스를 런칭할 수 있다. 이는 마이크로서비스 패턴의 상위 개념으로 미니서비스 단위로 판단할 수도 있다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;사례 3 - 코드 변경 없이 어플리케이션을 Kubernetes에 배포해야 하는 경우&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;마지막으로 어플리케이션의 영향도를 최소화 하기 위해 적용할 수 있다. 클라우드 환경의 어플리케이션은 폴리그랏 언어를 지원할 경우 그 형태가 다양하여 이를 지원해야 하는 인프라 복잡도는 사실상 증가하게 된다. 특히 공통 영역은 각 언어와 다양한 솔루션 모두에 최적화 될 수 없기에 예외적으로 multi container를 적용하여 공통 서비스를 호출할 수 있는 인터페이스 영역을 구현하거나, 데이터 포맷을 정형화 하는 등의 용도로 활용이 가능하다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;그럼 지금부터는 위와 같은 사례를 기준으로 multi container로 구현할 수 있는 디자인 패턴 형태에 대해 알아보자.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Multi Container 디자인 패턴&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Adapter Pattern&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Adapter Pattern은 말 그대로 원 형태의 Main Container에 배포되어 있는 어플리케이션에 Adapter 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;542&quot; data-origin-height=&quot;227&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bNncKa/btrFVULU9Bk/125IN14ld61lO0SsF9XR3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bNncKa/btrFVULU9Bk/125IN14ld61lO0SsF9XR3k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bNncKa/btrFVULU9Bk/125IN14ld61lO0SsF9XR3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbNncKa%2FbtrFVULU9Bk%2F125IN14ld61lO0SsF9XR3k%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;542&quot; height=&quot;227&quot; data-origin-width=&quot;542&quot; data-origin-height=&quot;227&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: 'Noto Serif KR'; color: #000000;&quot;&gt;대표적인 Adapter Pattern으로는 로깅 모듈, 공통 모듈, 인터페이스 모듈이 있다. 예를 들어 Kubernetes 클러스터에 log aggregation 환경을 구성할 경우 로그 형태에 따라 추적 분석할 수 있도록 형태를 정형화해야 한다. 그러나 클러스터에는 다양한 형식의 로그를 출력하는 다양한 언어로 작성된 다수의 어플리케이션이 존재할 수 있다. 특히 log aggregation을 위한 도구(elasticsearch, splunk 등)가 변경될 경우 모든 어플리케이션에서 로깅 형태를 다시 변경해야 한다면, 이는 굉장히 비효율적인 업무 처리 방식이 될 것이다. 이 문제를 해결하기 위해 기본 어플리케이션 컨테이너(Main Container)의 로그를 읽고 모니터링 도구에서 원하는 형식으로 변환하여 처리하는 Adapter Container를 생성할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Ambassador Pattern&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Ambassador Pattern은 Main Container의 Proxy 역할을 하는 Container이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;예를 들어 DB URL이 애플리케이션 내부에 localhost로 하드코딩된 레거시 어플리케이션이 있다고 가정하자. 이때 레거시 어플리케이션 코드 변경 없이 Kubernetes에 배포하고자 할 경우 Ambassador 패턴을 사용하면 코드 변경 없이 적용할 수 있다. Ambassador Container를 적용하면, Dev, QA 또는 Stage 환경에 따라 변경되는 DB URL을 수정하지 않고도 원하는 데이터베이스에 연결할 수 있다.&amp;nbsp;&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;542&quot; data-origin-height=&quot;319&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/72sMC/btrFTOF7GrA/JGmTNSHx6qm7KsPd0kf191/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/72sMC/btrFTOF7GrA/JGmTNSHx6qm7KsPd0kf191/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/72sMC/btrFTOF7GrA/JGmTNSHx6qm7KsPd0kf191/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F72sMC%2FbtrFTOF7GrA%2FJGmTNSHx6qm7KsPd0kf191%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;542&quot; height=&quot;319&quot; data-origin-width=&quot;542&quot; data-origin-height=&quot;319&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: 'Noto Serif KR'; color: #000000;&quot;&gt;메인 애플리케이션은 Ambassador Container를 통해 외부 URL에 연결할 수 있다. 이 경우 레거시 어플리케이션의 변경을 최소화 할 수 있으며, 이후 변경되는 URL에 대해 걱정할 필요가 없게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Sidecar Pattern&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Sidecar Pattern은 필수 기능은 아니지만, 어플리케이션 Container의 기능 또는 성능을 향상 시키기 위해 추가적으로 동작하는 업무를 배치하는데 사용된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Main Container를 변경하지 않고 기능을 적용하고 향상시킬 수 있다. 예를 들어 특정 폴더에 로그 파일을 생성하는 애플리케이션이 있는 경우 Sidecar Container는 App log를 Streaming 또는 File처리 로직을 통해 전체 로그를 수집하는 Cluster Log Store로 복제할 수 있다. 이때, Main 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;542&quot; data-origin-height=&quot;355&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ccgdcF/btrFT2YqujL/miN0IvhlfJRNJKOKG01B0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ccgdcF/btrFT2YqujL/miN0IvhlfJRNJKOKG01B0K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ccgdcF/btrFT2YqujL/miN0IvhlfJRNJKOKG01B0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FccgdcF%2FbtrFT2YqujL%2FmiN0IvhlfJRNJKOKG01B0K%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;542&quot; height=&quot;355&quot; data-origin-width=&quot;542&quot; data-origin-height=&quot;355&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;style5&quot; /&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: 'Noto Serif KR'; color: #000000;&quot;&gt;결론&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;지금까지 Kubernetes Multi Container Design Pattern에 대해 알아보았다. 이를 통해 알 수 있는 사실은 Multi Container를 통해 어플리케이션을 변경하지 않고 또 다른 목적을 갖고 어플리케이션을 처리하거나, 데이터를 조작하는데 활용된다는 점이다. 또한, 이러한 워크로드는 다른 Pod에서 재사용할 수 있는 방식으로 작성되어야 한다는 점도 기억해야 한다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;Adapter Pattern : Main Container의 OutPut(데이터, 로그, 인터페이스 대상 정보 등)을 원하는 형태로 변환 처리하는 용도&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Ambassador Pattern : 자주 변경될 가능성이 있는 또는 공통으로 관리되어야 하는 Nerwork Route 정보를 관리하는 Proxy Server 용도&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Sidecar Pattern : Main Container를 서포트 하는 유틸리티 서비스를 제공하는 용도&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이러한 Multi Container 패턴을 적용하여 Kubernetes Cluster를 확장하는데 유용하게 활용하기를 기대한다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>③ 클라우드/ⓚ Kubernetes</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/775</guid>
      <comments>https://waspro.tistory.com/775#entry775comment</comments>
      <pubDate>Sun, 26 Jun 2022 22:52:43 +0900</pubDate>
    </item>
    <item>
      <title>Terraform으로 EC2 인스턴스 생성하기</title>
      <link>https://waspro.tistory.com/773</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;개요&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Cloud 환경은 복잡한 인프라로 구성되어 있어 그 일관성을 항상 유지하는 것은 어려운 일이다. 특히 확장성있게 증가하는 인프라 환경을 사람의 힘으로 관리하는 것은 민첩성과 안정성을 저해하는 요소가 된다. &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;이에 인프라를 코드로 관리하는 &lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;'코드형 인프라(IaC)'&lt;/span&gt;가 등장하게 되었고, 이를 통해 일관된 클라우드 인프라를 관리할 수 있게 되었다. 대표적인 IaC로는 Terraform이 있으며, AWS에는 CloudFormation이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;이번 포스팅부터 Terraform 활용에 대해서는 별도 목차를 구분하여 작성하고자 한다. 그 첫 시간으로 Terraform을 사용하여 EC2 인스턴스를 생성하는 과정에 대해 알아보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Terraform 설치&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;아래와 같이 yum package manager를 통해 쉽게 설치가 가능하다. repository는 OS별로 각각 서로 다른 Repository를 추가한다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;yum install -y yum-utils&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;yum-config-manager&amp;nbsp;--add-repo&amp;nbsp;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://rpm.releases.hashicorp.com/AmazonLinux/hashicorp.repo&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://rpm.releases.hashicorp.com/AmazonLinux/hashicorp.repo&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;yum install -y terraform&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;which terraform&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;terraform&amp;nbsp;version&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1650093814934&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# yum install -y yum-utils
Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
Package yum-utils-1.1.31-46.amzn2.0.1.noarch already installed and latest version
Nothing to do
[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# yum-config-manager --add-repo https://rpm.releases.hashicorp.com/AmazonLinux/hashicorp.repo
Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
adding repo from: https://rpm.releases.hashicorp.com/AmazonLinux/hashicorp.repo
grabbing file https://rpm.releases.hashicorp.com/AmazonLinux/hashicorp.repo to /etc/yum.repos.d/hashicorp.repo
repo saved to /etc/yum.repos.d/hashicorp.repo
[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# yum -y install terraform
Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
Resolving Dependencies
--&amp;gt; Running transaction check
---&amp;gt; Package terraform.x86_64 0:1.1.8-1 will be installed
--&amp;gt; Finished Dependency Resolution

Dependencies Resolved

=======================================================================================================================================================================================================
 Package                                          Arch                                          Version                                         Repository                                        Size
=======================================================================================================================================================================================================
Installing:
 terraform                                        x86_64                                        1.1.8-1                                         hashicorp                                         12 M

Transaction Summary
=======================================================================================================================================================================================================
Install  1 Package

Total download size: 12 M
Installed size: 60 M
Downloading packages:
terraform-1.1.8-1.x86_64.rpm                                                                                                                                                    |  12 MB  00:00:00
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  Installing : terraform-1.1.8-1.x86_64                                                                                                                                                            1/1
  Verifying  : terraform-1.1.8-1.x86_64                                                                                                                                                            1/1

Installed:
  terraform.x86_64 0:1.1.8-1

Complete!
[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# which terraform
/usr/bin/terraform
[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# terraform version
Terraform v1.1.8
on linux_amd64
[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]#&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Terraform Script 작성&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;다음으로 Terraform Script(main.tf)를 작성한다. Terraform Script는 default로 main.tf를 참조한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1650094488462&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 terraform (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# cat main.tf
terraform {
  required_providers {
    aws = {
      source  = &quot;hashicorp/aws&quot;
      version = &quot;~&amp;gt; 3.27&quot;
    }
  }

  required_version = &quot;&amp;gt;= 0.14.9&quot;
}

provider &quot;aws&quot; {
  profile = &quot;default&quot;
  region  = &quot;ap-northeast-2&quot;
}

resource &quot;aws_instance&quot; &quot;ec2&quot; {
  ami                    = &quot;ami-xxxxxxxxxxxxxxxxx&quot;
  instance_type          = &quot;t3.xlarge&quot;
}
[root@ip-192-168-78-195 terraform (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]#&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: 'Noto Serif KR'; color: #000000;&quot;&gt;terraform : provider, version에 대한 정보를 명확히 기입하여 현재 리소스를 생성하고자 하는 환경에 대한 정보 정의&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;provider : terraform 필드에서 정의한 provider에 접근하기 위한 정보 정의&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;resource : 생성하고자 하는 리소스 정보 정의 resource &quot;module&quot; &quot;resource_name&quot; 형태로 정의 (ex - aws_instance를 ec2라는 이름으로 생성. 하부 태그는 module에 대한 상세 정보.)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Terraform 실행&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;1. terraform init (terraform 실행 초기화)&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1650096088528&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 terraform (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# terraform init

Initializing the backend...

Initializing provider plugins...
- Finding hashicorp/aws versions matching &quot;~&amp;gt; 3.27&quot;...
- Installing hashicorp/aws v3.75.1...
- Installed hashicorp/aws v3.75.1 (signed by HashiCorp)

Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run &quot;terraform init&quot; in the future.

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running &quot;terraform plan&quot; to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
[root@ip-192-168-78-195 terraform (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;2. terraform fmt (terraform 설정파일 수정)&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1650096169464&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 terraform (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# terraform fmt
main.tf
[root@ip-192-168-78-195 terraform (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;3. terraform validate (terraform 설정파일 검증)&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1650096208258&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 terraform (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# terraform validate
Success! The configuration is valid.

[root@ip-192-168-78-195 terraform (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;4. aws ec2 describe-instances --query &quot;Reservations[].Instances[].InstanceId&quot; (현재 생성되어 있는 ec2 인스턴스)&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1650096314228&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 terraform (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# aws ec2 describe-instances --query &quot;Reservations[].Instances[].InstanceId&quot;
[
    &quot;i-0667fadc7d193112d&quot;,
    &quot;i-07647537570c72296&quot;
]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;5. terraform apply (terraform resource 생성)&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1650096402225&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 terraform (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# terraform apply

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # aws_instance.ec2 will be created
  + resource &quot;aws_instance&quot; &quot;ec2&quot; {
      + ami                                  = &quot;ami-0d3f686a76ad0de18&quot;
      + arn                                  = (known after apply)
      + associate_public_ip_address          = (known after apply)
      + availability_zone                    = (known after apply)
      + cpu_core_count                       = (known after apply)
      + cpu_threads_per_core                 = (known after apply)
      + disable_api_termination              = (known after apply)
      + ebs_optimized                        = (known after apply)
      + get_password_data                    = false
      + host_id                              = (known after apply)
      + id                                   = (known after apply)
      + instance_initiated_shutdown_behavior = (known after apply)
      + instance_state                       = (known after apply)
      + instance_type                        = &quot;t3.xlarge&quot;
      + ipv6_address_count                   = (known after apply)
      + ipv6_addresses                       = (known after apply)
      + key_name                             = (known after apply)
      + monitoring                           = (known after apply)
      + outpost_arn                          = (known after apply)
      + password_data                        = (known after apply)
      + placement_group                      = (known after apply)
      + placement_partition_number           = (known after apply)
      + primary_network_interface_id         = (known after apply)
      + private_dns                          = (known after apply)
      + private_ip                           = (known after apply)
      + public_dns                           = (known after apply)
      + public_ip                            = (known after apply)
      + secondary_private_ips                = (known after apply)
      + security_groups                      = (known after apply)
      + source_dest_check                    = true
      + subnet_id                            = (known after apply)
      + tags_all                             = (known after apply)
      + tenancy                              = (known after apply)
      + user_data                            = (known after apply)
      + user_data_base64                     = (known after apply)
      + vpc_security_group_ids               = (known after apply)

      + capacity_reservation_specification {
          + capacity_reservation_preference = (known after apply)

          + capacity_reservation_target {
              + capacity_reservation_id = (known after apply)
            }
        }

      + ebs_block_device {
          + delete_on_termination = (known after apply)
          + device_name           = (known after apply)
          + encrypted             = (known after apply)
          + iops                  = (known after apply)
          + kms_key_id            = (known after apply)
          + snapshot_id           = (known after apply)
          + tags                  = (known after apply)
          + throughput            = (known after apply)
          + volume_id             = (known after apply)
          + volume_size           = (known after apply)
          + volume_type           = (known after apply)
        }

      + enclave_options {
          + enabled = (known after apply)
        }

      + ephemeral_block_device {
          + device_name  = (known after apply)
          + no_device    = (known after apply)
          + virtual_name = (known after apply)
        }

      + metadata_options {
          + http_endpoint               = (known after apply)
          + http_put_response_hop_limit = (known after apply)
          + http_tokens                 = (known after apply)
          + instance_metadata_tags      = (known after apply)
        }

      + network_interface {
          + delete_on_termination = (known after apply)
          + device_index          = (known after apply)
          + network_interface_id  = (known after apply)
        }

      + root_block_device {
          + delete_on_termination = (known after apply)
          + device_name           = (known after apply)
          + encrypted             = (known after apply)
          + iops                  = (known after apply)
          + kms_key_id            = (known after apply)
          + tags                  = (known after apply)
          + throughput            = (known after apply)
          + volume_id             = (known after apply)
          + volume_size           = (known after apply)
          + volume_type           = (known after apply)
        }
    }

Plan: 1 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_instance.ec2: Creating...
aws_instance.ec2: Still creating... [10s elapsed]
aws_instance.ec2: Creation complete after 12s [id=i-09357bb8a63838d3c]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
[root@ip-192-168-78-195 terraform (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;6. terraform show (terraform으로 생성한 리소스 정보 출력)&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1650096453865&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 terraform (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# terraform show
# aws_instance.ec2:
resource &quot;aws_instance&quot; &quot;ec2&quot; {
    ami                                  = &quot;ami-0d3f686a76ad0de18&quot;
    arn                                  = &quot;arn:aws:ec2:ap-northeast-2:104818303680:instance/i-09357bb8a63838d3c&quot;
    associate_public_ip_address          = true
    availability_zone                    = &quot;ap-northeast-2d&quot;
    cpu_core_count                       = 2
    cpu_threads_per_core                 = 2
    disable_api_termination              = false
    ebs_optimized                        = false
    get_password_data                    = false
    hibernation                          = false
    id                                   = &quot;i-09357bb8a63838d3c&quot;
    instance_initiated_shutdown_behavior = &quot;stop&quot;
    instance_state                       = &quot;running&quot;
    instance_type                        = &quot;t3.xlarge&quot;
    ipv6_address_count                   = 0
    ipv6_addresses                       = []
    monitoring                           = false
    primary_network_interface_id         = &quot;eni-0b6f70ee1be02ab9e&quot;
    private_dns                          = &quot;ip-172-31-51-221.ap-northeast-2.compute.internal&quot;
    private_ip                           = &quot;172.31.51.221&quot;
    public_dns                           = &quot;ec2-3-37-15-65.ap-northeast-2.compute.amazonaws.com&quot;
    public_ip                            = &quot;3.37.15.65&quot;
    secondary_private_ips                = []
    security_groups                      = [
        &quot;default&quot;,
    ]
    source_dest_check                    = true
    subnet_id                            = &quot;subnet-0aae81bee94e876cd&quot;
    tags_all                             = {}
    tenancy                              = &quot;default&quot;
    vpc_security_group_ids               = [
        &quot;sg-016d5d1659dfc56cd&quot;,
    ]

    capacity_reservation_specification {
        capacity_reservation_preference = &quot;open&quot;
    }

    credit_specification {
        cpu_credits = &quot;unlimited&quot;
    }

    enclave_options {
        enabled = false
    }

    metadata_options {
        http_endpoint               = &quot;enabled&quot;
        http_put_response_hop_limit = 1
        http_tokens                 = &quot;optional&quot;
        instance_metadata_tags      = &quot;disabled&quot;
    }

    root_block_device {
        delete_on_termination = true
        device_name           = &quot;/dev/xvda&quot;
        encrypted             = false
        iops                  = 192
        tags                  = {}
        throughput            = 0
        volume_id             = &quot;vol-01a8e901e3a88a529&quot;
        volume_size           = 64
        volume_type           = &quot;gp2&quot;
    }
}
[root@ip-192-168-78-195 terraform (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;7. aws ec2 describe-instances --query &quot;Reservations[].Instances[].InstanceId&quot; (현재 생성되어 있는 ec2 인스턴스)&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1650096487832&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 terraform (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# aws ec2 describe-instances --query &quot;Reservations[].Instances[].InstanceId&quot;
[
    &quot;i-0667fadc7d193112d&quot;,
    &quot;i-07647537570c72296&quot;,
    &quot;i-09357bb8a63838d3c&quot;
]
[root@ip-192-168-78-195 terraform (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;8. terraform destroy (terraform으로 생성한 리소스 삭제)&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1650096523321&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 terraform (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# terraform destroy
aws_instance.ec2: Refreshing state... [id=i-09357bb8a63838d3c]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  - destroy

Terraform will perform the following actions:

  # aws_instance.ec2 will be destroyed
  - resource &quot;aws_instance&quot; &quot;ec2&quot; {
      - ami                                  = &quot;ami-0d3f686a76ad0de18&quot; -&amp;gt; null
      - arn                                  = &quot;arn:aws:ec2:ap-northeast-2:104818303680:instance/i-09357bb8a63838d3c&quot; -&amp;gt; null
      - associate_public_ip_address          = true -&amp;gt; null
      - availability_zone                    = &quot;ap-northeast-2d&quot; -&amp;gt; null
      - cpu_core_count                       = 2 -&amp;gt; null
      - cpu_threads_per_core                 = 2 -&amp;gt; null
      - disable_api_termination              = false -&amp;gt; null
      - ebs_optimized                        = false -&amp;gt; null
      - get_password_data                    = false -&amp;gt; null
      - hibernation                          = false -&amp;gt; null
      - id                                   = &quot;i-09357bb8a63838d3c&quot; -&amp;gt; null
      - instance_initiated_shutdown_behavior = &quot;stop&quot; -&amp;gt; null
      - instance_state                       = &quot;running&quot; -&amp;gt; null
      - instance_type                        = &quot;t3.xlarge&quot; -&amp;gt; null
      - ipv6_address_count                   = 0 -&amp;gt; null
      - ipv6_addresses                       = [] -&amp;gt; null
      - monitoring                           = false -&amp;gt; null
      - primary_network_interface_id         = &quot;eni-0b6f70ee1be02ab9e&quot; -&amp;gt; null
      - private_dns                          = &quot;ip-172-31-51-221.ap-northeast-2.compute.internal&quot; -&amp;gt; null
      - private_ip                           = &quot;172.31.51.221&quot; -&amp;gt; null
      - public_dns                           = &quot;ec2-3-37-15-65.ap-northeast-2.compute.amazonaws.com&quot; -&amp;gt; null
      - public_ip                            = &quot;3.37.15.65&quot; -&amp;gt; null
      - secondary_private_ips                = [] -&amp;gt; null
      - security_groups                      = [
          - &quot;default&quot;,
        ] -&amp;gt; null
      - source_dest_check                    = true -&amp;gt; null
      - subnet_id                            = &quot;subnet-0aae81bee94e876cd&quot; -&amp;gt; null
      - tags                                 = {} -&amp;gt; null
      - tags_all                             = {} -&amp;gt; null
      - tenancy                              = &quot;default&quot; -&amp;gt; null
      - vpc_security_group_ids               = [
          - &quot;sg-016d5d1659dfc56cd&quot;,
        ] -&amp;gt; null

      - capacity_reservation_specification {
          - capacity_reservation_preference = &quot;open&quot; -&amp;gt; null
        }

      - credit_specification {
          - cpu_credits = &quot;unlimited&quot; -&amp;gt; null
        }

      - enclave_options {
          - enabled = false -&amp;gt; null
        }

      - metadata_options {
          - http_endpoint               = &quot;enabled&quot; -&amp;gt; null
          - http_put_response_hop_limit = 1 -&amp;gt; null
          - http_tokens                 = &quot;optional&quot; -&amp;gt; null
          - instance_metadata_tags      = &quot;disabled&quot; -&amp;gt; null
        }

      - root_block_device {
          - delete_on_termination = true -&amp;gt; null
          - device_name           = &quot;/dev/xvda&quot; -&amp;gt; null
          - encrypted             = false -&amp;gt; null
          - iops                  = 192 -&amp;gt; null
          - tags                  = {} -&amp;gt; null
          - throughput            = 0 -&amp;gt; null
          - volume_id             = &quot;vol-01a8e901e3a88a529&quot; -&amp;gt; null
          - volume_size           = 64 -&amp;gt; null
          - volume_type           = &quot;gp2&quot; -&amp;gt; null
        }
    }

Plan: 0 to add, 0 to change, 1 to destroy.

Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes

aws_instance.ec2: Destroying... [id=i-09357bb8a63838d3c]
aws_instance.ec2: Still destroying... [id=i-09357bb8a63838d3c, 10s elapsed]
aws_instance.ec2: Still destroying... [id=i-09357bb8a63838d3c, 20s elapsed]
aws_instance.ec2: Still destroying... [id=i-09357bb8a63838d3c, 30s elapsed]
aws_instance.ec2: Still destroying... [id=i-09357bb8a63838d3c, 40s elapsed]
aws_instance.ec2: Still destroying... [id=i-09357bb8a63838d3c, 50s elapsed]
aws_instance.ec2: Still destroying... [id=i-09357bb8a63838d3c, 1m0s elapsed]
aws_instance.ec2: Still destroying... [id=i-09357bb8a63838d3c, 1m10s elapsed]
aws_instance.ec2: Destruction complete after 1m20s

Destroy complete! Resources: 1 destroyed.
[root@ip-192-168-78-195 terraform (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;9. &lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;aws ec2 describe-instances --query &quot;Reservations[].Instances[].InstanceId&quot; (현재 생성되어 있는 ec2 인스턴스)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1650096559904&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 terraform (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# aws ec2 describe-instances --query &quot;Reservations[].Instances[].InstanceId&quot;
[
    &quot;i-0667fadc7d193112d&quot;,
    &quot;i-07647537570c72296&quot;
]
[root@ip-192-168-78-195 terraform (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]#&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;결론&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;이번 시간에는 Terraform 설치 및 ec2 instance를 생성하는 과정에 대해 Quick하게 알아보았다. Terraform은 Provider에 대한 제약이 없는 IaC로 다양한 환경에서 각광받고 있다. &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;이는 Public/Private Cloud 가리지 않고 여러 클라우드 인프라를 관리하는 주용 기술로써 활용되고 있다. 특히 사용하지 않는 인프라를 삭제하고 필요 시 일관성있게 생성하는 등 비용적인 이점도 가져갈 수 있다.&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>③ 클라우드/ⓣ Terraform</category>
      <category>terraform</category>
      <category>terraform apply</category>
      <category>terraform init</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/773</guid>
      <comments>https://waspro.tistory.com/773#entry773comment</comments>
      <pubDate>Thu, 14 Apr 2022 23:33:26 +0900</pubDate>
    </item>
    <item>
      <title>어플리케이션 &amp;amp; 클러스터 통합 모니터링 (Kuberhealthy &amp;amp; Prometheus)</title>
      <link>https://waspro.tistory.com/772</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;개요&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Kubernetes는 수 많은 객체들의 집합으로 구성되어 있으며, 이는 확장성 가능하게 구성되어 클러스터 내 장애 상황을 식별하는 것은 굉장히 번거로운 일이라고 볼 수 있다. 이로 인해 Kubernetes 클러스터 내의 다양한 각도에서 모니터링할 수 있는 환경을 구성하는 것은 장애 발생으로 인한 가동 중지 시간을 줄이거나 피할 수 있다. 대표적인 장애 상황은 다음을 예로 들 수 있다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;노드 문제 : 실패 상태의 Docker 데몬/Kubelet, CNI 실패로 인한 할당되지 않은 IP 주소 등&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;포드 문제 : Health Check 실패, Running 상태가 아닌 포드 등&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;네임스페이스 문제 : Pod를 배치할 수 없는 Namespace&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;DNS 확인 문제 : CoreDNS lookup 실패&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;네트워크 문제 : 네트워크 정책 변경 등&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Kuberhalthy는 모니터링 및 지속적인 프로세스 검증을 위한 &lt;span style=&quot;color: #006dd7;&quot;&gt;Kubernetes Operator&lt;/span&gt;이다. Kuberhealthy가 제공하는 Synthetic Check는 khcheck/khjob이라는 사용자 지정 리소스에 의해 생성된 테스트 컨테이너이다. Check가 생성되면 Kuberhealthy는 주어진 간격과 제한 시간 내에 모든 검사를 예약한다. khjob이 한 번 실행되는 반면 khcheck는 정기적인 간격으로 실행된다는 점을 제외하면 기능면에서 거의 동일하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;u&gt;&lt;i&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;Kubernetes Operator&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;는 Kubernetes 코드 자체를 수정하지 않고도 컨트롤러를 하나 이상의 사용자 정의 리소스(custom resource)에 연결하여 클러스터의 동작을 확장할 수 있다. 오퍼레이터는 사용자 정의 리소스의 컨트롤러 역할을 하는 쿠버네티스 API의 클라이언트이다.&quot;&lt;/span&gt;&lt;/i&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Kuberhealthy는 특정 khcheck에 해당하는 Checker Pod를 프로비저닝한다. 목적이 달성되면 Checker Pod는 삭제된다. 생성/삭제 주기는 khcheck 구성에서 runInterval/timeout의 지속 시간에 따라 일정한 간격으로 반복된다. 결과는 Kuberhealthy로 전송되고 Kuberhealthy는 이를 모니터링을 위해 Prometheus와 통합하거나 JSON 기반 상태 페이지에서 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Kuberhealthy 설치&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;1. kube-prometheus-stack 설치&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;a. namespace 생성&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1649255793952&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# kubectl create namespace monitoring
namespace/monitoring created
[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# kubectl config set-context --current --namespace=monitoring
Context &quot;iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io&quot; modified.
[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:monitoring)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;b. kube-prometheus-stack 설치&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1649255868121&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:monitoring)]# helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
&quot;prometheus-community&quot; already exists with the same configuration, skipping
[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:monitoring)]# helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the &quot;nfs-subdir-external-provisioner&quot; chart repository
...Successfully got an update from the &quot;kuberhealthy&quot; chart repository
...Successfully got an update from the &quot;prometheus-community&quot; chart repository
Update Complete. 뉸appy Helming!
[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:monitoring)]# helm install prometheus prometheus-community/kube-prometheus-stack
NAME: prometheus
LAST DEPLOYED: Tue Apr  5 03:25:09 2022
NAMESPACE: monitoring
STATUS: deployed
REVISION: 1
NOTES:
kube-prometheus-stack has been installed. Check its status by running:
  kubectl --namespace monitoring get pods -l &quot;release=prometheus&quot;

Visit https://github.com/prometheus-operator/kube-prometheus for instructions on how to create &amp;amp; configure Alertmanager and Prometheus instances using the Operator.
[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:monitoring)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;c. 설치 확인&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1649255929480&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:monitoring)]# kubectl get svc -n monitoring
NAME                                      TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE
alertmanager-operated                     ClusterIP   None             &amp;lt;none&amp;gt;        9093/TCP,9094/TCP,9094/UDP   12s
prometheus-grafana                        ClusterIP   10.100.207.52    &amp;lt;none&amp;gt;        80/TCP                       22s
prometheus-kube-prometheus-alertmanager   ClusterIP   10.100.88.52     &amp;lt;none&amp;gt;        9093/TCP                     22s
prometheus-kube-prometheus-operator       ClusterIP   10.100.132.210   &amp;lt;none&amp;gt;        443/TCP                      22s
prometheus-kube-prometheus-prometheus     ClusterIP   10.100.206.148   &amp;lt;none&amp;gt;        9090/TCP                     22s
prometheus-kube-state-metrics             ClusterIP   10.100.190.195   &amp;lt;none&amp;gt;        8080/TCP                     22s
prometheus-operated                       ClusterIP   None             &amp;lt;none&amp;gt;        9090/TCP                     12s
prometheus-prometheus-node-exporter       ClusterIP   10.100.243.19    &amp;lt;none&amp;gt;        9100/TCP                     22s
[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:monitoring)]# k get service prometheus-kube-prometheus-prometheus -n monitoring
NAME                                    TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
prometheus-kube-prometheus-prometheus   ClusterIP   10.100.206.148   &amp;lt;none&amp;gt;        9090/TCP   40s
[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:monitoring)]# k get service prometheus-grafana -n monitoring
NAME                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
prometheus-grafana   ClusterIP   10.100.207.52   &amp;lt;none&amp;gt;        80/TCP    3m14s
[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:monitoring)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;d. Prometheus &amp;amp; Grafana 대시보드 접속&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;1237&quot; data-origin-height=&quot;664&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/clxxls/btryCQdoerM/rbhpT9AxRlpDhLAGbQwJB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/clxxls/btryCQdoerM/rbhpT9AxRlpDhLAGbQwJB1/img.png&quot; data-alt=&quot;1) Prometheus Dashboard&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/clxxls/btryCQdoerM/rbhpT9AxRlpDhLAGbQwJB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fclxxls%2FbtryCQdoerM%2FrbhpT9AxRlpDhLAGbQwJB1%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;1237&quot; height=&quot;664&quot; data-origin-width=&quot;1237&quot; data-origin-height=&quot;664&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;1) Prometheus Dashboard&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1237&quot; data-origin-height=&quot;662&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cdIKtE/btryy0Oj3G5/fTx40D0Bl3prnHP5RRAka1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cdIKtE/btryy0Oj3G5/fTx40D0Bl3prnHP5RRAka1/img.png&quot; data-alt=&quot;2) Grafana Dashboard&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cdIKtE/btryy0Oj3G5/fTx40D0Bl3prnHP5RRAka1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcdIKtE%2Fbtryy0Oj3G5%2FfTx40D0Bl3prnHP5RRAka1%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;1237&quot; height=&quot;662&quot; data-origin-width=&quot;1237&quot; data-origin-height=&quot;662&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;2) Grafana Dashboard&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Grafana는 default ID : admin, PW : prom-operator로 로그인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;2. kuberhealthy 설치&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;a. namespace 생성&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1649256236544&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:monitoring)]# kubectl create ns kuberhealthy
namespace/kuberhealthy created
[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:monitoring)]# kubectl config set-context --current --namespace=kuberhealthy
Context &quot;iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io&quot; modified.
[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;b. kuberhealthy 설치&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1649256396951&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# helm repo add kuberhealthy https://comcast.github.io/kuberhealthy/kuberhealthy/helm-repos
&quot;kuberhealthy&quot; already exists with the same configuration, skipping
[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the &quot;nfs-subdir-external-provisioner&quot; chart repository
...Successfully got an update from the &quot;kuberhealthy&quot; chart repository
...Successfully got an update from the &quot;prometheus-community&quot; chart repository
Update Complete. 뉸appy Helming!
[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# helm install kuberhealthy kuberhealthy/kuberhealthy --set prometheus.enabled=true,prometheus.enableAlerting=true,prometheus.serviceMonitor.enabled=true
W0405 06:58:25.676172   10155 warnings.go:70] policy/v1beta1 PodDisruptionBudget is deprecated in v1.21+, unavailable in v1.25+; use policy/v1 PodDisruptionBudget
W0405 06:58:26.133098   10155 warnings.go:70] policy/v1beta1 PodDisruptionBudget is deprecated in v1.21+, unavailable in v1.25+; use policy/v1 PodDisruptionBudget
NAME: kuberhealthy
LAST DEPLOYED: Tue Apr  5 06:58:25 2022
NAMESPACE: kuberhealthy
STATUS: deployed
REVISION: 1
TEST SUITE: None
[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;c. 설치 확인&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1649256521400&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# kubectl get svc
NAME             TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
deployment-svc   ClusterIP   10.100.178.80   &amp;lt;none&amp;gt;        80/TCP    31s
kuberhealthy     ClusterIP   10.100.143.56   &amp;lt;none&amp;gt;        80/TCP    97s
[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# kubectl get pods
NAME                             READY   STATUS      RESTARTS   AGE
daemonset-1649141932             0/1     Completed   0          97s
deployment-1649141933            0/1     Completed   0          96s
dns-status-internal-1649141933   0/1     Completed   0          96s
kuberhealthy-7977cc6fcf-cbq4g    1/1     Running     0          2m8s
kuberhealthy-7977cc6fcf-m7zcl    1/1     Running     0          2m8s
[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;khchecks와 관련된 포드는 Completed상태여야 한다. &lt;/span&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;kuberhealthy 네임스페이스에는 기본적으로 3개의 khchecks가 설치되어 있어야 한다. khcheck는 테스트를 실행하기 위해 클러스터에서 Kuberhealthy가 생성한 사용자 지정 리소스이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1649256620079&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# kubectl get khchecks
NAME                  AGE
daemonset             107s
deployment            107s
dns-status-internal   107s
[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]#&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: 'Noto Serif KR'; color: #000000;&quot;&gt;daemonset : 클러스터의 모든 노드가 작동하는지 확인하기 위해 daemonset을 배포.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;deployment : deployment를 생성한 다음 rolling update를 트리거. service를 통해 deployment에 연결할 수 있는지 테스트한 후 테스트 pod를 complete 처리. 문제가 발생하면 failure 처리.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;dns-status-internal : Internal Cluter DNS가 정상 동작하는지 확인.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;3. kuberhealthy Prometheus 연동&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;a. servicemonitor CRD 확인&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1649295260254&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# kubectl get servicemonitors -A
NAMESPACE      NAME                                                 AGE
kuberhealthy   kuberhealthy                                         2m45s
monitoring     prometheus-grafana                                   3h35m
monitoring     prometheus-kube-prometheus-alertmanager              3h35m
monitoring     prometheus-kube-prometheus-apiserver                 3h35m
monitoring     prometheus-kube-prometheus-coredns                   3h35m
monitoring     prometheus-kube-prometheus-kube-controller-manager   3h35m
monitoring     prometheus-kube-prometheus-kube-etcd                 3h35m
monitoring     prometheus-kube-prometheus-kube-proxy                3h35m
monitoring     prometheus-kube-prometheus-kube-scheduler            3h35m
monitoring     prometheus-kube-prometheus-kubelet                   3h35m
monitoring     prometheus-kube-prometheus-operator                  3h35m
monitoring     prometheus-kube-prometheus-prometheus                3h35m
monitoring     prometheus-kube-state-metrics                        3h35m
monitoring     prometheus-prometheus-node-exporter                  3h35m
[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;위와 같이 Prometheus Operation이 Metric을 수집하기 위한 서비스 대상을 정의하는 servicemonitor CRD에 매핑된 정보를 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;kuberhealthy namespace의 kuberhealthy는 Prometheus 오퍼레이션과 연계하여 메트릭을 수집할 수 있도록 servicemonitor를 기본 지원한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1649295681195&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# kubectl get Prometheus -A
NAMESPACE    NAME                                    VERSION   REPLICAS   AGE
monitoring   prometheus-kube-prometheus-prometheus   v2.34.0   1          3h36m
[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# kubectl get Prometheus prometheus-kube-prometheus-prometheus -n monitoring -o yaml
apiVersion: monitoring.coreos.com/v1
kind: Prometheus
metadata:
  annotations:
    meta.helm.sh/release-name: prometheus
    meta.helm.sh/release-namespace: monitoring
  creationTimestamp: &quot;2022-04-05T03:25:23Z&quot;
...
spec:
...
  serviceAccountName: prometheus-kube-prometheus-prometheus
  serviceMonitorNamespaceSelector: {}
  serviceMonitorSelector:
    matchLabels:
      release: prometheus
  shards: 1
  version: v2.34.0
[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;prometheus에서는 servicemonitor 대상을 아래와 같이 두가지 규칙을 가지고 대상은 선정하게 된다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;serviceMonitorNamespaceSelector : Prometheus pod는 기본 serviceMonitorNamespaceSelector: {}로 구성되며, 이는 Prometheus Pod가 기동된 monitoring namespace만 모니터링 대상으로 메트릭을 수집한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;serviceMonitorSelector : matchLabels이 release: prometheus인 Pod를 대상으로 메트릭을 수집한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;위 기준을 충족하는지 확인하기 위해 kuberhealthy의 구성 정보를 확인해 보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1649297587245&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# kubectl get servicemonitors kuberhealthy -o yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: kuberhealthy
  namespace: kuberhealthy
  annotations:
    meta.helm.sh/release-name: kuberhealthy
    meta.helm.sh/release-namespace: kuberhealthy
  creationTimestamp: &quot;2022-04-05T06:58:26Z&quot;
  generation: 1
  labels:
    app: kuberhealthy
    app.kubernetes.io/managed-by: Helm
    prometheus: prometheus
    release: prometheus-operator
...
spec:
  endpoints:
  - bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
    interval: 15s
    port: http
  jobLabel: component
  namespaceSelector:
    matchNames:
    - kuberhealthy
  selector:
    matchLabels:
      app: kuberhealthy
[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;위와 같이 kuberhealthy는 kuberhealthy namespace 내 release: prometheus-operator label을 갖고 있다. 따라서 현재 상태로는 prometheus에서는 메트릭 수집 대상에서 제외된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;b. kuberhealthy 구성 변경&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1649282911481&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# kubectl get servicemonitors kuberhealthy -o yaml &amp;gt; kuberhealty_servicemonitor.yaml
[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# vi kuberhealty_servicemonitor.yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: kuberhealthy
  namespace: monitoring
  annotations:
    meta.helm.sh/release-name: kuberhealthy
    meta.helm.sh/release-namespace: kuberhealthy
  creationTimestamp: &quot;2022-04-05T06:58:26Z&quot;
  generation: 1
  labels:
    app: kuberhealthy
    app.kubernetes.io/managed-by: Helm
    prometheus: prometheus
    release: prometheus
...
spec:
  endpoints:
  - bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
    interval: 15s
    port: http
  jobLabel: component
  namespaceSelector:
    matchNames:
    - kuberhealthy
  selector:
    matchLabels:
      app: kuberhealthy
[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# kubectl apply -f kuberhealty_servicemonitor.yaml
servicemonitor.monitoring.coreos.com/kuberhealthy created
[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# kubectl get servicemonitors -A
NAMESPACE      NAME                                                 AGE
kuberhealthy   kuberhealthy                                         5m49s
monitoring     kuberhealthy                                         9s
monitoring     prometheus-grafana                                   3h38m
monitoring     prometheus-kube-prometheus-alertmanager              3h38m
monitoring     prometheus-kube-prometheus-apiserver                 3h38m
monitoring     prometheus-kube-prometheus-coredns                   3h38m
monitoring     prometheus-kube-prometheus-kube-controller-manager   3h38m
monitoring     prometheus-kube-prometheus-kube-etcd                 3h38m
monitoring     prometheus-kube-prometheus-kube-proxy                3h38m
monitoring     prometheus-kube-prometheus-kube-scheduler            3h38m
monitoring     prometheus-kube-prometheus-kubelet                   3h38m
monitoring     prometheus-kube-prometheus-operator                  3h38m
monitoring     prometheus-kube-prometheus-prometheus                3h38m
monitoring     prometheus-kube-state-metrics                        3h38m
monitoring     prometheus-prometheus-node-exporter                  3h38m
[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# kubectl delete servicemonitor kuberhealthy -n kuberhealthy
servicemonitor.monitoring.coreos.com &quot;kuberhealthy&quot; deleted
[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 kuberhealthy의 yaml 파일을 내려 받아 모니터링 대상으로 지정하기 위해 namespace를 monitoring으로&amp;nbsp; lebel을 release: prometheus로 수정한 후 반영한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;또한 불필요한 기존 kuberhealthy namespace 내에 생성한 kuberhealthy는 삭제한다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;4. 대시보드 구성&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;a. Prometheus Service Discovery 확인&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;1224&quot; data-origin-height=&quot;638&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bojpR3/btryEtPuhmO/GG9u9AcK4g5PaPRwV2wuLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bojpR3/btryEtPuhmO/GG9u9AcK4g5PaPRwV2wuLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bojpR3/btryEtPuhmO/GG9u9AcK4g5PaPRwV2wuLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbojpR3%2FbtryEtPuhmO%2FGG9u9AcK4g5PaPRwV2wuLK%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;1224&quot; height=&quot;638&quot; data-origin-width=&quot;1224&quot; data-origin-height=&quot;638&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Service Discovery는 현재 메트릭을 수집하고 있는 대상 서비스 목록이다. 위와 같이 serviceMonitor/monitoring/kuberhealthy/0 (2/2 active targets)이 탐색되는 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;b. Graph 확인&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;1236&quot; data-origin-height=&quot;662&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAcdXa/btryCOGUxti/ai7ra2s4oSgNZmV5VKhSVK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAcdXa/btryCOGUxti/ai7ra2s4oSgNZmV5VKhSVK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAcdXa/btryCOGUxti/ai7ra2s4oSgNZmV5VKhSVK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAcdXa%2FbtryCOGUxti%2Fai7ra2s4oSgNZmV5VKhSVK%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;1236&quot; height=&quot;662&quot; data-origin-width=&quot;1236&quot; data-origin-height=&quot;662&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Prometheus Graph 탭에서 graph를 생성하기 위한 데이터가 조회되는지 확인한다. 위와 같이 kuberhealthy_check &amp;gt; Excute 클릭 시 아래와 같이 결과가 표출될 경우 정상적으로 kuberhealthy와 prometheus의 연동은 완료된다.&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;1235&quot; data-origin-height=&quot;664&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SIGrw/btryEXv3Rod/mbLKkvgaLgLI9KBj2GUick/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SIGrw/btryEXv3Rod/mbLKkvgaLgLI9KBj2GUick/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SIGrw/btryEXv3Rod/mbLKkvgaLgLI9KBj2GUick/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSIGrw%2FbtryEXv3Rod%2FmbLKkvgaLgLI9KBj2GUick%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;1235&quot; height=&quot;664&quot; data-origin-width=&quot;1235&quot; data-origin-height=&quot;664&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;c. Grafana 대시보드 확인&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Grafana 대시보드를 자동 생성하기 위해 아래 json 파일을 다운로드 받는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #006dd7;&quot;&gt;&lt;a style=&quot;color: #006dd7;&quot; href=&quot;https://github.com/Comcast/kuberhealthy/blob/master/deploy/grafana/dashboard.json&quot;&gt;https://github.com/Comcast/kuberhealthy/blob/master/deploy/grafana/dashboard.json&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bf2kBj/btryCOmzynL/TlJB1tty5wB3WIYkTkY7ik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bf2kBj/btryCOmzynL/TlJB1tty5wB3WIYkTkY7ik/img.png&quot; data-origin-width=&quot;1237&quot; data-origin-height=&quot;637&quot; data-is-animation=&quot;false&quot; style=&quot;width: 50.387%; margin-right: 10px;&quot; data-widthpercent=&quot;50.98&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bf2kBj/btryCOmzynL/TlJB1tty5wB3WIYkTkY7ik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbf2kBj%2FbtryCOmzynL%2FTlJB1tty5wB3WIYkTkY7ik%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;1237&quot; height=&quot;637&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tluNK/btryI4IYEFR/WMk5nmdFMP90nbKKqV9e81/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tluNK/btryI4IYEFR/WMk5nmdFMP90nbKKqV9e81/img.png&quot; data-origin-width=&quot;1238&quot; data-origin-height=&quot;663&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;49.02&quot; style=&quot;width: 48.4502%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tluNK/btryI4IYEFR/WMk5nmdFMP90nbKKqV9e81/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtluNK%2FbtryI4IYEFR%2FWMk5nmdFMP90nbKKqV9e81%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;1238&quot; height=&quot;663&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;+(Creat) &amp;gt; Import 버튼 클릭 후 json 파일을 import 한다.&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;1239&quot; data-origin-height=&quot;839&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/O5SMp/btryEyRRi9T/N8RHvgPnYHvUqvqeGIQHe0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/O5SMp/btryEyRRi9T/N8RHvgPnYHvUqvqeGIQHe0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/O5SMp/btryEyRRi9T/N8RHvgPnYHvUqvqeGIQHe0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FO5SMp%2FbtryEyRRi9T%2FN8RHvgPnYHvUqvqeGIQHe0%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;1239&quot; height=&quot;839&quot; data-origin-width=&quot;1239&quot; data-origin-height=&quot;839&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;위와 같이 정상적으로 생성이 완료되면 kuberhealthy 메트릭에 대한 Grafana 대시보드를 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>③ 클라우드/ⓚ Kubernetes</category>
      <category>grafana</category>
      <category>kuberhealthy</category>
      <category>prometheus</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/772</guid>
      <comments>https://waspro.tistory.com/772#entry772comment</comments>
      <pubDate>Thu, 7 Apr 2022 02:04:45 +0900</pubDate>
    </item>
    <item>
      <title>StorageClass를 활용한 Dynamic Provisioning</title>
      <link>https://waspro.tistory.com/771</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;개요&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Kubernetes가 대세로 자리 잡은 이후 다양한 3rd Party 솔루션과의 연동이슈는 끊임없이 발생하고 있다. Container Orchestrator(CO)와의 단일화된 인터페이스를 제공하기 위해 CRI(Container Runtime Interface), CNI(Container Network Interface), CSI(Container Storage Interface)가 등장하고 발전해 오고 있다.&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;1303&quot; data-origin-height=&quot;604&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rUulQ/btrye4J4Dsf/74DL85m8V8j6pRpMV6QSu0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rUulQ/btrye4J4Dsf/74DL85m8V8j6pRpMV6QSu0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rUulQ/btrye4J4Dsf/74DL85m8V8j6pRpMV6QSu0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrUulQ%2Fbtrye4J4Dsf%2F74DL85m8V8j6pRpMV6QSu0%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;600&quot; height=&quot;278&quot; data-origin-width=&quot;1303&quot; data-origin-height=&quot;604&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; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;CSI의 등장이전에는 특정 볼륨에 대한 연결 방식을 Kubernetes가 제공하는 방식으로 구현되었다. 하지만 새로운 볼륨 플러그인이 지속적으로 추가되고, 특히 특정 볼륨을 제공하는 솔루션의 버전 변화에 일일이 대응하기에는 어려움이 있었다. 또한 볼륨 스토리지와의 연결을 위해 SDK 코드가 Kubernetes 바이너리에 추가되어야 했으며, 이는 안정성 및 보안 문제를 야기했으며, 테스트와 관리의 어려움이 발생하였다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;CSI는 Kubernetes와 같은 컨테이너 오케스트레이션 시스템의 컨테이너화된 워크로드에 임의의 블록 및 파일 스토리지 시스템을 노출하기 위한 표준으로 개발되었다. Container Storage Interface의 채택으로 Kubernetes 볼륨 계층은 무한한 확장이 가능한 상태로 발전하였다. 이제 볼륨 확장을 위해서는 Kubernetes와의 직접적인 연계 없이 구현할 수 있으며, 이미 정의된 인터페이스를 통해 통신하며, 이는 CSI 등장 이전에 문제점으로 제시되었던, 관리의 어려움, 안정성의 문제, 보안 문제를 모두 해소할 수 있게 되었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이번 포스팅에서 살펴볼 StorageClass는 CSI의 구현체를 가리키는 오브젝트이다. StorageClass를 통해 대표적으로 많이 사용되는 볼륨인 AWS EBS와 NFS 연동 과정에 대해 살펴보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Dynamic Provisioning&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;CSI는 Container Orchestrator와 다양한 Storage Provider간의 인터페이스를 담당하며, PersistentVolume을 자동으로 생성할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;CSI는 아래와 같은 다양한 스토리지 Provider를 지원한다. Kubernetes 내에 이미 Provisioner를 제공하거나, 필요 시 deployment, statefulset 등으로 배포하여 볼륨과 연동한다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;[주요 스토리지의 Privisioner]&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: 'Noto Serif KR'; color: #000000;&quot;&gt;AWS EBS - provisioner: kubernetes.io/aws-ebs&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;GCE PD - provisioner: kubernetes.io/gce-pd&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Glusterfs - provisioner: kubernetes.io/glusterfs&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;NFS - provisioner: example.com/external-nfs&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;OpenStack Cinder - provisioner: kubernetes.io/cinder&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;vSphere - provisioner: csi.vsphere.vmware.com / provisioner: kubernetes.io/vsphere-volume&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Ceph RBD - provisioner: kubernetes.io/rbd&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Quobyte - provisioner: kubernetes.io/quobyte&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Azure Disk - provisioner: kubernetes.io/azure-disk&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Azure File - provisioner: kubernetes.io/azure-file&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Portworx Volume - provisioner: kubernetes.io/portworx-volume&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;ScaleIO - provisioner: kubernetes.io/scaleio&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;StorageOS - provisioner: kubernetes.io/storageos&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Local&amp;nbsp;-&amp;nbsp;provisioner:&amp;nbsp;kubernetes.io/no-provisioner&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;해당 Provisioner를 사용하여 개별 정의된 Parameter를 통해 세부 연결 방식을 정의한다. &lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;세부적인 환경 구성은 아래를 참고한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;a href=&quot;https://kubernetes.io/ko/docs/concepts/storage/storage-classes/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://kubernetes.io/ko/docs/concepts/storage/storage-classes/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1649011334421&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;스토리지 클래스&quot; data-og-description=&quot;이 문서는 쿠버네티스의 스토리지클래스의 개념을 설명한다. 볼륨과 퍼시스턴트 볼륨에 익숙해지는 것을 권장한다. 소개 스토리지클래스는 관리자가 제공하는 스토리지의 &amp;quot;classes&amp;quot;를 설명할 수 &quot; data-og-host=&quot;kubernetes.io&quot; data-og-source-url=&quot;https://kubernetes.io/ko/docs/concepts/storage/storage-classes/&quot; data-og-url=&quot;https://kubernetes.io/ko/docs/concepts/storage/storage-classes/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bzQNJO/hyNUvcW0UG/Fy1CSCZHd07CQzKkP4kkG0/img.png?width=1727&amp;amp;height=373&amp;amp;face=0_0_1727_373,https://scrap.kakaocdn.net/dn/UZkRk/hyNUxof6RA/W2lzdr1g4wiH4oBaQOM8z1/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512&quot;&gt;&lt;a href=&quot;https://kubernetes.io/ko/docs/concepts/storage/storage-classes/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://kubernetes.io/ko/docs/concepts/storage/storage-classes/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bzQNJO/hyNUvcW0UG/Fy1CSCZHd07CQzKkP4kkG0/img.png?width=1727&amp;amp;height=373&amp;amp;face=0_0_1727_373,https://scrap.kakaocdn.net/dn/UZkRk/hyNUxof6RA/W2lzdr1g4wiH4oBaQOM8z1/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512');&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;스토리지 클래스&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;이 문서는 쿠버네티스의 스토리지클래스의 개념을 설명한다. 볼륨과 퍼시스턴트 볼륨에 익숙해지는 것을 권장한다. 소개 스토리지클래스는 관리자가 제공하는 스토리지의 &quot;classes&quot;를 설명할 수&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;kubernetes.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;[동작 순서]&lt;/span&gt;&lt;/h3&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1. PersistentVolumeClaim은 StorageClass를 사용하여 동적 프로비저닝 트리거 &lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2. Dynamic Provisioning은 PersistentVolumeClaim에 의해 트리거&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;3. 볼륨 프로비저닝이 호출되면 Parameter type의 value와 CreateVolume 호출을 volume provisioner로 전달&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;4. volume provisioner는 새 볼륨을 생성한 후 생성한 볼륨을 나타내는 PersistentVolume 개체를 자동으로 생성&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;5. Kubernetes는 새로운 PersistentVolume 개체를 PersistentVolumeClaim에 바인딩&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;6. Pod는 PersistentVolumeClaim을 추가하여 volume 사용&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;AWS EBS&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;먼저 살펴볼 볼륨은 aws ebs이다. ebs는 aws managed service로 대표적인 블록 스토리지이다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;[storageclass-aws.yaml]&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;html xml&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: aws-sc-ebs
provisioner: kubernetes.io/aws-ebs
parameters:
  type: gp2
  fsType: ext4&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;aws-ebs의 StorageClass를 추가할 경우 다음과 같은 parameter를 함께 구성한다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;type :&amp;nbsp;io1,&amp;nbsp;gp2,&amp;nbsp;sc1,&amp;nbsp;st1, default(gp2)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;iopsPerGB :&amp;nbsp;io1&amp;nbsp;볼륨 전용. 1초당 GiB에 대한 I/O 작업 수. AWS 볼륨 플러그인은 요청된 볼륨 크기에 곱셈하여 볼륨의 IOPS를 계산하고 이를 20,000 IOPS로 제한한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;fsType : fsType은 쿠버네티스에서 지원된다. default(&quot;ext4&quot;)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;encrypted : EBS 볼륨의 암호화 여부&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;kmsKeyId : 선택 사항. 볼륨을 암호화할 때 사용할 키의 전체 Amazon 리소스 이름.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;provisioner를 통해 aws-ebs와 연결하는 storageclass임을 알 수 있다. parameters.type이 gp2이며, aws ebs volume type은 다음을 참조한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #006dd7;&quot;&gt;&lt;a style=&quot;color: #006dd7;&quot; href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-volume-types.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-volume-types.html&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1648907677010&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;Amazon EBS volume types - Amazon Elastic Compute Cloud&quot; data-og-description=&quot;Amazon EBS volume types Amazon EBS provides the following volume types, which differ in performance characteristics and price, so that you can tailor your storage performance and cost to the needs of your applications. The volumes types fall into these cat&quot; data-og-host=&quot;docs.aws.amazon.com&quot; data-og-source-url=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-volume-types.html&quot; data-og-url=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-volume-types.html&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/c8TOdc/hyNTlWqM5o/OnGk51RI8MkK7VjLMnTQ41/img.png?width=1122&amp;amp;height=537&amp;amp;face=0_0_1122_537,https://scrap.kakaocdn.net/dn/bZM5sZ/hyNUBwyTPd/nGLGTc2h6JsKNvkdiValH0/img.png?width=1275&amp;amp;height=460&amp;amp;face=0_0_1275_460,https://scrap.kakaocdn.net/dn/2I8zo/hyNUw9R1AW/OQwFZ0pq4cBKG5h3dJsKu1/img.png?width=947&amp;amp;height=445&amp;amp;face=0_0_947_445&quot;&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-volume-types.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-volume-types.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/c8TOdc/hyNTlWqM5o/OnGk51RI8MkK7VjLMnTQ41/img.png?width=1122&amp;amp;height=537&amp;amp;face=0_0_1122_537,https://scrap.kakaocdn.net/dn/bZM5sZ/hyNUBwyTPd/nGLGTc2h6JsKNvkdiValH0/img.png?width=1275&amp;amp;height=460&amp;amp;face=0_0_1275_460,https://scrap.kakaocdn.net/dn/2I8zo/hyNUw9R1AW/OQwFZ0pq4cBKG5h3dJsKu1/img.png?width=947&amp;amp;height=445&amp;amp;face=0_0_947_445');&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;Amazon EBS volume types - Amazon Elastic Compute Cloud&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Amazon EBS volume types Amazon EBS provides the following volume types, which differ in performance characteristics and price, so that you can tailor your storage performance and cost to the needs of your applications. The volumes types fall into these cat&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.aws.amazon.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;pre id=&quot;code_1648910393326&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 aws-sc (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# k apply -f storageclass-aws.yaml 
storageclass.storage.k8s.io/aws-sc-ebs created
[root@ip-192-168-78-195 aws-sc (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# k get sc
NAME            PROVISIONER             RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
aws-sc-ebs      kubernetes.io/aws-ebs   Delete          Immediate              false                  8s
gp2 (default)   kubernetes.io/aws-ebs   Delete          WaitForFirstConsumer   false                  34h
[root@ip-192-168-78-195 aws-sc (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 storageclass 추가 후 aws-sc-ebs를 조회한 결과이다. 이미 eks 설치 시점에 gp2라는 aws-ebs provisioner가 default로 추가되어 있는 것을 확인할 수 있지만, 본 포스팅에서는 aws-sc-ebs를 활용하도록 한다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;[persistentvolumeclaim-aws.yaml]&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1648893426833&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: aws-sc-ebs-pvc
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
  storageClassName: aws-sc-ebs&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;aws-sc-ebs-pvc PersistentVolumeClaim은 aws-sc-ebs storageclass를 사용하여 Dynamic Provisioning을 위한 트리거를 동작한다. storage 크기는 5Gi로 생성한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1648910262846&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 aws-sc (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# k apply -f persistentvolumeclaim-aws.yaml 
persistentvolumeclaim/aws-sc-ebs-pvc created
[root@ip-192-168-78-195 aws-sc (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# k get pvc
NAME             STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
aws-sc-ebs-pvc   Bound    pvc-f64695d3-a6a2-4857-80ac-2bb9d344a55d   5Gi        RWO            aws-sc-ebs     7s
[root@ip-192-168-78-195 aws-sc (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 persistentvolumeclaim 추가 후 aws-sc-ebs-pvc를 조회한 결과이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;마지막으로 Dynamic Provisioning으로 생성된 PersistentVolume을 확인해 보자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1648913888717&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 aws-sc (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# k get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                    STORAGECLASS   REASON   AGE
pvc-f64695d3-a6a2-4857-80ac-2bb9d344a55d   5Gi        RWO            Delete           Bound    default/aws-sc-ebs-pvc   aws-sc-ebs              10s
[root@ip-192-168-78-195 aws-sc (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 자동으로 생성된 PV를 확인할 수 있다. 이제 Application을 생성하여 볼륨이 정상적으로 생성되고 공유되는지 확인해 보자.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;[namespace.yaml]&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1648914410389&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: v1
kind: Namespace
metadata:
    name: app-test&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;[nginx-service.yaml]&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1648914418900&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: v1
kind: Service
metadata:
  name: my-nginx
  labels:
    run: my-nginx
spec:
  ports:
  - nodePort: 30380
    port: 80
    protocol: TCP
  type: NodePort
  selector:
    run: my-nginx&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;[nginx-deployment.yaml]&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1648914428429&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx
        ports:
        - containerPort: 80
        volumeMounts:
        - name: aws-sc-ebs-pvc-nginx
          mountPath: /data
      volumes:
      - name: aws-sc-ebs-pvc-nginx
        persistentVolumeClaim:
          claimName: aws-sc-ebs-pvc&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 생성한 yaml 파일 반영 후 pv 볼륨을 확인해 보자. 자세한 Deployment 내 Volume 구성 방법은 아래 URL을 참고한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #006dd7;&quot;&gt;&lt;a style=&quot;color: #006dd7;&quot; href=&quot;https://waspro.tistory.com/580?category=831751&quot;&gt;https://waspro.tistory.com/580?category=831751&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1649011516659&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;Kubernetes Persistent Volume 생성하기 - PV, PVC&quot; data-og-description=&quot;서론 본 포스팅에서는 Kubernetes에서 Persistent Volume &amp;amp; Persistent Volume Claim을 사용하는 방법에 대해 알아보도록 하겠습니다. 먼저 Persistent Volume(이하 PV)에 대해 알아보겠습니다. PV는 Kubernetes와..&quot; data-og-host=&quot;waspro.tistory.com&quot; data-og-source-url=&quot;https://waspro.tistory.com/580?category=831751&quot; data-og-url=&quot;https://waspro.tistory.com/580&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/pSjLO/hyNUBjWNDy/OOEk120nnks24whWSUpPYK/img.png?width=656&amp;amp;height=713&amp;amp;face=0_0_656_713,https://scrap.kakaocdn.net/dn/b0vdQm/hyNUz7tGK9/GbklUcKFopIlCYbOm4NIU1/img.png?width=656&amp;amp;height=713&amp;amp;face=0_0_656_713,https://scrap.kakaocdn.net/dn/n1HYq/hyNUqvWhmo/hH30SYyYTJiIZtk9KpS4o1/img.png?width=656&amp;amp;height=713&amp;amp;face=0_0_656_713&quot;&gt;&lt;a href=&quot;https://waspro.tistory.com/580?category=831751&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://waspro.tistory.com/580?category=831751&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/pSjLO/hyNUBjWNDy/OOEk120nnks24whWSUpPYK/img.png?width=656&amp;amp;height=713&amp;amp;face=0_0_656_713,https://scrap.kakaocdn.net/dn/b0vdQm/hyNUz7tGK9/GbklUcKFopIlCYbOm4NIU1/img.png?width=656&amp;amp;height=713&amp;amp;face=0_0_656_713,https://scrap.kakaocdn.net/dn/n1HYq/hyNUqvWhmo/hH30SYyYTJiIZtk9KpS4o1/img.png?width=656&amp;amp;height=713&amp;amp;face=0_0_656_713');&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;Kubernetes Persistent Volume 생성하기 - PV, PVC&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;서론 본 포스팅에서는 Kubernetes에서 Persistent Volume &amp;amp; Persistent Volume Claim을 사용하는 방법에 대해 알아보도록 하겠습니다. 먼저 Persistent Volume(이하 PV)에 대해 알아보겠습니다. PV는 Kubernetes와..&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;waspro.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;pre id=&quot;code_1648914839206&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 aws-sc (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# k get pods
NAME                       READY   STATUS    RESTARTS   AGE
my-nginx-87f6dbffb-p2647   1/1     Running   0          106s
my-nginx-87f6dbffb-twvkf   1/1     Running   0          106s
[root@ip-192-168-78-195 aws-sc (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# k exec -it my-nginx-87f6dbffb-p2647 /bin/bash
root@my-nginx-87f6dbffb-p2647:/# cd /data
root@my-nginx-87f6dbffb-p2647:/data# ls
lost+found
root@my-nginx-87f6dbffb-p2647:/data# touch test
root@my-nginx-87f6dbffb-p2647:/data# ls -la
total 20
drwxr-xr-x 3 root root  4096 Apr  2 15:52 .
drwxr-xr-x 1 root root    51 Apr  2 15:45 ..
drwx------ 2 root root 16384 Apr  2 15:45 lost+found
-rw-r--r-- 1 root root     0 Apr  2 15:52 test
root@my-nginx-87f6dbffb-p2647:/data#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;deployment replicas에 의해 my-nginx pod는 2개 배포되어 있다. 그 중 7로 끝나는 pod에 접속하여 pvc에 정의한 mount point인 /data 하위에 test라는 파일을 생성한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1648915104229&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# k exec -it my-nginx-87f6dbffb-twvkf /bin/bash
root@my-nginx-87f6dbffb-twvkf:/# cd /data
root@my-nginx-87f6dbffb-twvkf:/data# ls -la
total 20
drwxr-xr-x 3 root root  4096 Apr  2 15:52 .
drwxr-xr-x 1 root root    51 Apr  2 15:45 ..
drwx------ 2 root root 16384 Apr  2 15:45 lost+found
-rw-r--r-- 1 root root     0 Apr  2 15:52 test
root@my-nginx-87f6dbffb-twvkf:/data#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;다음으로 f로 끝나는 pod에 접속하여 방금 생성한 test 파일이 생성되었는지 여부를 확인한다. 위와 같이 정상적으로 파일 볼륨 생성 및 파일공유가 이뤄지는 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;NFS&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;다음으로 NFS(Network File System)을 동적 프로비저닝하는 방법에 대해 알아보자. Kubernetes는 NFS Provisioning을 처리하기 위해 외부 프로비저닝 도구를 구성해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;nfs-subdir-external-provisioner는 기 구성되어 있는 NFS 서버를 PersistentVolumeClaim, StorageClass를 사용하여 PersistentVolume을 자동으로 프로비저닝하기 위한 provisioner이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;본 테스트를 위해 NFS 서버는 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7; font-family: 'Noto Serif KR';&quot;&gt;&lt;a style=&quot;color: #006dd7;&quot; href=&quot;https://waspro.tistory.com/586&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://waspro.tistory.com/586&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1648947362040&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;5분만에 NFS 구축하기 (CentOS7)&quot; data-og-description=&quot;개요 본 포스팅에서는 CentOS7에 NFS를 구축하는 방법에 대해 살펴보겠습니다. NFS는 Network File System으로 파일 시스템을 외부에서 접근하여 사용하고 공유할 수 있도록 하는 볼륨의 형태입니다. 본 &quot; data-og-host=&quot;waspro.tistory.com&quot; data-og-source-url=&quot;https://waspro.tistory.com/586&quot; data-og-url=&quot;https://waspro.tistory.com/586&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/xYVID/hyNUqIJBM7/KtDCUS40KIZAKvTfi1uixK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/AmCKJ/hyNUpC3cW8/ZGKvBb2NTcOqvI3Yui8agK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800&quot;&gt;&lt;a href=&quot;https://waspro.tistory.com/586&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://waspro.tistory.com/586&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/xYVID/hyNUqIJBM7/KtDCUS40KIZAKvTfi1uixK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/AmCKJ/hyNUpC3cW8/ZGKvBb2NTcOqvI3Yui8agK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800');&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;5분만에 NFS 구축하기 (CentOS7)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;개요 본 포스팅에서는 CentOS7에 NFS를 구축하는 방법에 대해 살펴보겠습니다. NFS는 Network File System으로 파일 시스템을 외부에서 접근하여 사용하고 공유할 수 있도록 하는 볼륨의 형태입니다. 본&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;waspro.tistory.com&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;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;를 참고하여 구성하며, NFS-UTIL과 PORTMAP을 구성하였다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;1. github repository clone&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #006dd7;&quot;&gt;&lt;a style=&quot;color: #006dd7;&quot; href=&quot;https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1648942735150&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 - kubernetes-sigs/nfs-subdir-external-provisioner: Dynamic sub-dir volume provisioner on a remote NFS server.&quot; data-og-description=&quot;Dynamic sub-dir volume provisioner on a remote NFS server. - GitHub - kubernetes-sigs/nfs-subdir-external-provisioner: Dynamic sub-dir volume provisioner on a remote NFS server.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner&quot; data-og-url=&quot;https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cephnH/hyNUqhCVC8/nApsZp78YYROKAc5OKHoDK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cephnH/hyNUqhCVC8/nApsZp78YYROKAc5OKHoDK/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;GitHub - kubernetes-sigs/nfs-subdir-external-provisioner: Dynamic sub-dir volume provisioner on a remote NFS server.&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Dynamic sub-dir volume provisioner on a remote NFS server. - GitHub - kubernetes-sigs/nfs-subdir-external-provisioner: Dynamic sub-dir volume provisioner on a remote NFS server.&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;pre id=&quot;code_1648942871056&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 nfs (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# git clone https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner
Cloning into 'nfs-subdir-external-provisioner'...
remote: Enumerating objects: 7221, done.
remote: Counting objects: 100% (6023/6023), done.
remote: Compressing objects: 100% (3024/3024), done.
remote: Total 7221 (delta 3193), reused 5570 (delta 2790), pack-reused 1198
Receiving objects: 100% (7221/7221), 7.42 MiB | 10.60 MiB/s, done.
Resolving deltas: 100% (3838/3838), done.
[root@ip-192-168-78-195 nfs (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2. Setup Authorization&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1648942981415&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 nfs (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# cd nfs-subdir-external-provisioner/
[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# NS=$(kubectl config get-contexts|grep -e &quot;^\*&quot; |awk '{print $5}')
[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# NAMESPACE=${NS:-default}
[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# echo $NS
default
[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# echo $NAMESPACE
default
[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# sed -i'' &quot;s/namespace:.*/namespace: $NAMESPACE/g&quot; ./deploy/rbac.yaml ./deploy/deployment.yaml
[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# kubectl create -f deploy/rbac.yaml
serviceaccount/nfs-client-provisioner created
clusterrole.rbac.authorization.k8s.io/nfs-client-provisioner-runner created
clusterrolebinding.rbac.authorization.k8s.io/run-nfs-client-provisioner created
role.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created
rolebinding.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created
[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;3. Configure nfs-subdir-external-provisioner&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1648943372720&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-client-provisioner
  labels:
    app: nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: default
spec:
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: nfs-client-provisioner
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccountName: nfs-client-provisioner
      containers:
        - name: nfs-client-provisioner
          image: k8s.gcr.io/sig-storage/nfs-subdir-external-provisioner:v4.0.2
          volumeMounts:
            - name: nfs-client-root
              mountPath: /root/nfs
          env:
            - name: PROVISIONER_NAME
              value: k8s-sigs.io/nfs-subdir-external-provisioner
            - name: NFS_SERVER
              value: 192.168.78.195
            - name: NFS_PATH
              value: /root/nfs
      volumes:
        - name: nfs-client-root
          nfs:
            server: 192.168.78.195
            path: /root/nfs&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;nfs-client-provisioner 컨테이너를 배포하여 재정의된 nfs-subdir-external-privisioner를 구성한다. 유의할 점은 env tag 내 정보들을 환경에 맞게 수정 반영한다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;PROVISIONER_NAME : PROVISIONER 이름을 지정하며, StorageClass에서 provisioner로 동일한 이름을 지정&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;NFS_SERVER : NFS SERVER IP&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;NFS_PATH : NFS Server Root Path&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1648947613479&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# k apply -f deploy/deployment.yaml 
deployment.apps/nfs-client-provisioner created
[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# k get pods 
NAME                                      READY   STATUS    RESTARTS   AGE
nfs-client-provisioner-86cd8c4768-nkxvb   1/1     Running   0          11s
[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;4. StorageClass&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1648943578215&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-client
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner # or choose another name, must match deployment's env PROVISIONER_NAME'
parameters:
  pathPattern: &quot;${.PVC.namespace}/${.PVC.annotations.nfs.io/storage-path}&quot; # waits for nfs.io/storage-path annotation, if not specified will accept as empty string.
  onDelete: delete&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Storage Class의 provisioner를 nfs-client-provisioner의 PROVISIONER_NAME과 매핑한다. &lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;nfs-client의 StorageClass를 추가할 경우 다음과 같은 parameter를 함께 구성한다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;onDelete : delete일 경우 디렉터리 삭제. retain일 경우 디렉토리 유지.&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;archiveOnDelete : false일 경우 디렉토리를 삭제. onDelete존재하는 경우 archiveOnDelete 무시.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;pathPattern : label, annotation, name, namepsace와 같은 PVC 메타데이터를 통해 디렉토리 경로를 생성하기 위한 템플릿을 지정. 사용방법 - ${.PVC.&amp;lt;metadata&amp;gt;}&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1648947649328&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# k apply -f deploy/class.yaml 
storageclass.storage.k8s.io/nfs-client created
[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# k get sc
NAME            PROVISIONER                                   RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
gp2 (default)   kubernetes.io/aws-ebs                         Delete          WaitForFirstConsumer   false                  47h
nfs-client      k8s-sigs.io/nfs-subdir-external-provisioner   Delete          Immediate              false                  8s
[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;위와 같이 storageclass를 추가하고 상태를 확인한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;5. PersistentVolumeClaim&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1648943711960&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: test-claim
spec:
  storageClassName: nfs-client
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Mi&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;다음으로 Dynamic Provisioning을 트리거 하기 위한 PersistentVolumeClaim을 생성한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1648947688824&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# k apply -f deploy/test-claim.yaml 
persistentvolumeclaim/test-claim created
[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# k get pvc
NAME         STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
test-claim   Bound    pvc-d5483f0f-eda5-4d7e-bdda-d8febaa39696   1Mi        RWX            nfs-client     9s
[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# k get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                STORAGECLASS   REASON   AGE
pvc-d5483f0f-eda5-4d7e-bdda-d8febaa39696   1Mi        RWX            Delete           Bound    default/test-claim   nfs-client              2m
[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 pvc 생성 시 자동으로 pv를 생성하고 pvc가 Bound 되는 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;6. Pod deploy&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이제 Pod를 생성하고, 볼륨의 동작에 대해 확인해 보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1648943746808&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;kind: Pod
apiVersion: v1
metadata:
  name: test-pod
spec:
  containers:
  - name: test-pod
    image: busybox:stable
    command:
      - &quot;/bin/sh&quot;
    args:
      - &quot;-c&quot;
      - &quot;touch /mnt/SUCCESS &amp;amp;&amp;amp; exit 0 || exit 1&quot;
    volumeMounts:
      - name: nfs-pvc
        mountPath: &quot;/mnt&quot;
  restartPolicy: &quot;Never&quot;
  volumes:
    - name: nfs-pvc
      persistentVolumeClaim:
        claimName: test-claim&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 test-pod는 pod 내 mount path인 &quot;/mnt&quot; 하위에 SUCCESS라는 파일을 생성하고 Pod를 완료한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1648947891893&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# k apply -f deploy/test-pod.yaml 
pod/test-pod created
[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# k get pods
NAME                                      READY   STATUS              RESTARTS   AGE
nfs-client-provisioner-86cd8c4768-nkxvb   1/1     Running             0          115s
test-pod                                  0/1     ContainerCreating   0          5s
[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# k get pods
NAME                                      READY   STATUS      RESTARTS   AGE
nfs-client-provisioner-86cd8c4768-nkxvb   1/1     Running     0          119s
test-pod                                  0/1     Completed   0          9s
[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Pod의 상태가 Complete으로 변경되면 아래와 같이 NFS Server를 확인해 보자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1648947969104&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 default (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# ls -la
total 0
drwxrwxrwx 2 root      root      21 Apr  3 00:03 .
drwxr-xr-x 3 root      root      21 Apr  1 16:48 ..
-rw-r--r-- 1 nfsnobody nfsnobody  0 Apr  3 00:00 SUCCESS
[root@ip-192-168-78-195 default (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;SUCCESS 파일이 생성된 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;7. deployment deploy&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;다음으로 nginx pod를 생성하여 volume을 사용하는 deployment를 배포해 보자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1648945156744&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx
        ports:
        - containerPort: 80
        volumeMounts:
          - name: nfs-pvc
            mountPath: &quot;/mnt&quot;
      volumes:
        - name: nfs-pvc
          persistentVolumeClaim:
            claimName: test-claim&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;해당 deployment는 replicas를 2로 구성하고 각 pod간 데이터가 공유되는지, NFS에는 저장이 되는지 확인해 보자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1648945233794&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# k get pods 
NAME                                      READY   STATUS    RESTARTS   AGE
my-nginx-95b4dc9cc-hkshf                  1/1     Running   0          37s
my-nginx-95b4dc9cc-jt5ml                  1/1     Running   0          37s
nfs-client-provisioner-86cd8c4768-nkxvb   1/1     Running   0          21m
[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# k exec -it my-nginx-95b4dc9cc-hkshf /bin/bash
root@my-nginx-95b4dc9cc-hkshf:/# cd /mnt
root@my-nginx-95b4dc9cc-hkshf:/mnt# touch nfstest
root@my-nginx-95b4dc9cc-hkshf:/mnt# ls -la
total 0
drwxrwxrwx 2 root   root    36 Apr  3 00:20 .
drwxr-xr-x 1 root   root    39 Apr  3 00:18 ..
-rw-r--r-- 1 nobody nogroup  0 Apr  3 00:00 SUCCESS
-rw-r--r-- 1 nobody nogroup  0 Apr  3 00:20 nfstest
root@my-nginx-95b4dc9cc-hkshf:/mnt#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 f로 끝나는 nginx pod에 접속하여 &quot;/mnt&quot; 하위에 nfstest 파일을 생성한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1648945248232&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# k exec -it my-nginx-95b4dc9cc-jt5ml /bin/bash
root@my-nginx-95b4dc9cc-jt5ml:/# cd /mnt
root@my-nginx-95b4dc9cc-jt5ml:/mnt# ls -la
total 0
drwxrwxrwx 2 root   root    36 Apr  3 00:20 .
drwxr-xr-x 1 root   root    39 Apr  3 00:18 ..
-rw-r--r-- 1 nobody nogroup  0 Apr  3 00:00 SUCCESS
-rw-r--r-- 1 nobody nogroup  0 Apr  3 00:20 nfstest
root@my-nginx-95b4dc9cc-jt5ml:/mnt#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;다음으로 l로 끝나는 Pod에 연결하여 &quot;/mnt&quot; 경로 하위를 확인한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;마지막으로 NFS Server를 직접 확인한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1648945269512&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 default (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# ls -la
total 0
drwxrwxrwx 2 root      root      36 Apr  3 00:20 .
drwxr-xr-x 3 root      root      21 Apr  1 16:48 ..
-rw-r--r-- 1 nfsnobody nfsnobody  0 Apr  3 00:20 nfstest
-rw-r--r-- 1 nfsnobody nfsnobody  0 Apr  3 00:00 SUCCESS
[root@ip-192-168-78-195 default (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 NFS 서버에 정상적으로 추가된 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;결론&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;서두에 이야기한 것처럼 Kubernetes와 연결하여 사용되는 수많은 볼륨들은 이제 CSI 표준에 따라 구성되며, 손쉬운 확장과 통합을 지원하게 되었다. 그 확장성의 측면에서 Kubernetes의 부담을 줄이고, 볼륨을 제공하는 Provider 측면에서 인터페이스를 개발하여 제공하게 됨으로써 유연함을 확보할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;여전히 Kubernetes에서 직접 연결하는 방식에 대해 제공되고 있지만, Provider를 제공하는 Volume에 대해서는 CSI Provisioner에 의해 구현된 StorageClass, PersistentVolume에 의해 자동으로 프로비저닝을 관리하는 것이 보다 효과적일 것이다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>③ 클라우드/ⓚ Kubernetes</category>
      <category>Container Storage Interface</category>
      <category>CSI</category>
      <category>Kubernete NFS</category>
      <category>Kubernetes EBS</category>
      <category>Kubernetes Volume</category>
      <category>persistentvolume</category>
      <category>persistentvolumeclaim</category>
      <category>storageclass</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/771</guid>
      <comments>https://waspro.tistory.com/771#entry771comment</comments>
      <pubDate>Sat, 2 Apr 2022 18:16:45 +0900</pubDate>
    </item>
    <item>
      <title>Kubernetes (.bashrc - kubectl 자동완성, kube-ps1)</title>
      <link>https://waspro.tistory.com/769</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;$HOME/.bashrc&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;#&amp;nbsp;.bashrc &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;#&amp;nbsp;User&amp;nbsp;specific&amp;nbsp;aliases&amp;nbsp;and&amp;nbsp;functions &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;alias&amp;nbsp;rm='rm&amp;nbsp;-i' &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;alias&amp;nbsp;cp='cp&amp;nbsp;-i' &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;alias&amp;nbsp;mv='mv&amp;nbsp;-i' &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;#&amp;nbsp;Source&amp;nbsp;global&amp;nbsp;definitions &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;if&amp;nbsp;[&amp;nbsp;-f&amp;nbsp;/etc/bashrc&amp;nbsp;];&amp;nbsp;then &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.&amp;nbsp;/etc/bashrc &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;fi &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;i&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;source&amp;nbsp;~/eks/kube-ps1/kube-ps1.sh &lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;i&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;PS1='[\u@\h&amp;nbsp;\W&amp;nbsp;$(kube_ps1)]\$&amp;nbsp;' &lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;i&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;KUBE_PS1_SYMBOL_ENABLE=false &lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;i&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;KUBE_PS1_SYMBOL_COLOR=null &lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;i&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;KUBE_PS1_CTX_COLOR=null &lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;i&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;KUBE_PS1_NS_COLOR=null &lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;i&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;source&amp;nbsp;/usr/share/bash-completion/bash_completion &lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;i&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;source&amp;nbsp;&amp;lt;(kubectl&amp;nbsp;completion&amp;nbsp;bash) &lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;i&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;alias&amp;nbsp;k=kubectl &lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;i&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;complete&amp;nbsp;-F&amp;nbsp;__start_kubectl&amp;nbsp;k&lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1) kube-ps1&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;source&amp;nbsp;~/eks/kube-ps1/kube-ps1.sh&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;PS1='[\u@\h&amp;nbsp;\W&amp;nbsp;$(kube_ps1)]\$&amp;nbsp;'&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;KUBE_PS1_SYMBOL_ENABLE=false&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;KUBE_PS1_SYMBOL_COLOR=null&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;KUBE_PS1_CTX_COLOR=null&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;KUBE_PS1_NS_COLOR=null&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2) bash_completion&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;source /usr/share/bash-completion/bash_completion&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;source&amp;nbsp;&amp;lt;(kubectl&amp;nbsp;completion&amp;nbsp;bash)&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;alias&amp;nbsp;k=kubectl&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;complete&amp;nbsp;-F&amp;nbsp;__start_kubectl&amp;nbsp;k&lt;/span&gt;&lt;/p&gt;</description>
      <category>⑨ IT Wordbook</category>
      <category>bash_completion</category>
      <category>kube-ps1</category>
      <category>kubectl 자동완성</category>
      <category>kubernetes 자동완성</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/769</guid>
      <comments>https://waspro.tistory.com/769#entry769comment</comments>
      <pubDate>Mon, 21 Mar 2022 02:09:28 +0900</pubDate>
    </item>
    <item>
      <title>Kubernetes 네트워크 ACL &amp;quot;NetworkPolicy&amp;quot;</title>
      <link>https://waspro.tistory.com/768</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;개요&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;기본적으로 Kubernetes는 클러스터 내에서 실행되는 Pod 간 트래픽을 제한하지 않는다. 이와 같은 특징은 때때로 보안과 성능 또는 장애와 연관이 되는 문제들이 발생할 수 있다.&amp;nbsp;NetworkPolicy는 Pod간 통신을 제어하는 오브젝트이다. 통신이 허용되는 네임스페이스를 지정하거나 더 구체적으로 각 정책을 적용할 수 있다. 즉 NetworkPolicy는 Pod 간 ACL을 수행하는 Kubernetes 오브젝트이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;NetworkPolicy는 실시간으로 적용되며, Pod 간에 연결이 열려 있는 경우 해당 연결을 방지하는 NetworkPolicy를 적용하면 연결이 즉시 종료된다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;제약조건&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;NetworkPolicy는 Inbound 트래픽과 Outbount 트래픽을 구분하여 정의할 수 있으며, 사용중인 CNI(Container Network Interface)에 따라 NetworkPolicy 오브젝트 지원 여부를 확인해야 한다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;Ingress/Egress NetworkPolicy 모두 지원 : Calico, Canal, Cilium&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Ingress NetworkPolicy만 지원 : Kube-router, WeaveNet&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;미지원 : Romana, Flannel, EKS(Amazon VPC CNI)/GKE(kubenet)/AKS(Azure CNI)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;많이 사용되는 CNI인 Flannel이나, EKS / GKE / AKS 등 Public Cloud Managed Service에서도 기본 NetworkPolicy가 활성화 되어 있지 않다는 점에 유의해야 한다. 이 경우 위와 같이 Ingress/Egress 모두를 지원하는 Calico, Canal, Cilium CNI를 구축함으로써 NetworkPolicy를 사용할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;본 포스팅에서는 Amazon EKS 환경에서 작성되고 있으며, Calico를 설치하여 NetworkPolicy 기능을 검증해 보자.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Calico 설치&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1) Calico Manifest 적용&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647646968453&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 app (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# kubectl apply -f https://raw.githubusercontent.com/aws/amazon-vpc-cni-k8s/master/config/master/calico-operator.yaml
customresourcedefinition.apiextensions.k8s.io/apiservers.operator.tigera.io created
customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/blockaffinities.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/clusterinformations.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/felixconfigurations.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/globalnetworkpolicies.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/globalnetworksets.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/hostendpoints.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/imagesets.operator.tigera.io created
customresourcedefinition.apiextensions.k8s.io/ipamblocks.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/ipamconfigs.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/ipamhandles.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/ippools.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/kubecontrollersconfigurations.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/networkpolicies.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/networksets.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/installations.operator.tigera.io created
customresourcedefinition.apiextensions.k8s.io/tigerastatuses.operator.tigera.io created
namespace/tigera-operator created
podsecuritypolicy.policy/tigera-operator created
clusterrolebinding.rbac.authorization.k8s.io/tigera-operator created
clusterrole.rbac.authorization.k8s.io/tigera-operator created
serviceaccount/tigera-operator created
deployment.apps/tigera-operator created
[root@ip-192-168-78-195 app (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# kubectl apply -f https://raw.githubusercontent.com/aws/amazon-vpc-cni-k8s/master/config/master/calico-crs.yaml
installation.operator.tigera.io/default created
[root@ip-192-168-78-195 app (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2) DaemonSet 확인&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647647015403&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 app (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# kubectl get ds -A
NAMESPACE       NAME          DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
calico-system   calico-node   2         2         2       2            2           kubernetes.io/os=linux   2m52s
kube-system     aws-node      2         2         2       2            2           &amp;lt;none&amp;gt;                   26h
kube-system     kube-proxy    2         2         2       2            2           &amp;lt;none&amp;gt;                   26h
[root@ip-192-168-78-195 app (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]#&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;NetworkPolicy 검증&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&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;1303&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9hul8/btrwptR7OPF/N4X84RB6g6kackszkmdPX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9hul8/btrwptR7OPF/N4X84RB6g6kackszkmdPX0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9hul8/btrwptR7OPF/N4X84RB6g6kackszkmdPX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9hul8%2FbtrwptR7OPF%2FN4X84RB6g6kackszkmdPX0%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;1303&quot; height=&quot;400&quot; data-origin-width=&quot;1303&quot; data-origin-height=&quot;400&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;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;default namespace - my-nginx service&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;network namespace - my-nginx-network service&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;policy namespace : my-nginx-policy service&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1) NetworkPolicy 적용 전&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647702919398&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# kubectl exec -it my-nginx-5b56ccd65f-nw4pp /bin/bash
root@my-nginx-5b56ccd65f-nw4pp:/# curl -v my-nginx-network.network.svc.cluster.local
*   Trying 10.100.114.127:80...
* Connected to my-nginx-network.network.svc.cluster.local (10.100.114.127) port 80 (#0)
&amp;gt; GET / HTTP/1.1
&amp;gt; Host: my-nginx-network.network.svc.cluster.local
&amp;gt; User-Agent: curl/7.74.0
&amp;gt; Accept: */*
&amp;gt; 
* Mark bundle as not supporting multiuse
&amp;lt; HTTP/1.1 200 OK
&amp;lt; Server: nginx/1.21.6
&amp;lt; Date: Sat, 19 Mar 2022 15:14:25 GMT
&amp;lt; Content-Type: text/html
&amp;lt; Content-Length: 615
&amp;lt; Last-Modified: Tue, 25 Jan 2022 15:03:52 GMT
&amp;lt; Connection: keep-alive
&amp;lt; ETag: &quot;61f01158-267&quot;
&amp;lt; Accept-Ranges: bytes
&amp;lt; 
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
&amp;lt;title&amp;gt;Welcome to nginx!&amp;lt;/title&amp;gt;
&amp;lt;style&amp;gt;
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
&amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;h1&amp;gt;Welcome to nginx!&amp;lt;/h1&amp;gt;
&amp;lt;p&amp;gt;If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;For online documentation and support please refer to
&amp;lt;a href=&quot;http://nginx.org/&quot;&amp;gt;nginx.org&amp;lt;/a&amp;gt;.&amp;lt;br/&amp;gt;
Commercial support is available at
&amp;lt;a href=&quot;http://nginx.com/&quot;&amp;gt;nginx.com&amp;lt;/a&amp;gt;.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;Thank you for using nginx.&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
* Connection #0 to host my-nginx-network.network.svc.cluster.local left intact
root@my-nginx-5b56ccd65f-nw4pp:/#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 default namespace 내에서 network namespace의 my-nginx-network pod를 호출해 보면 정상적으로 호출되는 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;NetworkPolicy를 적용하기 전 주요 yaml을 구성하는 항목에 대해 알아보자.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 147px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 15.8914%; text-align: center; height: 21px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;상위 필드&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 14.031%; text-align: center; height: 21px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;하위 필드&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 70.0775%; text-align: center; height: 21px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;설명&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 29.9224%; text-align: center; height: 21px;&quot; colspan=&quot;2&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;podSelector&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 70.0775%; text-align: left; height: 21px;&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;NetworkPolicy에는 정책이 적용되는 Pod 그룹을 선택하는 podSelector가 포함된다. podSelector가 비어있을 경우 네임스페이스의 모든 파드를 선택한다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 29.9224%; text-align: center; height: 21px;&quot; colspan=&quot;2&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;policyTypes&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 70.0775%; text-align: left; height: 21px;&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;NetworkPolicy에는 Ingress, Egress 또는 두 가지 모두를 포함할 수 있는 policyTypes 목록이 포함된다. policyTypes 필드는 podSelector에 의해 선택된 Pod에 대한 Ingress 트래픽 정책, 선택한 Pod에 대한 Egress 트래픽 정책 또는 두 가지 모두에 지정된 정책의 적용 여부를 나타낸다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 15.8914%; text-align: center; height: 42px;&quot; rowspan=&quot;2&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;ingress&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 14.031%; text-align: center; height: 21px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;from&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 70.0775%; text-align: left; height: 21px;&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;NetworkPolicy에는 whitelist ingress 규칙 목록이 포함될 수 있다. 각 규칙은 from과 ports 부분과 모두 일치하는 트래픽을 허용한다.&lt;br /&gt;&amp;gt; ipBlock은 CIDR 대역을 지정하며, 특정 IP대역에서만 트래픽이 유입되도록 제한&lt;br /&gt;&amp;gt; podSelector와 namespaceSelector는 특정 Label을 포함하는 Object에서 요청되는 트래픽만 유입되도록 제한. podSelector는 해당 label을 포함하는 pod의 요청만 허용하며, namespaceSelector는 해당 namespace에서 유입되는 요청만 허용&lt;br /&gt;이를 기반으로 개발, 검증, 운영 환경을 구분하여 설계하거나, 배포방식의 다변화를 가져갈 수 있다.&lt;br /&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 14.031%; text-align: center; height: 21px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;ports&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 70.0775%; text-align: left; height: 21px;&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;NetworkPolicy에는 whitelist&amp;nbsp;ingress 규칙 목록이 포함될 수 있다. 각 규칙은 from과 ports 부분과 모두 일치하는 트래픽을 허용한다.&lt;br /&gt;&amp;gt; protocol : 허용되는 프로토콜의 종류&lt;br /&gt;&amp;gt; port : 유입이 허용되는 포트&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 15.8914%; text-align: center; height: 42px;&quot; rowspan=&quot;2&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;egress&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 14.031%; text-align: center; height: 21px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;to&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 70.0775%; text-align: left; height: 21px;&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;NetworkPolicy에는 &lt;span style=&quot;background-color: #f9f9f9;&quot;&gt;whitelist&lt;/span&gt;&lt;span style=&quot;background-color: #f9f9f9;&quot;&gt;&amp;nbsp;&lt;/span&gt;egress 규칙이 포함될 수 있다. 각 규칙은 to 와 ports 부분과 모두 일치하는 트래픽을 허용한다.&lt;br /&gt;&amp;gt; ipBlock은 CIDR 대역을 지정하며, 특정 IP 대역으로만 트래픽을 반환하도록 제한&lt;br /&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 14.031%; text-align: center; height: 21px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;ports&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 70.0775%; text-align: left; height: 21px;&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;NetworkPolicy에는 &lt;span style=&quot;background-color: #f9f9f9;&quot;&gt;whitelist&lt;/span&gt;&lt;span style=&quot;background-color: #f9f9f9;&quot;&gt;&amp;nbsp;&lt;/span&gt;egress 규칙이 포함될 수 있다. 각 규칙은 to 와 ports 부분과 모두 일치하는 트래픽을 허용한다.&lt;br /&gt;&amp;gt; protocol : 반환되는 프로토콜의 종류&lt;br /&gt;&amp;gt; port : 반환이 허용되는 포트&lt;br /&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2) 어플리케이션에 대한 모든 트래픽 거부&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;1303&quot; data-origin-height=&quot;573&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blBtnZ/btrwsIt2pDx/uH0HiJ30mFstT7BwSXtXLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blBtnZ/btrwsIt2pDx/uH0HiJ30mFstT7BwSXtXLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blBtnZ/btrwsIt2pDx/uH0HiJ30mFstT7BwSXtXLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblBtnZ%2FbtrwsIt2pDx%2FuH0HiJ30mFstT7BwSXtXLK%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;1303&quot; height=&quot;573&quot; data-origin-width=&quot;1303&quot; data-origin-height=&quot;573&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1647680762506&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: web-deny-all
  namespace: network
spec:
  podSelector:
    matchLabels:
      run: my-nginx-network
  ingress: []&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위 NetworkPolicy는 network namespace 내 run: my-nginx-network Label을 갖는 Pod로의 Ingress를 차단한다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;Case 1. 다른 Namespace에서 my-nginx-network pod 호출 시 &amp;gt; 차단&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Case 2. 동일 Namespace 내 다른 서비스에서 my-nginx-network pod 호출 시 &amp;gt; 차단&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Case 3. network Namespace 내 my-nginx-network pod에서 외부 Namespace로의 Egress 호출 시 &amp;gt; 허용&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1647704786562&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;root@my-nginx-5b56ccd65f-nw4pp:/# curl -v my-nginx-network.network.svc.cluster.local
*   Trying 10.100.114.127:80...
* connect to 10.100.114.127 port 80 failed: Connection timed out
* Failed to connect to my-nginx-network.network.svc.cluster.local port 80: Connection timed out
* Closing connection 0
curl: (28) Failed to connect to my-nginx-network.network.svc.cluster.local port 80: Connection timed out
root@my-nginx-5b56ccd65f-nw4pp:/#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 기존 정상적으로 호출되었던 network namespace 내 my-nginx-network pod에 대한 호출이 Connection timed out이 발생하는 것을 알 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647754648622&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;root@my-nginx-network-5588897f5-hr9q2:/# curl -v my-nginx-policy.policy.svc.cluster.local              
*   Trying 10.100.179.121:80...
* Connected to my-nginx-policy.policy.svc.cluster.local (10.100.179.121) port 80 (#0)
&amp;gt; GET / HTTP/1.1
&amp;gt; Host: my-nginx-policy.policy.svc.cluster.local
&amp;gt; User-Agent: curl/7.74.0
&amp;gt; Accept: */*
&amp;gt; 
* Mark bundle as not supporting multiuse
&amp;lt; HTTP/1.1 200 OK
&amp;lt; Server: nginx/1.21.6
&amp;lt; Date: Sun, 20 Mar 2022 05:34:10 GMT
&amp;lt; Content-Type: text/html
&amp;lt; Content-Length: 615
&amp;lt; Last-Modified: Tue, 25 Jan 2022 15:03:52 GMT
&amp;lt; Connection: keep-alive
&amp;lt; ETag: &quot;61f01158-267&quot;
&amp;lt; Accept-Ranges: bytes
&amp;lt; 
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
&amp;lt;title&amp;gt;Welcome to nginx!&amp;lt;/title&amp;gt;
&amp;lt;style&amp;gt;
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
&amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;h1&amp;gt;Welcome to nginx!&amp;lt;/h1&amp;gt;
&amp;lt;p&amp;gt;If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;For online documentation and support please refer to
&amp;lt;a href=&quot;http://nginx.org/&quot;&amp;gt;nginx.org&amp;lt;/a&amp;gt;.&amp;lt;br/&amp;gt;
Commercial support is available at
&amp;lt;a href=&quot;http://nginx.com/&quot;&amp;gt;nginx.com&amp;lt;/a&amp;gt;.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;Thank you for using nginx.&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
* Connection #0 to host my-nginx-policy.policy.svc.cluster.local left intact
root@my-nginx-network-5588897f5-hr9q2:/#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;반대로 network namespace 내 my-nginx-network pod에서 외부 namespace로의 egress 호출은 정상적으로 연결되는 것을 알 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;근본적으로 ACL을 구성하기 위해 먼저 이 정책을 사용하여 트래픽을 차단하고 white list 정책으로 오픈해 나가는 것이 바람직하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;3) 특정 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;1302&quot; data-origin-height=&quot;799&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b9SNgc/btrwwsdaSBq/SYHKZJleeQO5J4ngT4rJbK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b9SNgc/btrwwsdaSBq/SYHKZJleeQO5J4ngT4rJbK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b9SNgc/btrwwsdaSBq/SYHKZJleeQO5J4ngT4rJbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb9SNgc%2FbtrwwsdaSBq%2FSYHKZJleeQO5J4ngT4rJbK%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;1302&quot; height=&quot;799&quot; data-origin-width=&quot;1302&quot; data-origin-height=&quot;799&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1647757605362&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: api-allow
  namespace: network
spec:
  podSelector:
    matchLabels:
      run: my-nginx-network
  ingress:
  - from:
      - podSelector:
          matchLabels:
            run: my-nginx-network2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;어플리케이션에 대한 모든 트래픽 거부에서 살펴본 내용과의 차잊머은 podSelector에서 선택된 Pod 대상으로 ingress whitelist 방식으로 연결을 허용하는 대상을 정의했다는 점이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위 NetworkPolicy는 run: my-nginx-netowrk2 label을 갖는 service의 요청을 허용한다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;Case 1. 다른 Namespace에서 my-nginx-network pod 호출 시 &amp;gt; 차단&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Case 2.&amp;nbsp;동일 Namespace 내 다른 서비스에서 my-nginx-network pod 호출 시 &amp;gt; 차단&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Case 3. 동일 Namespace 내 run: my-nginx-network2 label을 갖는 서비스에서 호출 시 &amp;gt; 허용&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Case 4. network Namespace 내 my-nginx-network pod에서 외부 Namespace로의 Egress 호출 시 &amp;gt; 허용&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1647758187417&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;root@my-nginx-network2-774bb6b4ff-d8mj8:/# curl -v my-nginx-network.network.svc.cluster.local
*   Trying 10.100.114.127:80...
* Connected to my-nginx-network.network.svc.cluster.local (10.100.114.127) port 80 (#0)
&amp;gt; GET / HTTP/1.1
&amp;gt; Host: my-nginx-network.network.svc.cluster.local
&amp;gt; User-Agent: curl/7.74.0
&amp;gt; Accept: */*
&amp;gt; 
* Mark bundle as not supporting multiuse
&amp;lt; HTTP/1.1 200 OK
&amp;lt; Server: nginx/1.21.6
&amp;lt; Date: Sun, 20 Mar 2022 06:19:18 GMT
&amp;lt; Content-Type: text/html
&amp;lt; Content-Length: 615
&amp;lt; Last-Modified: Tue, 25 Jan 2022 15:03:52 GMT
&amp;lt; Connection: keep-alive
&amp;lt; ETag: &quot;61f01158-267&quot;
&amp;lt; Accept-Ranges: bytes
&amp;lt; 
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
&amp;lt;title&amp;gt;Welcome to nginx!&amp;lt;/title&amp;gt;
&amp;lt;style&amp;gt;
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
&amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;h1&amp;gt;Welcome to nginx!&amp;lt;/h1&amp;gt;
&amp;lt;p&amp;gt;If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;For online documentation and support please refer to
&amp;lt;a href=&quot;http://nginx.org/&quot;&amp;gt;nginx.org&amp;lt;/a&amp;gt;.&amp;lt;br/&amp;gt;
Commercial support is available at
&amp;lt;a href=&quot;http://nginx.com/&quot;&amp;gt;nginx.com&amp;lt;/a&amp;gt;.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;Thank you for using nginx.&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
* Connection #0 to host my-nginx-network.network.svc.cluster.local left intact
root@my-nginx-network2-774bb6b4ff-d8mj8:/#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 label이 run: my-nginx-netowrk2인 network namespace 내 my-nginx-network2 service로 부터의 요청이 허용된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;4) 특정 Namespace로 부터의 요청 허용&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;1303&quot; data-origin-height=&quot;573&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nUHNC/btrwree8QKf/d0u1YKkaitiZOr1DI7uKYk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nUHNC/btrwree8QKf/d0u1YKkaitiZOr1DI7uKYk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nUHNC/btrwree8QKf/d0u1YKkaitiZOr1DI7uKYk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnUHNC%2Fbtrwree8QKf%2Fd0u1YKkaitiZOr1DI7uKYk%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;1303&quot; height=&quot;573&quot; data-origin-width=&quot;1303&quot; data-origin-height=&quot;573&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1647759052178&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 NetworkPolicy (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# kubectl label namespace/default purpose=default
namespace/default labeled
[root@ip-192-168-78-195 NetworkPolicy (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# kubectl label namespace/network purpose=network
namespace/network labeled
[root@ip-192-168-78-195 NetworkPolicy (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# kubectl label namespace/policy purpose=policy
namespace/policy labeled
[root@ip-192-168-78-195 NetworkPolicy (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 각 namespace에 label을 설정한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647759139178&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: web-allow-prod
  namespace: network
spec:
  podSelector:
    matchLabels:
      run: my-nginx-network
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          purpose: policy&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위 NetworkPolicy는 network namesapce 내 run: my-nginx-network label을 갖는 pod를 대상으로 purpose: policy label을 갖는 namespace의 요청을 허용한다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;Case 1. 다른 Namespace에서 my-nginx-network pod 호출 시 &amp;gt; 차단&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Case 2.&amp;nbsp;동일 Namespace 내 다른 서비스에서 my-nginx-network pod 호출 시 &amp;gt; 차단&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Case 3. namespace label이 purpose: policy인 namespace에서 호출 시 &amp;gt; 허용&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Case 4. network Namespace 내 my-nginx-network pod에서 외부 Namespace로의 Egress 호출 시 &amp;gt; 허용&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1647761294489&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt; 타 네임스페이스
root@my-nginx-network2-774bb6b4ff-89wqs:/# curl -v my-nginx-network.network.svc.cluster.local
*   Trying 10.100.114.127:80...
* connect to 10.100.114.127 port 80 failed: Connection timed out
* Failed to connect to my-nginx-network.network.svc.cluster.local port 80: Connection timed out
* Closing connection 0
curl: (28) Failed to connect to my-nginx-network.network.svc.cluster.local port 80: Connection timed out
root@my-nginx-network2-774bb6b4ff-89wqs:/#

&amp;gt; 동일 네임스페이스 내 타 서비스
root@my-nginx-network2-774bb6b4ff-d8mj8:/# curl -v my-nginx-network.network.svc.cluster.local
*   Trying 10.100.114.127:80...
* connect to 10.100.114.127 port 80 failed: Connection timed out
* Failed to connect to my-nginx-network.network.svc.cluster.local port 80: Connection timed out
* Closing connection 0
curl: (28) Failed to connect to my-nginx-network.network.svc.cluster.local port 80: Connection timed out
root@my-nginx-network2-774bb6b4ff-d8mj8:/#

&amp;gt; purpose: policy label을 갖는 policy namespace 내 호출 시
root@my-nginx-policy-786684cb7f-gj5gj:/# curl -v my-nginx-network.network.svc.cluster.local
*   Trying 10.100.114.127:80...
* Connected to my-nginx-network.network.svc.cluster.local (10.100.114.127) port 80 (#0)
&amp;gt; GET / HTTP/1.1
&amp;gt; Host: my-nginx-network.network.svc.cluster.local
&amp;gt; User-Agent: curl/7.74.0
&amp;gt; Accept: */*
&amp;gt; 
* Mark bundle as not supporting multiuse
&amp;lt; HTTP/1.1 200 OK
&amp;lt; Server: nginx/1.21.6
&amp;lt; Date: Sun, 20 Mar 2022 06:53:39 GMT
&amp;lt; Content-Type: text/html
&amp;lt; Content-Length: 615
&amp;lt; Last-Modified: Tue, 25 Jan 2022 15:03:52 GMT
&amp;lt; Connection: keep-alive
&amp;lt; ETag: &quot;61f01158-267&quot;
&amp;lt; Accept-Ranges: bytes
&amp;lt; 
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
&amp;lt;title&amp;gt;Welcome to nginx!&amp;lt;/title&amp;gt;
&amp;lt;style&amp;gt;
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
&amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;h1&amp;gt;Welcome to nginx!&amp;lt;/h1&amp;gt;
&amp;lt;p&amp;gt;If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;For online documentation and support please refer to
&amp;lt;a href=&quot;http://nginx.org/&quot;&amp;gt;nginx.org&amp;lt;/a&amp;gt;.&amp;lt;br/&amp;gt;
Commercial support is available at
&amp;lt;a href=&quot;http://nginx.com/&quot;&amp;gt;nginx.com&amp;lt;/a&amp;gt;.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;Thank you for using nginx.&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
* Connection #0 to host my-nginx-network.network.svc.cluster.local left intact
root@my-nginx-policy-786684cb7f-gj5gj:/#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;아래와 같이 policy namespace 내 호출이 정상적으로 요청되는 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;결론&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;NetworkPolicy의 동작방식을 정의해 보자면 다음과 같다. 먼저 &lt;/span&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;단일 Namespace 내 NetworkPolicy에는 다음과 같은 규칙으로 동작한다.&lt;/span&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: 'Noto Serif KR'; color: #000000;&quot;&gt;NetworkPolicy에 의해 지정된 Pod는 트래픽이 제한된다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Pod에 NetworkPolicy가 정의되지 않은 경우 모든 Namespace의 모든 Pod이 해당 Pod에 연결할 수 있다. 즉, 기본적으로는 특정 Pod에 대해 정의된 네트워크 정책이 없으며 암묵적으로 &quot;allow all&quot;을 의미한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Pod A에 대한 트래픽이 제한되고 Pod B가 Pod A에 연결해야 하는 경우 Pod A를 NetworkPolicy에 의해 지정하고, ingress rule에 의해 Pod B를 선택하여 허용한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;다음으로 멀티 Namespace 내 NetworkPolicy는 다음과 같은 규칙으로 동작한다.&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;NetworkPolicy가 적용된 네임스페이스에 있는 Pod 연결에 대해서만 규칙을 적용할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;ingress 규칙의 podSelector는 NetworkPolicy가 배포된 네임스페이스 내의 pod만 선택할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Pod A가 다른 네임스페이스의 Pod B에 연결해야 하는 경우 Pod B에 Pod A를 지정하는 namespaceSelector가 추가되어야 한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;지금까지 살펴본&amp;nbsp;&lt;/span&gt;NetworkPolicy는 Firewall과 같은 네트워크 트래픽을 캡처하고, 관리하는 장비는 아니다. 단순하게 네트워크의 흐름을 제어하는 논리적인 도구라고 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;따라서 Kubernetes 내 Pod 간 통신을 제어하는데 NetworkPolicy에 전적으로 의존해서는 안된다. Pod 간 통신을 제어하기 위해 NetworkPolicy는 물론 TLS(Istio mTLS) 방식의 트래픽 인증을 적용하거나, ingress로의 유입을 제어하는 별도의 도구를 도입하는 것을 함께 고려해야 할 것이다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>③ 클라우드/ⓚ Kubernetes</category>
      <category>kubernetes acl</category>
      <category>kubernetes namespace 간 차단</category>
      <category>networkpolicy</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/768</guid>
      <comments>https://waspro.tistory.com/768#entry768comment</comments>
      <pubDate>Sat, 19 Mar 2022 08:51:32 +0900</pubDate>
    </item>
    <item>
      <title>Kubernetes 보안 강화를 위한 오픈소스 소프트웨어 활용</title>
      <link>https://waspro.tistory.com/767</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;개요&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Kubernetes는 강력한 확장성과 안정성을 제공하는 Container Management Platform으로 이미 대표적인 클라우드 컴포넌트로 자리를 확고히 하고 있다. 많은 기업에서 Kubernetes를 활용하고 있지만, 정작 Container에 대한 보안이나, Kubernetes에 대한 보안 정책은 자리잡지 못하고 있으며, 이로 인해 보안 침해 사고가 터져 나오고 있는 실정이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;보안문제는 개인이나, 중-소 규모의 기업에서 온전히 대응하는 것은 조직을 구축하는 것부터 체계를 수립하는 것까지 쉽지 않은 일이라는 점때문에 여전히 대응 방안을 수립하기 어려운 실정이다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이에 여러 오픈소스 소프트웨어들의 조합으로 최소한의 문제들을 진단하고 사전에 검증할 수 있는 방법을 살펴보도록 하자. &lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;지금부터 프로젝트에 적용 가능한 보안관련 오픈소스 소프트웨어들을 살펴보고, 활용 방안에 대해 알아보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;kube-hunter (클러스터 보안취약점)&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;kube-hunter는 Security Vulnerabilitiy를 발견하여 Kubernetes 클러스터의 보안을 강화하는데 도움을 주는 오픈소스 도구이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;a. 설치&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;python 패키지 매니저를 이용하여 손쉽게 설치가 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647269133911&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-84-159 kube-hunter]# yum install python-pip
Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
Package python2-pip-20.2.2-1.amzn2.0.3.noarch already installed and latest version
Nothing to do
[root@ip-192-168-84-159 kube-hunter]# python3 -m ensurepip
Looking in links: /tmp/tmp_nw7te6m
Requirement already satisfied: setuptools in /usr/lib/python3.7/site-packages (49.1.3)
Requirement already satisfied: pip in /usr/lib/python3.7/site-packages (20.2.2)
[root@ip-192-168-84-159 kube-hunter]# pip3 --version
pip 20.2.2 from /usr/lib/python3.7/site-packages/pip (python 3.7)
[root@ip-192-168-84-159 kube-hunter]# pip3 install --user kube-hunter
WARNING: Running pip install with root privileges is generally not a good idea. Try `pip3 install --user` instead.
Collecting kube-hunter
  Downloading kube_hunter-0.6.5-py3-none-any.whl (72 kB)
Collecting ruamel.yaml
  Downloading ruamel.yaml-0.17.21-py3-none-any.whl (109 kB)
Collecting future
  Downloading future-0.18.2.tar.gz (829 kB)
Collecting PrettyTable
  Downloading prettytable-3.2.0-py3-none-any.whl (26 kB)
Collecting urllib3&amp;gt;=1.24.3
  Downloading urllib3-1.26.8-py2.py3-none-any.whl (138 kB)
Collecting pluggy
  Downloading pluggy-1.0.0-py2.py3-none-any.whl (13 kB)
Collecting kubernetes==12.0.1
  Downloading kubernetes-12.0.1-py2.py3-none-any.whl (1.7 MB)
Collecting netaddr
  Downloading netaddr-0.8.0-py2.py3-none-any.whl (1.9 MB)
Collecting dataclasses
  Downloading dataclasses-0.6-py3-none-any.whl (14 kB)
Collecting requests
  Downloading requests-2.27.1-py2.py3-none-any.whl (63 kB)
Collecting netifaces
Collecting packaging
  Downloading packaging-21.3-py3-none-any.whl (40 kB)
Collecting scapy&amp;gt;=2.4.3
  Downloading scapy-2.4.5.tar.gz (1.1 MB)
Collecting ruamel.yaml.clib&amp;gt;=0.2.6; platform_python_implementation == &quot;CPython&quot; and python_version &amp;lt; &quot;3.11&quot;
  Downloading ruamel.yaml.clib-0.2.6-cp37-cp37m-manylinux1_x86_64.whl (546 kB)
Collecting importlib-metadata; python_version &amp;lt; &quot;3.8&quot;
  Downloading importlib_metadata-4.11.2-py3-none-any.whl (17 kB)
Collecting wcwidth
  Downloading wcwidth-0.2.5-py2.py3-none-any.whl (30 kB)
Collecting pyyaml&amp;gt;=3.12
  Downloading PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl (596 kB)
Collecting six&amp;gt;=1.9.0
  Downloading six-1.16.0-py2.py3-none-any.whl (11 kB)
Collecting python-dateutil&amp;gt;=2.5.3
  Downloading python_dateutil-2.8.2-py2.py3-none-any.whl (247 kB)
Collecting google-auth&amp;gt;=1.0.1
  Downloading google_auth-2.6.0-py2.py3-none-any.whl (156 kB)
Collecting requests-oauthlib
  Downloading requests_oauthlib-1.3.1-py2.py3-none-any.whl (23 kB)
Requirement already satisfied: setuptools&amp;gt;=21.0.0 in /usr/lib/python3.7/site-packages (from kubernetes==12.0.1-&amp;gt;kube-hunter) (49.1.3)
Collecting websocket-client!=0.40.0,!=0.41.*,!=0.42.*,&amp;gt;=0.32.0
  Downloading websocket_client-1.3.1-py3-none-any.whl (54 kB)
Collecting certifi&amp;gt;=14.05.14
  Downloading certifi-2021.10.8-py2.py3-none-any.whl (149 kB)
Collecting charset-normalizer~=2.0.0; python_version &amp;gt;= &quot;3&quot;
  Downloading charset_normalizer-2.0.12-py3-none-any.whl (39 kB)
Collecting idna&amp;lt;4,&amp;gt;=2.5; python_version &amp;gt;= &quot;3&quot;
  Downloading idna-3.3-py3-none-any.whl (61 kB)
Collecting pyparsing!=3.0.5,&amp;gt;=2.0.2
  Downloading pyparsing-3.0.7-py3-none-any.whl (98 kB)
Collecting zipp&amp;gt;=0.5
  Downloading zipp-3.7.0-py3-none-any.whl (5.3 kB)
Collecting typing-extensions&amp;gt;=3.6.4; python_version &amp;lt; &quot;3.8&quot;
  Downloading typing_extensions-4.1.1-py3-none-any.whl (26 kB)
Collecting rsa&amp;lt;5,&amp;gt;=3.1.4; python_version &amp;gt;= &quot;3.6&quot;
  Downloading rsa-4.8-py3-none-any.whl (39 kB)
Collecting pyasn1-modules&amp;gt;=0.2.1
  Downloading pyasn1_modules-0.2.8-py2.py3-none-any.whl (155 kB)
Collecting cachetools&amp;lt;6.0,&amp;gt;=2.0.0
  Downloading cachetools-5.0.0-py3-none-any.whl (9.1 kB)
Collecting oauthlib&amp;gt;=3.0.0
  Downloading oauthlib-3.2.0-py3-none-any.whl (151 kB)
Collecting pyasn1&amp;gt;=0.1.3
  Downloading pyasn1-0.4.8-py2.py3-none-any.whl (77 kB)
Using legacy 'setup.py install' for future, since package 'wheel' is not installed.
Using legacy 'setup.py install' for scapy, since package 'wheel' is not installed.
Installing collected packages: ruamel.yaml.clib, ruamel.yaml, future, zipp, typing-extensions, importlib-metadata, wcwidth, PrettyTable, urllib3, pluggy, pyyaml, six, python-dateutil, pyasn1, rsa, pyasn1-modules, cachetools, google-auth, charset-normalizer, certifi, idna, requests, oauthlib, requests-oauthlib, websocket-client, kubernetes, netaddr, dataclasses, netifaces, pyparsing, packaging, scapy, kube-hunter
    Running setup.py install for future ... done
  WARNING: The scripts pyrsa-decrypt, pyrsa-encrypt, pyrsa-keygen, pyrsa-priv2pub, pyrsa-sign and pyrsa-verify are installed in '/root/.local/bin' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
  WARNING: The script normalizer is installed in '/root/.local/bin' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
  WARNING: The script wsdump is installed in '/root/.local/bin' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
  WARNING: The script netaddr is installed in '/root/.local/bin' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
    Running setup.py install for scapy ... done
  WARNING: The script kube-hunter is installed in '/root/.local/bin' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
Successfully installed PrettyTable-3.2.0 cachetools-5.0.0 certifi-2021.10.8 charset-normalizer-2.0.12 dataclasses-0.6 future-0.18.2 google-auth-2.6.0 idna-3.3 importlib-metadata-4.11.2 kube-hunter-0.6.5 kubernetes-12.0.1 netaddr-0.8.0 netifaces-0.11.0 oauthlib-3.2.0 packaging-21.3 pluggy-1.0.0 pyasn1-0.4.8 pyasn1-modules-0.2.8 pyparsing-3.0.7 python-dateutil-2.8.2 pyyaml-6.0 requests-2.27.1 requests-oauthlib-1.3.1 rsa-4.8 ruamel.yaml-0.17.21 ruamel.yaml.clib-0.2.6 scapy-2.4.5 six-1.16.0 typing-extensions-4.1.1 urllib3-1.26.8 wcwidth-0.2.5 websocket-client-1.3.1 zipp-3.7.0
[root@ip-192-168-84-159 kube-hunter]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;b. kube-hunter path 등록&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;설치가 완료되면 kube-hunter 바이너리는 $HOME/.local/bin 경로에 생성된다. 아래와 같이 PATH에 등록하고 사용하도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647269133912&quot; class=&quot;bash&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# .bash_profile

# Get the aliases and functions
if [ -f ~/.bashrc ]; then
        . ~/.bashrc
fi

# User specific environment and startup programs

PATH=$PATH:$HOME/bin:$HOME/.local/bin

export PATH&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;c. kube-hunter test list&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647269133913&quot; class=&quot;routeros&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-84-159 ~]# kube-hunter --list

Passive Hunters:
----------------
* API Service Discovery
  Checks for the existence of K8s API Services

* K8s Dashboard Discovery
  Checks for the existence of a Dashboard

* Etcd service
  check for the existence of etcd service

* Host Discovery when running as pod
  Generates ip adresses to scan, based on cluster/scan type

* Host Discovery
  Generates ip adresses to scan, based on cluster/scan type

* Kubectl Client Discovery
  Checks for the existence of a local kubectl client

* Kubelet Discovery
  Checks for the existence of a Kubelet service, and its open ports

* Port Scanning
  Scans Kubernetes known ports to determine open endpoints for discovery

* Proxy Discovery
  Checks for the existence of a an open Proxy service

* Kubelet Readonly Ports Hunter
  Hunts specific endpoints on open ports in the readonly Kubelet server

* Kubelet Secure Ports Hunter
  Hunts specific endpoints on an open secured Kubelet

* AKS Hunting
  Hunting Azure cluster deployments using specific known configurations

* API Server Hunter
  Checks if API server is accessible

* API Server Hunter
  Accessing the API server using the service account token obtained from a compromised pod

* Api Version Hunter
  Tries to obtain the Api Server's version directly from /version endpoint

* Pod Capabilities Hunter
  Checks for default enabled capabilities in a pod

* Certificate Email Hunting
  Checks for email addresses in kubernetes ssl certificates

* Kubectl CVE Hunter
  Checks if the kubectl client is vulnerable to specific important CVEs

* Dashboard Hunting
  Hunts open Dashboards, gets the type of nodes in the cluster

* Etcd Remote Access
  Checks for remote availability of etcd, its version, and read access to the DB

* Mount Hunter - /var/log
  Hunt pods that have write access to host's /var/log. in such case, the pod can traverse read files on the host machine

* Proxy Hunting
  Hunts for a dashboard behind the proxy

* Access Secrets
  Accessing the secrets accessible to the pod

[root@ip-192-168-84-159 ~]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;kube-hunter가 지원하는 Kubernetes 탐지 대상 오브젝트들이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;d. kube-hunter 활용&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;kube-hunter는 클러스터를 스캔하기 위해 세가지 옵션을 지원한다.&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; font-family: 'Noto Serif KR';&quot;&gt;원격지에 위치한 Cluster를 스캔하는 옵션&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;로컬 네트워크 인터페이스를 스캔하는 옵션&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;특정 IP 대역을 스캔하는 옵션&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;먼저 Rmote Scanning 방법에 대해 알아보자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647269133913&quot; class=&quot;routeros&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-84-159 ~]# kube-hunter
Choose one of the options below:
1. Remote scanning      (scans one or more specific IPs or DNS names)
2. Interface scanning   (scans subnets on all local network interfaces)
3. IP range scanning    (scans a given IP range)
Your choice: 1
Remotes (separated by a ','): 192.168.84.159
2022-03-13 14:13:50,012 INFO kube_hunter.modules.report.collector Started hunting
2022-03-13 14:13:50,012 INFO kube_hunter.modules.report.collector Discovering Open Kubernetes Services
2022-03-13 14:13:50,023 INFO kube_hunter.modules.report.collector Found open service &quot;Etcd&quot; at 192.168.84.159:2379
2022-03-13 14:13:50,045 INFO kube_hunter.modules.report.collector Found open service &quot;Kubelet API&quot; at 192.168.84.159:10250

Nodes
+-------------+----------------+
| TYPE        | LOCATION       |
+-------------+----------------+
| Node/Master | 192.168.84.159 |
+-------------+----------------+

Detected Services
+-------------+----------------------+----------------------+
| SERVICE     | LOCATION             | DESCRIPTION          |
+-------------+----------------------+----------------------+
| Kubelet API | 192.168.84.159:10250 | The Kubelet is the   |
|             |                      | main component in    |
|             |                      | every Node, all pod  |
|             |                      | operations goes      |
|             |                      | through the kubelet  |
+-------------+----------------------+----------------------+
| Etcd        | 192.168.84.159:2379  | Etcd is a DB that    |
|             |                      | stores cluster's     |
|             |                      | data, it contains    |
|             |                      | configuration and    |
|             |                      | current              |
|             |                      |     state            |
|             |                      | information, and     |
|             |                      | might contain        |
|             |                      | secrets              |
+-------------+----------------------+----------------------+

No vulnerabilities were found
[root@ip-192-168-84-159 ~]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Remote Scanning의 경우 IP를 직접 입력하여 대상 서버를 탐지할 수 있다. 위는 minikube가 기동되어 있는 IP를 입력하고, 그 결과를 확인하는 과정이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;다음으로 IP range Scanning이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647270354641&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# kube-hunter
Choose one of the options below:
1. Remote scanning      (scans one or more specific IPs or DNS names)
2. Interface scanning   (scans subnets on all local network interfaces)
3. IP range scanning    (scans a given IP range)
Your choice: 3
CIDR separated by a ',' (example - 192.168.0.0/16,!192.168.0.8/32,!192.168.1.0/24): 192.168.0.0/16
2022-03-14 03:26:23,664 INFO kube_hunter.modules.report.collector Started hunting
2022-03-14 03:26:23,664 INFO kube_hunter.modules.report.collector Discovering Open Kubernetes Services
2022-03-14 03:41:47,778 INFO kube_hunter.modules.report.collector Found open service &quot;Kubelet API&quot; at 192.168.119.45:10250
2022-03-14 03:41:47,790 INFO kube_hunter.modules.report.collector Found open service &quot;Kubelet API&quot; at 192.168.178.164:10250
2022-03-14 03:41:47,838 INFO kube_hunter.modules.report.collector Found open service &quot;API Server&quot; at 192.168.74.138:443
2022-03-14 03:41:47,868 INFO kube_hunter.modules.report.collector Found vulnerability &quot;K8s Version Disclosure&quot; in 192.168.74.138:443
2022-03-14 03:41:47,883 INFO kube_hunter.modules.report.collector Found open service &quot;API Server&quot; at 192.168.183.221:443
2022-03-14 03:41:47,930 INFO kube_hunter.modules.report.collector Found vulnerability &quot;K8s Version Disclosure&quot; in 192.168.183.221:443

Nodes
+-------------+-----------------+
| TYPE        | LOCATION        |
+-------------+-----------------+
| Node/Master | 192.168.183.221 |
+-------------+-----------------+
| Node/Master | 192.168.178.164 |
+-------------+-----------------+
| Node/Master | 192.168.119.45  |
+-------------+-----------------+
| Node/Master | 192.168.74.138  |
+-------------+-----------------+

Detected Services
+-------------+----------------------+----------------------+
| SERVICE     | LOCATION             | DESCRIPTION          |
+-------------+----------------------+----------------------+
| Kubelet API | 192.168.178.164:1025 | The Kubelet is the   |
|             | 0                    | main component in    |
|             |                      | every Node, all pod  |
|             |                      | operations goes      |
|             |                      | through the kubelet  |
+-------------+----------------------+----------------------+
| Kubelet API | 192.168.119.45:10250 | The Kubelet is the   |
|             |                      | main component in    |
|             |                      | every Node, all pod  |
|             |                      | operations goes      |
|             |                      | through the kubelet  |
+-------------+----------------------+----------------------+
| API Server  | 192.168.74.138:443   | The API server is in |
|             |                      | charge of all        |
|             |                      | operations on the    |
|             |                      | cluster.             |
+-------------+----------------------+----------------------+
| API Server  | 192.168.183.221:443  | The API server is in |
|             |                      | charge of all        |
|             |                      | operations on the    |
|             |                      | cluster.             |
+-------------+----------------------+----------------------+

Vulnerabilities
For further information about a vulnerability, search its ID in:
https://avd.aquasec.com/
+--------+---------------------+----------------------+----------------------+----------------------+---------------------+
| ID     | LOCATION            | MITRE CATEGORY       | VULNERABILITY        | DESCRIPTION          | EVIDENCE            |
+--------+---------------------+----------------------+----------------------+----------------------+---------------------+
| KHV002 | 192.168.74.138:443  | Initial Access //    | K8s Version          | The kubernetes       | v1.21.5-eks-bc4871b |
|        |                     | Exposed sensitive    | Disclosure           | version could be     |                     |
|        |                     | interfaces           |                      | obtained from the    |                     |
|        |                     |                      |                      | /version endpoint    |                     |
+--------+---------------------+----------------------+----------------------+----------------------+---------------------+
| KHV002 | 192.168.183.221:443 | Initial Access //    | K8s Version          | The kubernetes       | v1.21.5-eks-bc4871b |
|        |                     | Exposed sensitive    | Disclosure           | version could be     |                     |
|        |                     | interfaces           |                      | obtained from the    |                     |
|        |                     |                      |                      | /version endpoint    |                     |
+--------+---------------------+----------------------+----------------------+----------------------+---------------------+

[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;IP Scanning의 경우 특정 CIDR 내 구축되어 있는 클러스터를 탐지한다. 위 결과는 AWS EKS가 구성되어 있는 CIDR을 입력하고, 그 결과를 확인하는 과정이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;위와 같이 노드 4대가 검색되었다. 두대는 API Server로 EKS의 Master Node는 완전관리형으로 관리되지만, 위와 같이 API Server는 물리 노드로 노출되어 있는것을 확인할 수 있다. &lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;또한, Kubelet API가 설치되어 있는 Worker Node가 스캔된 것을 확인할 수 있다. endpoint 노출로 인한 보안취약점 문제를 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;kube-bench (클러스터 보안취약점)&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;다음으로 살펴볼 도구는 kube-hunter와 같이 클러스터 보안취약점 검사로 활용 가능한 오픈소스 소프트웨어 kube-bench이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;a. 설치&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;아래와 같이 바이너리를 다운로드 받아 Path에 복사하는 것만으로 설치 완료할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647272758923&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 kube-bench (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# wget https://github.com/aquasecurity/kube-bench/releases/download/v0.6.6/kube-bench_0.6.6_linux_amd64.tar.gz
--2022-03-14 04:16:51--  https://github.com/aquasecurity/kube-bench/releases/download/v0.6.6/kube-bench_0.6.6_linux_amd64.tar.gz
Resolving github.com (github.com)... 52.78.231.108
Connecting to github.com (github.com)|52.78.231.108|:443... connected.
HTTP request sent, awaiting response... 302 Found
Location: https://objects.githubusercontent.com/github-production-release-asset-2e65be/94779471/f3f9478c-ab50-4a05-9482-6976183c9e3e?X-Amz-Algorithm=AWS4-HMAC-SHA256&amp;amp;X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20220314%2Fus-east-1%2Fs3%2Faws4_request&amp;amp;X-Amz-Date=20220314T041651Z&amp;amp;X-Amz-Expires=300&amp;amp;X-Amz-Signature=350eb286f29247cfc83f31e6f3c229b296809f10b06b2490b2799d371a891df0&amp;amp;X-Amz-SignedHeaders=host&amp;amp;actor_id=0&amp;amp;key_id=0&amp;amp;repo_id=94779471&amp;amp;response-content-disposition=attachment%3B%20filename%3Dkube-bench_0.6.6_linux_amd64.tar.gz&amp;amp;response-content-type=application%2Foctet-stream [following]
--2022-03-14 04:16:51--  https://objects.githubusercontent.com/github-production-release-asset-2e65be/94779471/f3f9478c-ab50-4a05-9482-6976183c9e3e?X-Amz-Algorithm=AWS4-HMAC-SHA256&amp;amp;X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20220314%2Fus-east-1%2Fs3%2Faws4_request&amp;amp;X-Amz-Date=20220314T041651Z&amp;amp;X-Amz-Expires=300&amp;amp;X-Amz-Signature=350eb286f29247cfc83f31e6f3c229b296809f10b06b2490b2799d371a891df0&amp;amp;X-Amz-SignedHeaders=host&amp;amp;actor_id=0&amp;amp;key_id=0&amp;amp;repo_id=94779471&amp;amp;response-content-disposition=attachment%3B%20filename%3Dkube-bench_0.6.6_linux_amd64.tar.gz&amp;amp;response-content-type=application%2Foctet-stream
Resolving objects.githubusercontent.com (objects.githubusercontent.com)... 185.199.109.133, 185.199.108.133, 185.199.111.133, ...
Connecting to objects.githubusercontent.com (objects.githubusercontent.com)|185.199.109.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 10491759 (10M) [application/octet-stream]
Saving to: kube-bench_0.6.6_linux_amd64.tar.gz

100%[=====================================================================================================================================================================&amp;gt;] 10,491,759  24.2MB/s   in 0.4s

[root@ip-192-168-78-195 kube-bench (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# ls
kube-bench_0.6.6_linux_amd64.tar.gz
[root@ip-192-168-78-195 kube-bench (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# tar -xzvf kube-bench_0.6.6_linux_amd64.tar.gz
cfg/ack-1.0/config.yaml
cfg/ack-1.0/controlplane.yaml
cfg/ack-1.0/etcd.yaml
cfg/ack-1.0/managedservices.yaml
cfg/ack-1.0/master.yaml
cfg/ack-1.0/node.yaml
cfg/ack-1.0/policies.yaml
cfg/aks-1.0/config.yaml
cfg/aks-1.0/controlplane.yaml
cfg/aks-1.0/managedservices.yaml
cfg/aks-1.0/master.yaml
cfg/aks-1.0/node.yaml
cfg/aks-1.0/policies.yaml
cfg/cis-1.20/config.yaml
cfg/cis-1.20/controlplane.yaml
cfg/cis-1.20/etcd.yaml
cfg/cis-1.20/master.yaml
cfg/cis-1.20/node.yaml
cfg/cis-1.20/policies.yaml
cfg/cis-1.5/config.yaml
cfg/cis-1.5/controlplane.yaml
cfg/cis-1.5/etcd.yaml
cfg/cis-1.5/master.yaml
cfg/cis-1.5/node.yaml
cfg/cis-1.5/policies.yaml
cfg/cis-1.6/config.yaml
cfg/cis-1.6/controlplane.yaml
cfg/cis-1.6/etcd.yaml
cfg/cis-1.6/master.yaml
cfg/cis-1.6/node.yaml
cfg/cis-1.6/policies.yaml
cfg/config.yaml
cfg/eks-1.0.1/config.yaml
cfg/eks-1.0.1/controlplane.yaml
cfg/eks-1.0.1/managedservices.yaml
cfg/eks-1.0.1/master.yaml
cfg/eks-1.0.1/node.yaml
cfg/eks-1.0.1/policies.yaml
cfg/gke-1.0/config.yaml
cfg/gke-1.0/controlplane.yaml
cfg/gke-1.0/etcd.yaml
cfg/gke-1.0/managedservices.yaml
cfg/gke-1.0/master.yaml
cfg/gke-1.0/node.yaml
cfg/gke-1.0/policies.yaml
cfg/gke-1.2.0/config.yaml
cfg/gke-1.2.0/controlplane.yaml
cfg/gke-1.2.0/managedservices.yaml
cfg/gke-1.2.0/master.yaml
cfg/gke-1.2.0/node.yaml
cfg/gke-1.2.0/policies.yaml
cfg/rh-0.7/config.yaml
cfg/rh-0.7/master.yaml
cfg/rh-0.7/node.yaml
cfg/rh-1.0/config.yaml
cfg/rh-1.0/controlplane.yaml
cfg/rh-1.0/etcd.yaml
cfg/rh-1.0/master.yaml
cfg/rh-1.0/node.yaml
cfg/rh-1.0/policies.yaml
kube-bench
[root@ip-192-168-78-195 kube-bench (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# ls -la
total 34480
drwxr-xr-x  3 root root         78 Mar 14 04:17 .
dr-xr-x--- 18 root root       4096 Mar 14 04:17 ..
drwxr-xr-x 12 root root        178 Mar 14 04:17 cfg
-rwxr-xr-x  1 1001 docker 24801491 Jan 12 12:58 kube-bench
-rw-r--r--  1 root root   10491759 Jan 13 07:49 kube-bench_0.6.6_linux_amd64.tar.gz
[root@ip-192-168-78-195 kube-bench (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# cp kube-bench /usr/bin/
[root@ip-192-168-78-195 kube-bench (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]#
[root@ip-192-168-78-195 kube-bench (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# kube-bench --help
This tool runs the CIS Kubernetes Benchmark (https://www.cisecurity.org/benchmark/kubernetes/)

Usage:
  kube-bench [flags]
  kube-bench [command]

Available Commands:
  completion  Generate the autocompletion script for the specified shell
  help        Help about any command
  run         Run tests
  version     Shows the version of kube-bench.

Flags:
      --alsologtostderr                  log to standard error as well as files
      --asff                             Send the results to AWS Security Hub
      --benchmark string                 Manually specify CIS benchmark version. It would be an error to specify both --version and --benchmark flags
  -c, --check string                     A comma-delimited list of checks to run as specified in CIS document. Example --check=&quot;1.1.1,1.1.2&quot;
      --config string                    config file (default is ./cfg/config.yaml)
  -D, --config-dir string                config directory (default &quot;/etc/kube-bench/cfg&quot;)
      --exit-code int                    Specify the exit code for when checks fail
  -g, --group string                     Run all the checks under this comma-delimited list of groups. Example --group=&quot;1.1&quot;
  -h, --help                             help for kube-bench
      --include-test-output              Prints the actual result when test fails
      --json                             Prints the results as JSON
      --junit                            Prints the results as JUnit
      --log_backtrace_at traceLocation   when logging hits line file:N, emit a stack trace (default :0)
      --log_dir string                   If non-empty, write log files in this directory
      --logtostderr                      log to standard error instead of files (default true)
      --noremediations                   Disable printing of remediations section
      --noresults                        Disable printing of results section
      --nosummary                        Disable printing of summary section
      --nototals                         Disable printing of totals for failed, passed, ... checks across all sections
      --outputfile string                Writes the JSON results to output file
      --pgsql                            Save the results to PostgreSQL
      --scored                           Run the scored CIS checks (default true)
      --skip string                      List of comma separated values of checks to be skipped
      --stderrthreshold severity         logs at or above this threshold go to stderr (default 2)
      --unscored                         Run the unscored CIS checks (default true)
  -v, --v Level                          log level for V logs
      --version string                   Manually specify Kubernetes version, automatically detected if unset
      --vmodule moduleSpec               comma-separated list of pattern=N settings for file-filtered logging

Use &quot;kube-bench [command] --help&quot; for more information about a command.
[root@ip-192-168-78-195 kube-bench (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# kube-bench version
0.6.6
[root@ip-192-168-78-195 kube-bench (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;b. apply ruleset&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;검사에 활용할 수 있는 룰셋은 git repository를 통해 다운로드 받을 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647273401754&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 kube-bench (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# mkdir git-repo
[root@ip-192-168-78-195 kube-bench (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# cd git-repo/
[root@ip-192-168-78-195 git-repo (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# git clone https://github.com/aquasecurity/kube-bench
Cloning into 'kube-bench'...
remote: Enumerating objects: 4373, done.
remote: Counting objects: 100% (178/178), done.
remote: Compressing objects: 100% (101/101), done.
remote: Total 4373 (delta 84), reused 133 (delta 62), pack-reused 4195
Receiving objects: 100% (4373/4373), 8.67 MiB | 12.17 MiB/s, done.
Resolving deltas: 100% (2730/2730), done.
[root@ip-192-168-78-195 git-repo (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;c. EKS Check 수행&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647273506355&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 git-repo (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# cd kube-bench/
[root@ip-192-168-78-195 kube-bench (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# kube-bench --config-dir `pwd`/cfg --config `pwd`/cfg/config.yaml
[INFO] 3 Worker Node Security Configuration
[INFO] 3.1 Worker Node Configuration Files
[WARN] 3.1.1 Ensure that the kubeconfig file permissions are set to 644 or more restrictive (Manual)
[WARN] 3.1.2 Ensure that the kubelet kubeconfig file ownership is set to root:root (Manual)
[WARN] 3.1.3 Ensure that the kubelet configuration file has permissions set to 644 or more restrictive (Manual)
[WARN] 3.1.4 Ensure that the kubelet configuration file ownership is set to root:root (Manual)
[INFO] 3.2 Kubelet
[FAIL] 3.2.1 Ensure that the --anonymous-auth argument is set to false (Automated)
[FAIL] 3.2.2 Ensure that the --authorization-mode argument is not set to AlwaysAllow (Automated)
[WARN] 3.2.3 Ensure that the --client-ca-file argument is set as appropriate (Manual)
[WARN] 3.2.4 Ensure that the --read-only-port argument is set to 0 (Manual)
[WARN] 3.2.5 Ensure that the --streaming-connection-idle-timeout argument is not set to 0 (Manual)
[FAIL] 3.2.6 Ensure that the --protect-kernel-defaults argument is set to true (Automated)
[FAIL] 3.2.7 Ensure that the --make-iptables-util-chains argument is set to true (Automated)
[WARN] 3.2.8 Ensure that the --hostname-override argument is not set (Manual)
[WARN] 3.2.9 Ensure that the --eventRecordQPS argument is set to 0 or a level which ensures appropriate event capture (Automated)
[WARN] 3.2.10 Ensure that the --rotate-certificates argument is not set to false (Manual)
[WARN] 3.2.11 Ensure that the RotateKubeletServerCertificate argument is set to true (Manual)

== Remediations node ==
3.1.1 Run the below command (based on the file location on your system) on the each worker node.
For example,
chmod 644 /etc/kubernetes/kubelet.conf

3.1.2 Run the below command (based on the file location on your system) on the each worker node.
For example,
chown root:root /etc/kubernetes/kubelet.conf

3.1.3 Run the following command (using the config file location identified in the Audit step)
chmod 644 /var/lib/kubelet/config.yaml

3.1.4 Run the following command (using the config file location identified in the Audit step)
chown root:root /var/lib/kubelet/config.yaml

3.2.1 If using a Kubelet config file, edit the file to set authentication: anonymous: enabled to
false.
If using executable arguments, edit the kubelet service file
/etc/systemd/system/kubelet.service.d/10-kubeadm.conf on each worker node and
set the below parameter in KUBELET_SYSTEM_PODS_ARGS variable.
--anonymous-auth=false
Based on your system, restart the kubelet service. For example:
systemctl daemon-reload
systemctl restart kubelet.service

3.2.2 If using a Kubelet config file, edit the file to set authorization: mode to Webhook. If
using executable arguments, edit the kubelet service file
/etc/systemd/system/kubelet.service.d/10-kubeadm.conf on each worker node and
set the below parameter in KUBELET_AUTHZ_ARGS variable.
--authorization-mode=Webhook
Based on your system, restart the kubelet service. For example:
systemctl daemon-reload
systemctl restart kubelet.service

3.2.3 audit test did not run: failed to run: &quot;/bin/ps -fC $kubeletbin&quot;, output: &quot;error: list of command names must follow -C\n\nUsage:\n ps [options]\n\n Try 'ps --help &amp;lt;simple|list|output|threads|misc|all&amp;gt;'\n  or 'ps --help &amp;lt;s|l|o|t|m|a&amp;gt;'\n for additional help text.\n\nFor more details see ps(1).\n&quot;, error: exit status 1
3.2.4 audit test did not run: failed to run: &quot;/bin/ps -fC $kubeletbin&quot;, output: &quot;error: list of command names must follow -C\n\nUsage:\n ps [options]\n\n Try 'ps --help &amp;lt;simple|list|output|threads|misc|all&amp;gt;'\n  or 'ps --help &amp;lt;s|l|o|t|m|a&amp;gt;'\n for additional help text.\n\nFor more details see ps(1).\n&quot;, error: exit status 1
3.2.5 audit test did not run: failed to run: &quot;/bin/ps -fC $kubeletbin&quot;, output: &quot;error: list of command names must follow -C\n\nUsage:\n ps [options]\n\n Try 'ps --help &amp;lt;simple|list|output|threads|misc|all&amp;gt;'\n  or 'ps --help &amp;lt;s|l|o|t|m|a&amp;gt;'\n for additional help text.\n\nFor more details see ps(1).\n&quot;, error: exit status 1
3.2.6 If using a Kubelet config file, edit the file to set protectKernelDefaults: true.
If using command line arguments, edit the kubelet service file
/etc/systemd/system/kubelet.service.d/10-kubeadm.conf on each worker node and
set the below parameter in KUBELET_SYSTEM_PODS_ARGS variable.
--protect-kernel-defaults=true
Based on your system, restart the kubelet service. For example:
systemctl daemon-reload
systemctl restart kubelet.service

3.2.7 If using a Kubelet config file, edit the file to set makeIPTablesUtilChains: true.
If using command line arguments, edit the kubelet service file
/etc/systemd/system/kubelet.service.d/10-kubeadm.conf on each worker node and
remove the --make-iptables-util-chains argument from the
KUBELET_SYSTEM_PODS_ARGS variable.
Based on your system, restart the kubelet service. For example:
systemctl daemon-reload
systemctl restart kubelet.service

3.2.8 audit test did not run: failed to run: &quot;/bin/ps -fC $kubeletbin&quot;, output: &quot;error: list of command names must follow -C\n\nUsage:\n ps [options]\n\n Try 'ps --help &amp;lt;simple|list|output|threads|misc|all&amp;gt;'\n  or 'ps --help &amp;lt;s|l|o|t|m|a&amp;gt;'\n for additional help text.\n\nFor more details see ps(1).\n&quot;, error: exit status 1
3.2.9 audit test did not run: failed to run: &quot;/bin/ps -fC $kubeletbin&quot;, output: &quot;error: list of command names must follow -C\n\nUsage:\n ps [options]\n\n Try 'ps --help &amp;lt;simple|list|output|threads|misc|all&amp;gt;'\n  or 'ps --help &amp;lt;s|l|o|t|m|a&amp;gt;'\n for additional help text.\n\nFor more details see ps(1).\n&quot;, error: exit status 1
3.2.10 audit test did not run: failed to run: &quot;/bin/ps -fC $kubeletbin&quot;, output: &quot;error: list of command names must follow -C\n\nUsage:\n ps [options]\n\n Try 'ps --help &amp;lt;simple|list|output|threads|misc|all&amp;gt;'\n  or 'ps --help &amp;lt;s|l|o|t|m|a&amp;gt;'\n for additional help text.\n\nFor more details see ps(1).\n&quot;, error: exit status 1
3.2.11 audit test did not run: failed to run: &quot;/bin/ps -fC $kubeletbin&quot;, output: &quot;error: list of command names must follow -C\n\nUsage:\n ps [options]\n\n Try 'ps --help &amp;lt;simple|list|output|threads|misc|all&amp;gt;'\n  or 'ps --help &amp;lt;s|l|o|t|m|a&amp;gt;'\n for additional help text.\n\nFor more details see ps(1).\n&quot;, error: exit status 1

== Summary node ==
0 checks PASS
4 checks FAIL
11 checks WARN
0 checks INFO

[INFO] 4 Policies
[INFO] 4.1 RBAC and Service Accounts
[WARN] 4.1.1 Ensure that the cluster-admin role is only used where required (Manual)
[WARN] 4.1.2 Minimize access to secrets (Manual)
[WARN] 4.1.3 Minimize wildcard use in Roles and ClusterRoles (Manual)
[WARN] 4.1.4 Minimize access to create pods (Manual)
[WARN] 4.1.5 Ensure that default service accounts are not actively used. (Manual)
[WARN] 4.1.6 Ensure that Service Account Tokens are only mounted where necessary (Manual)
[INFO] 4.2 Pod Security Policies
[WARN] 4.2.1 Minimize the admission of privileged containers (Automated)
[WARN] 4.2.2 Minimize the admission of containers wishing to share the host process ID namespace (Automated)
[WARN] 4.2.3 Minimize the admission of containers wishing to share the host IPC namespace (Automated)
[WARN] 4.2.4 Minimize the admission of containers wishing to share the host network namespace (Automated)
[WARN] 4.2.5 Minimize the admission of containers with allowPrivilegeEscalation (Automated)
[WARN] 4.2.6 Minimize the admission of root containers (Automated)
[WARN] 4.2.7 Minimize the admission of containers with the NET_RAW capability (Automated)
[WARN] 4.2.8 Minimize the admission of containers with added capabilities (Automated)
[WARN] 4.2.9 Minimize the admission of containers with capabilities assigned (Manual)
[INFO] 4.3 CNI Plugin
[WARN] 4.3.1 Ensure that the latest CNI version is used (Manual)
[WARN] 4.3.2 Ensure that all Namespaces have Network Policies defined (Automated)
[INFO] 4.4 Secrets Management
[WARN] 4.4.1 Prefer using secrets as files over secrets as environment variables (Manual)
[WARN] 4.4.2 Consider external secret storage (Manual)
[INFO] 4.5 Extensible Admission Control
[WARN] 4.5.1 Configure Image Provenance using ImagePolicyWebhook admission controller (Manual)
[INFO] 4.6 General Policies
[WARN] 4.6.1 Create administrative boundaries between resources using namespaces (Manual)
[WARN] 4.6.2 Apply Security Context to Your Pods and Containers (Manual)
[WARN] 4.6.3 The default namespace should not be used (Automated)

== Remediations policies ==
4.1.1 Identify all clusterrolebindings to the cluster-admin role. Check if they are used and
if they need this role or if they could use a role with fewer privileges.
Where possible, first bind users to a lower privileged role and then remove the
clusterrolebinding to the cluster-admin role :
kubectl delete clusterrolebinding [name]

4.1.2 Where possible, remove get, list and watch access to secret objects in the cluster.

4.1.3 Where possible replace any use of wildcards in clusterroles and roles with specific
objects or actions.

4.1.4 Where possible, remove create access to pod objects in the cluster.

4.1.5 Create explicit service accounts wherever a Kubernetes workload requires specific access
to the Kubernetes API server.
Modify the configuration of each default service account to include this value
automountServiceAccountToken: false

4.1.6 Modify the definition of pods and service accounts which do not need to mount service
account tokens to disable it.

4.2.1 Create a PSP as described in the Kubernetes documentation, ensuring that
the .spec.privileged field is omitted or set to false.

4.2.2 Create a PSP as described in the Kubernetes documentation, ensuring that the
.spec.hostPID field is omitted or set to false.

4.2.3 Create a PSP as described in the Kubernetes documentation, ensuring that the
.spec.hostIPC field is omitted or set to false.

4.2.4 Create a PSP as described in the Kubernetes documentation, ensuring that the
.spec.hostNetwork field is omitted or set to false.

4.2.5 Create a PSP as described in the Kubernetes documentation, ensuring that the
.spec.allowPrivilegeEscalation field is omitted or set to false.

4.2.6 Create a PSP as described in the Kubernetes documentation, ensuring that the
.spec.runAsUser.rule is set to either MustRunAsNonRoot or MustRunAs with the range of
UIDs not including 0.

4.2.7 Create a PSP as described in the Kubernetes documentation, ensuring that the
.spec.requiredDropCapabilities is set to include either NET_RAW or ALL.

4.2.8 Ensure that allowedCapabilities is not present in PSPs for the cluster unless
it is set to an empty array.

4.2.9 Review the use of capabilities in applications running on your cluster. Where a namespace
contains applications which do not require any Linux capabities to operate consider adding
a PSP which forbids the admission of containers which do not drop all capabilities.

4.3.1 Review the documentation of AWS CNI plugin, and ensure latest CNI version is used.

4.3.2 Follow the documentation and create NetworkPolicy objects as you need them.

4.4.1 If possible, rewrite application code to read secrets from mounted secret files, rather than
from environment variables.

4.4.2 Refer to the secrets management options offered by your cloud provider or a third-party
secrets management solution.

4.5.1 Follow the Kubernetes documentation and setup image provenance.

4.6.1 Follow the documentation and create namespaces for objects in your deployment as you need
them.

4.6.2 Follow the Kubernetes documentation and apply security contexts to your pods. For a
suggested list of security contexts, you may refer to the CIS Security Benchmark for Docker
Containers.

4.6.3 Ensure that namespaces are created to allow for appropriate segregation of Kubernetes
resources and that all new resources are created in a specific namespace.


== Summary policies ==
0 checks PASS
0 checks FAIL
23 checks WARN
0 checks INFO

[INFO] 5 Managed Services
[INFO] 5.1 Image Registry and Image Scanning
[WARN] 5.1.1 Ensure Image Vulnerability Scanning using Amazon ECR image scanning or a third-party provider (Manual)
[WARN] 5.1.2 Minimize user access to Amazon ECR (Manual)
[WARN] 5.1.3 Minimize cluster access to read-only for Amazon ECR (Manual)
[WARN] 5.1.4 Minimize Container Registries to only those approved (Manual)
[INFO] 5.2 Identity and Access Management (IAM)
[WARN] 5.2.1 Prefer using dedicated Amazon EKS Service Accounts (Manual)
[INFO] 5.3 AWS Key Management Service (KMS)
[WARN] 5.3.1 Ensure Kubernetes Secrets are encrypted using Customer Master Keys (CMKs) managed in AWS KMS (Manual)
[INFO] 5.4 Cluster Networking
[WARN] 5.4.1 Restrict Access to the Control Plane Endpoint (Manual)
[WARN] 5.4.2 Ensure clusters are created with Private Endpoint Enabled and Public Access Disabled (Manual)
[WARN] 5.4.3 Ensure clusters are created with Private Nodes (Manual)
[WARN] 5.4.4 Ensure Network Policy is Enabled and set as appropriate (Manual)
[WARN] 5.4.5 Encrypt traffic to HTTPS load balancers with TLS certificates (Manual)
[INFO] 5.5 Authentication and Authorization
[WARN] 5.5.1 Manage Kubernetes RBAC users with AWS IAM Authenticator for Kubernetes (Manual)
[INFO] 5.6 Other Cluster Configurations
[WARN] 5.6.1 Consider Fargate for running untrusted workloads (Manual)

== Remediations managedservices ==
5.1.1 No remediation
5.1.2 No remediation
5.1.3 No remediation
5.1.4 No remediation
5.2.1 No remediation
5.3.1 No remediation
5.4.1 No remediation
5.4.2 No remediation
5.4.3 No remediation
5.4.4 No remediation
5.4.5 No remediation
5.5.1 No remediation
5.6.1 No remediation

== Summary managedservices ==
0 checks PASS
0 checks FAIL
13 checks WARN
0 checks INFO

== Summary total ==
0 checks PASS
4 checks FAIL
47 checks WARN
0 checks INFO

[root@ip-192-168-78-195 kube-bench (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;d. Minikube Check 수행&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647273639474&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 kube-bench (minikube:default)]# kube-bench --config-dir `pwd`/cfg --config `pwd`/cfg/config.yaml
[INFO] 4 Worker Node Security Configuration
[INFO] 4.1 Worker Node Configuration Files
[FAIL] 4.1.1 Ensure that the kubelet service file permissions are set to 644 or more restrictive (Automated)
[FAIL] 4.1.2 Ensure that the kubelet service file ownership is set to root:root (Automated)
[PASS] 4.1.3 If proxy kubeconfig file exists ensure permissions are set to 644 or more restrictive (Manual)
[PASS] 4.1.4 If proxy kubeconfig file exists ensure ownership is set to root:root (Manual)
[FAIL] 4.1.5 Ensure that the --kubeconfig kubelet.conf file permissions are set to 644 or more restrictive (Automated)
[FAIL] 4.1.6 Ensure that the --kubeconfig kubelet.conf file ownership is set to root:root (Automated)
[WARN] 4.1.7 Ensure that the certificate authorities file permissions are set to 644 or more restrictive (Manual)
[WARN] 4.1.8 Ensure that the client certificate authorities file ownership is set to root:root (Manual)
[FAIL] 4.1.9 Ensure that the kubelet --config configuration file has permissions set to 644 or more restrictive (Automated)
[FAIL] 4.1.10 Ensure that the kubelet --config configuration file ownership is set to root:root (Automated)
[INFO] 4.2 Kubelet
[FAIL] 4.2.1 Ensure that the anonymous-auth argument is set to false (Automated)
[FAIL] 4.2.2 Ensure that the --authorization-mode argument is not set to AlwaysAllow (Automated)
[FAIL] 4.2.3 Ensure that the --client-ca-file argument is set as appropriate (Automated)
[WARN] 4.2.4 Ensure that the --read-only-port argument is set to 0 (Manual)
[WARN] 4.2.5 Ensure that the --streaming-connection-idle-timeout argument is not set to 0 (Manual)
[FAIL] 4.2.6 Ensure that the --protect-kernel-defaults argument is set to true (Automated)
[FAIL] 4.2.7 Ensure that the --make-iptables-util-chains argument is set to true (Automated)
[WARN] 4.2.8 Ensure that the --hostname-override argument is not set (Manual)
[WARN] 4.2.9 Ensure that the --event-qps argument is set to 0 or a level which ensures appropriate event capture (Manual)
[WARN] 4.2.10 Ensure that the --tls-cert-file and --tls-private-key-file arguments are set as appropriate (Manual)
[WARN] 4.2.11 Ensure that the --rotate-certificates argument is not set to false (Manual)
[WARN] 4.2.12 Verify that the RotateKubeletServerCertificate argument is set to true (Manual)
[WARN] 4.2.13 Ensure that the Kubelet only makes use of Strong Cryptographic Ciphers (Manual)

== Remediations node ==
4.1.1 Run the below command (based on the file location on your system) on the each worker node.
For example,
chmod 644 /etc/systemd/system/kubelet.service.d/10-kubeadm.conf

4.1.2 Run the below command (based on the file location on your system) on the each worker node.
For example,
chown root:root /etc/systemd/system/kubelet.service.d/10-kubeadm.conf

4.1.5 Run the below command (based on the file location on your system) on the each worker node.
For example,
chmod 644 /etc/kubernetes/kubelet.conf

4.1.6 Run the below command (based on the file location on your system) on the each worker node.
For example,
chown root:root /etc/kubernetes/kubelet.conf

4.1.7 Run the following command to modify the file permissions of the
--client-ca-file chmod 644 &amp;lt;filename&amp;gt;

4.1.8 Run the following command to modify the ownership of the --client-ca-file.
chown root:root &amp;lt;filename&amp;gt;

4.1.9 Run the following command (using the config file location identified in the Audit step)
chmod 644 /var/lib/kubelet/config.yaml

4.1.10 Run the following command (using the config file location identified in the Audit step)
chown root:root /var/lib/kubelet/config.yaml

4.2.1 If using a Kubelet config file, edit the file to set authentication: anonymous: enabled to
false.
If using executable arguments, edit the kubelet service file
/etc/systemd/system/kubelet.service.d/10-kubeadm.conf on each worker node and
set the below parameter in KUBELET_SYSTEM_PODS_ARGS variable.
--anonymous-auth=false
Based on your system, restart the kubelet service. For example:
systemctl daemon-reload
systemctl restart kubelet.service

4.2.2 If using a Kubelet config file, edit the file to set authorization: mode to Webhook. If
using executable arguments, edit the kubelet service file
/etc/systemd/system/kubelet.service.d/10-kubeadm.conf on each worker node and
set the below parameter in KUBELET_AUTHZ_ARGS variable.
--authorization-mode=Webhook
Based on your system, restart the kubelet service. For example:
systemctl daemon-reload
systemctl restart kubelet.service

4.2.3 If using a Kubelet config file, edit the file to set authentication: x509: clientCAFile to
the location of the client CA file.
If using command line arguments, edit the kubelet service file
/etc/systemd/system/kubelet.service.d/10-kubeadm.conf on each worker node and
set the below parameter in KUBELET_AUTHZ_ARGS variable.
--client-ca-file=&amp;lt;path/to/client-ca-file&amp;gt;
Based on your system, restart the kubelet service. For example:
systemctl daemon-reload
systemctl restart kubelet.service

4.2.4 audit test did not run: failed to run: &quot;/bin/ps -fC $kubeletbin&quot;, output: &quot;error: list of command names must follow -C\n\nUsage:\n ps [options]\n\n Try 'ps --help &amp;lt;simple|list|output|threads|misc|all&amp;gt;'\n  or 'ps --help &amp;lt;s|l|o|t|m|a&amp;gt;'\n for additional help text.\n\nFor more details see ps(1).\n&quot;, error: exit status 1
4.2.5 audit test did not run: failed to run: &quot;/bin/ps -fC $kubeletbin&quot;, output: &quot;error: list of command names must follow -C\n\nUsage:\n ps [options]\n\n Try 'ps --help &amp;lt;simple|list|output|threads|misc|all&amp;gt;'\n  or 'ps --help &amp;lt;s|l|o|t|m|a&amp;gt;'\n for additional help text.\n\nFor more details see ps(1).\n&quot;, error: exit status 1
4.2.6 If using a Kubelet config file, edit the file to set protectKernelDefaults: true.
If using command line arguments, edit the kubelet service file
/etc/systemd/system/kubelet.service.d/10-kubeadm.conf on each worker node and
set the below parameter in KUBELET_SYSTEM_PODS_ARGS variable.
--protect-kernel-defaults=true
Based on your system, restart the kubelet service. For example:
systemctl daemon-reload
systemctl restart kubelet.service

4.2.7 If using a Kubelet config file, edit the file to set makeIPTablesUtilChains: true.
If using command line arguments, edit the kubelet service file
/etc/systemd/system/kubelet.service.d/10-kubeadm.conf on each worker node and
remove the --make-iptables-util-chains argument from the
KUBELET_SYSTEM_PODS_ARGS variable.
Based on your system, restart the kubelet service. For example:
systemctl daemon-reload
systemctl restart kubelet.service

4.2.8 audit test did not run: failed to run: &quot;/bin/ps -fC $kubeletbin&quot;, output: &quot;error: list of command names must follow -C\n\nUsage:\n ps [options]\n\n Try 'ps --help &amp;lt;simple|list|output|threads|misc|all&amp;gt;'\n  or 'ps --help &amp;lt;s|l|o|t|m|a&amp;gt;'\n for additional help text.\n\nFor more details see ps(1).\n&quot;, error: exit status 1
4.2.9 audit test did not run: failed to run: &quot;/bin/ps -fC $kubeletbin&quot;, output: &quot;error: list of command names must follow -C\n\nUsage:\n ps [options]\n\n Try 'ps --help &amp;lt;simple|list|output|threads|misc|all&amp;gt;'\n  or 'ps --help &amp;lt;s|l|o|t|m|a&amp;gt;'\n for additional help text.\n\nFor more details see ps(1).\n&quot;, error: exit status 1
4.2.10 audit test did not run: failed to run: &quot;/bin/ps -fC $kubeletbin&quot;, output: &quot;error: list of command names must follow -C\n\nUsage:\n ps [options]\n\n Try 'ps --help &amp;lt;simple|list|output|threads|misc|all&amp;gt;'\n  or 'ps --help &amp;lt;s|l|o|t|m|a&amp;gt;'\n for additional help text.\n\nFor more details see ps(1).\n&quot;, error: exit status 1
4.2.11 audit test did not run: failed to run: &quot;/bin/ps -fC $kubeletbin&quot;, output: &quot;error: list of command names must follow -C\n\nUsage:\n ps [options]\n\n Try 'ps --help &amp;lt;simple|list|output|threads|misc|all&amp;gt;'\n  or 'ps --help &amp;lt;s|l|o|t|m|a&amp;gt;'\n for additional help text.\n\nFor more details see ps(1).\n&quot;, error: exit status 1
4.2.12 audit test did not run: failed to run: &quot;/bin/ps -fC $kubeletbin&quot;, output: &quot;error: list of command names must follow -C\n\nUsage:\n ps [options]\n\n Try 'ps --help &amp;lt;simple|list|output|threads|misc|all&amp;gt;'\n  or 'ps --help &amp;lt;s|l|o|t|m|a&amp;gt;'\n for additional help text.\n\nFor more details see ps(1).\n&quot;, error: exit status 1
4.2.13 audit test did not run: failed to run: &quot;/bin/ps -fC $kubeletbin&quot;, output: &quot;error: list of command names must follow -C\n\nUsage:\n ps [options]\n\n Try 'ps --help &amp;lt;simple|list|output|threads|misc|all&amp;gt;'\n  or 'ps --help &amp;lt;s|l|o|t|m|a&amp;gt;'\n for additional help text.\n\nFor more details see ps(1).\n&quot;, error: exit status 1

== Summary node ==
2 checks PASS
11 checks FAIL
10 checks WARN
0 checks INFO

[INFO] 5 Kubernetes Policies
[INFO] 5.1 RBAC and Service Accounts
[WARN] 5.1.1 Ensure that the cluster-admin role is only used where required (Manual)
[WARN] 5.1.2 Minimize access to secrets (Manual)
[WARN] 5.1.3 Minimize wildcard use in Roles and ClusterRoles (Manual)
[WARN] 5.1.4 Minimize access to create pods (Manual)
[WARN] 5.1.5 Ensure that default service accounts are not actively used. (Manual)
[WARN] 5.1.6 Ensure that Service Account Tokens are only mounted where necessary (Manual)
[WARN] 5.1.7 Avoid use of system:masters group (Manual)
[WARN] 5.1.8 Limit use of the Bind, Impersonate and Escalate permissions in the Kubernetes cluster (Manual)
[INFO] 5.2 Pod Security Policies
[WARN] 5.2.1 Minimize the admission of privileged containers (Automated)
[WARN] 5.2.2 Minimize the admission of containers wishing to share the host process ID namespace (Automated)
[WARN] 5.2.3 Minimize the admission of containers wishing to share the host IPC namespace (Automated)
[WARN] 5.2.4 Minimize the admission of containers wishing to share the host network namespace (Automated)
[WARN] 5.2.5 Minimize the admission of containers with allowPrivilegeEscalation (Automated)
[WARN] 5.2.6 Minimize the admission of root containers (Automated)
[WARN] 5.2.7 Minimize the admission of containers with the NET_RAW capability (Automated)
[WARN] 5.2.8 Minimize the admission of containers with added capabilities (Automated)
[WARN] 5.2.9 Minimize the admission of containers with capabilities assigned (Manual)
[INFO] 5.3 Network Policies and CNI
[WARN] 5.3.1 Ensure that the CNI in use supports Network Policies (Manual)
[WARN] 5.3.2 Ensure that all Namespaces have Network Policies defined (Manual)
[INFO] 5.4 Secrets Management
[WARN] 5.4.1 Prefer using secrets as files over secrets as environment variables (Manual)
[WARN] 5.4.2 Consider external secret storage (Manual)
[INFO] 5.5 Extensible Admission Control
[WARN] 5.5.1 Configure Image Provenance using ImagePolicyWebhook admission controller (Manual)
[INFO] 5.7 General Policies
[WARN] 5.7.1 Create administrative boundaries between resources using namespaces (Manual)
[WARN] 5.7.2 Ensure that the seccomp profile is set to docker/default in your pod definitions (Manual)
[WARN] 5.7.3 Apply Security Context to Your Pods and Containers (Manual)
[WARN] 5.7.4 The default namespace should not be used (Manual)

== Remediations policies ==
5.1.1 Identify all clusterrolebindings to the cluster-admin role. Check if they are used and
if they need this role or if they could use a role with fewer privileges.
Where possible, first bind users to a lower privileged role and then remove the
clusterrolebinding to the cluster-admin role :
kubectl delete clusterrolebinding [name]

5.1.2 Where possible, remove get, list and watch access to secret objects in the cluster.

5.1.3 Where possible replace any use of wildcards in clusterroles and roles with specific
objects or actions.

5.1.4 Where possible, remove create access to pod objects in the cluster.

5.1.5 Create explicit service accounts wherever a Kubernetes workload requires specific access
to the Kubernetes API server.
Modify the configuration of each default service account to include this value
automountServiceAccountToken: false

5.1.6 Modify the definition of pods and service accounts which do not need to mount service
account tokens to disable it.

5.1.7 Remove the system:masters group from all users in the cluster.

5.1.8 Where possible, remove the impersonate, bind and escalate rights from subjects.

5.2.1 Create a PSP as described in the Kubernetes documentation, ensuring that
the .spec.privileged field is omitted or set to false.

5.2.2 Create a PSP as described in the Kubernetes documentation, ensuring that the
.spec.hostPID field is omitted or set to false.

5.2.3 Create a PSP as described in the Kubernetes documentation, ensuring that the
.spec.hostIPC field is omitted or set to false.

5.2.4 Create a PSP as described in the Kubernetes documentation, ensuring that the
.spec.hostNetwork field is omitted or set to false.

5.2.5 Create a PSP as described in the Kubernetes documentation, ensuring that the
.spec.allowPrivilegeEscalation field is omitted or set to false.

5.2.6 Create a PSP as described in the Kubernetes documentation, ensuring that the
.spec.runAsUser.rule is set to either MustRunAsNonRoot or MustRunAs with the range of
UIDs not including 0.

5.2.7 Create a PSP as described in the Kubernetes documentation, ensuring that the
.spec.requiredDropCapabilities is set to include either NET_RAW or ALL.

5.2.8 Ensure that allowedCapabilities is not present in PSPs for the cluster unless
it is set to an empty array.

5.2.9 Review the use of capabilites in applications running on your cluster. Where a namespace
contains applicaions which do not require any Linux capabities to operate consider adding
a PSP which forbids the admission of containers which do not drop all capabilities.

5.3.1 If the CNI plugin in use does not support network policies, consideration should be given to
making use of a different plugin, or finding an alternate mechanism for restricting traffic
in the Kubernetes cluster.

5.3.2 Follow the documentation and create NetworkPolicy objects as you need them.

5.4.1 if possible, rewrite application code to read secrets from mounted secret files, rather than
from environment variables.

5.4.2 Refer to the secrets management options offered by your cloud provider or a third-party
secrets management solution.

5.5.1 Follow the Kubernetes documentation and setup image provenance.

5.7.1 Follow the documentation and create namespaces for objects in your deployment as you need
them.

5.7.2 Use security context to enable the docker/default seccomp profile in your pod definitions.
An example is as below:
  securityContext:
    seccompProfile:
      type: RuntimeDefault

5.7.3 Follow the Kubernetes documentation and apply security contexts to your pods. For a
suggested list of security contexts, you may refer to the CIS Security Benchmark for Docker
Containers.

5.7.4 Ensure that namespaces are created to allow for appropriate segregation of Kubernetes
resources and that all new resources are created in a specific namespace.


== Summary policies ==
0 checks PASS
0 checks FAIL
26 checks WARN
0 checks INFO

== Summary total ==
2 checks PASS
11 checks FAIL
36 checks WARN
0 checks INFO

[root@ip-192-168-78-195 kube-bench (minikube:default)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;EKS 대비 Minikube의 경우 FAIL이 다 건 발생하는 것을 볼 수 있다. 클러스터 보안을 관리하는 측면에서 WARN 레벨까지 조치하는 것이 좋지만, FAIL에 대한 결과는 반드시 조치를 한 후 클러스터 환경을 운영할 것을 권고한다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;kyverno (정책관리)&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Kyverno는 그리스어로 거버넌스라는 의미이며, kubernetes를 위해 설계된 정책 엔진이다. Kyverno는 클러스터 관리자가 독립적으로 환경별 구성을 관리하고 클러스터에 대한 구성 모범 사례를 적용할 수 있도록 도와준다. Kyverno는 모범 사례를 위해 기존 워크로드를 스캔하는데 사용하거나 API 요청을 차단하거나 변경하여 모범 사례를 적용한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;a. 설치&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;yaml 파일을 통해 손쉽게 설치가 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647274982514&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 kube-bench (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# kubectl create -f https://raw.githubusercontent.com/kyverno/kyverno/main/config/install.yaml
namespace/kyverno created
customresourcedefinition.apiextensions.k8s.io/clusterpolicies.kyverno.io created
customresourcedefinition.apiextensions.k8s.io/clusterpolicyreports.wgpolicyk8s.io created
customresourcedefinition.apiextensions.k8s.io/clusterreportchangerequests.kyverno.io created
customresourcedefinition.apiextensions.k8s.io/generaterequests.kyverno.io created
customresourcedefinition.apiextensions.k8s.io/policies.kyverno.io created
customresourcedefinition.apiextensions.k8s.io/policyreports.wgpolicyk8s.io created
customresourcedefinition.apiextensions.k8s.io/reportchangerequests.kyverno.io created
serviceaccount/kyverno-service-account created
role.rbac.authorization.k8s.io/kyverno:leaderelection created
clusterrole.rbac.authorization.k8s.io/kyverno:admin-generaterequest created
clusterrole.rbac.authorization.k8s.io/kyverno:admin-policies created
clusterrole.rbac.authorization.k8s.io/kyverno:admin-policyreport created
clusterrole.rbac.authorization.k8s.io/kyverno:admin-reportchangerequest created
clusterrole.rbac.authorization.k8s.io/kyverno:events created
clusterrole.rbac.authorization.k8s.io/kyverno:generate created
clusterrole.rbac.authorization.k8s.io/kyverno:policies created
clusterrole.rbac.authorization.k8s.io/kyverno:userinfo created
clusterrole.rbac.authorization.k8s.io/kyverno:view created
clusterrole.rbac.authorization.k8s.io/kyverno:webhook created
rolebinding.rbac.authorization.k8s.io/kyverno:leaderelection created
clusterrolebinding.rbac.authorization.k8s.io/kyverno:events created
clusterrolebinding.rbac.authorization.k8s.io/kyverno:generate created
clusterrolebinding.rbac.authorization.k8s.io/kyverno:policies created
clusterrolebinding.rbac.authorization.k8s.io/kyverno:userinfo created
clusterrolebinding.rbac.authorization.k8s.io/kyverno:view created
clusterrolebinding.rbac.authorization.k8s.io/kyverno:webhook created
configmap/kyverno created
configmap/kyverno-metrics created
service/kyverno-svc created
service/kyverno-svc-metrics created
deployment.apps/kyverno created
[root@ip-192-168-78-195 kube-bench (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;b. label policy 적용&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;아래와 같이 label이 kubernetes에서 권고하는 app.kubernetes.io/name으로 추가되어 있는 검증하는 policy를 추가해보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;# 권장 레이블&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;a href=&quot;https://kubernetes.io/ko/docs/concepts/overview/working-with-objects/common-labels/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://kubernetes.io/ko/docs/concepts/overview/working-with-objects/common-labels/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1647275657283&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;권장 레이블&quot; data-og-description=&quot;kubectl과 대시보드와 같은 많은 도구들로 쿠버네티스 오브젝트를 시각화 하고 관리할 수 있다. 공통 레이블 셋은 모든 도구들이 이해할 수 있는 공통의 방식으로 오브젝트를 식별하고 도구들이 &quot; data-og-host=&quot;kubernetes.io&quot; data-og-source-url=&quot;https://kubernetes.io/ko/docs/concepts/overview/working-with-objects/common-labels/&quot; data-og-url=&quot;https://kubernetes.io/ko/docs/concepts/overview/working-with-objects/common-labels/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/eoU8rt/hyNH8V6xCV/cuC2k3P8Vjnznjsrt2dV2k/img.png?width=1727&amp;amp;height=373&amp;amp;face=0_0_1727_373,https://scrap.kakaocdn.net/dn/casWEU/hyNH73Y1PU/ylJLEiOWmpphDGOfbmqcLk/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512&quot;&gt;&lt;a href=&quot;https://kubernetes.io/ko/docs/concepts/overview/working-with-objects/common-labels/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://kubernetes.io/ko/docs/concepts/overview/working-with-objects/common-labels/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/eoU8rt/hyNH8V6xCV/cuC2k3P8Vjnznjsrt2dV2k/img.png?width=1727&amp;amp;height=373&amp;amp;face=0_0_1727_373,https://scrap.kakaocdn.net/dn/casWEU/hyNH73Y1PU/ylJLEiOWmpphDGOfbmqcLk/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512');&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;권장 레이블&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;kubectl과 대시보드와 같은 많은 도구들로 쿠버네티스 오브젝트를 시각화 하고 관리할 수 있다. 공통 레이블 셋은 모든 도구들이 이해할 수 있는 공통의 방식으로 오브젝트를 식별하고 도구들이&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;kubernetes.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;pre id=&quot;code_1647275270042&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 kyverno (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# cat policy.sh
kubectl create -f- &amp;lt;&amp;lt; EOF
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-labels
spec:
  validationFailureAction: enforce
  rules:
  - name: check-for-labels
    match:
      any:
      - resources:
          kinds:
          - Pod
    validate:
      message: &quot;label 'app.kubernetes.io/name' is required&quot;
      pattern:
        metadata:
          labels:
            app.kubernetes.io/name: &quot;?*&quot;
EOF
[root@ip-192-168-78-195 kyverno (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# sh policy.sh
clusterpolicy.kyverno.io/require-labels created
[root@ip-192-168-78-195 kyverno (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;policy sample은 아래 url에서 확인할 수 있으며, 총 128개가 제공되고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;# 정책 샘플&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;a href=&quot;https://kyverno.io/policies/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://kyverno.io/policies/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1647275601551&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;Policies&quot; data-og-description=&quot;Kyverno is a policy engine designed for Kubernetes&quot; data-og-host=&quot;kyverno.io&quot; data-og-source-url=&quot;https://kyverno.io/policies/&quot; data-og-url=&quot;https://kyverno.io/policies/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://kyverno.io/policies/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://kyverno.io/policies/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&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;Policies&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Kyverno is a policy engine designed for Kubernetes&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;kyverno.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: 'Noto Serif KR'; color: #000000;&quot;&gt;아래와 같이 app.kubernetes.io/name이 포함되어 있지 않은 deployment를 반영해 보자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647275453506&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 app (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# cat nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
    # namespace: app-test
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 1
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx
        command: [&quot;/bin/bash&quot;]
        args: [&quot;-c&quot;, &quot;echo \&quot;&amp;lt;p&amp;gt;Hello from $(hostname)&amp;lt;/p&amp;gt;\&quot; &amp;gt; index.html; sleep 30000 &amp;amp;&amp;amp; python -m SimpleHTTPServer 8080&quot;]
        ports:
        - containerPort: 80
[root@ip-192-168-78-195 app (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# kubectl apply -f nginx-deployment.yaml
Error from server: error when creating &quot;nginx-deployment.yaml&quot;: admission webhook &quot;validate.kyverno.svc-fail&quot; denied the request:

resource Deployment/default/my-nginx was blocked due to the following policies

require-labels:
  autogen-check-for-labels: 'validation error: label ''app.kubernetes.io/name'' is
    required. Rule autogen-check-for-labels failed at path /spec/template/metadata/labels/app.kubernetes.io/name/'
[root@ip-192-168-78-195 app (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;require-labels 항목과 함께 validation error가 발생하는 것을 확인할 수 있다.&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;deployment를 수정하고 다시 반영해 보도록 하자.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647275796138&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 app (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# cat nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
    # namespace: app-test
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 1
  template:
    metadata:
      labels:
        run: my-nginx
        app.kubernetes.io/name: nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx
        command: [&quot;/bin/bash&quot;]
        args: [&quot;-c&quot;, &quot;echo \&quot;&amp;lt;p&amp;gt;Hello from $(hostname)&amp;lt;/p&amp;gt;\&quot; &amp;gt; index.html; sleep 30000 &amp;amp;&amp;amp; python -m SimpleHTTPServer 8080&quot;]
        ports:
        - containerPort: 80
[root@ip-192-168-78-195 app (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# kubectl apply -f nginx-deployment.yaml
deployment.apps/my-nginx created
[root@ip-192-168-78-195 app (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 정상적으로 반영된 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;c. replicas policy&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;다음으로 replica에 대한 정책을 반영해 보자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647276055899&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 app (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# policy-replica.sh
kubectl create -f- &amp;lt;&amp;lt; EOF
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: deployment-has-multiple-replicas
  annotations:
    policies.kyverno.io/title: Require Multiple Replicas
    policies.kyverno.io/category: Sample
    policies.kyverno.io/severity: medium
    policies.kyverno.io/subject: Deployment
    policies.kyverno.io/description: &amp;gt;-
      Deployments with a single replica cannot be highly available and thus the application
      may suffer downtime if that one replica goes down. This policy validates that Deployments
      have more than one replica.
spec:
  validationFailureAction: audit
  background: true
  rules:
    - name: deployment-has-multiple-replicas
      match:
        resources:
          kinds:
          - Deployment
      validate:
        message: &quot;Deployments should have more than one replica to ensure availability.&quot;
        pattern:
          spec:
            replicas: &quot;&amp;gt;1&quot;
EOF
[root@ip-192-168-78-195 app (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;정책 반영시 validationFailureAction을 앞선 label에서는 enforce로 설정하였지만, replica에서는 audit으로 설정한 것을 확인할 수 있다. enforce의 경우 실패로 처리하여 배포가 되지 않도록 하지만, audit의 경우 실패를 남기지만, 배포는 수행하도록 한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647276308307&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 kyverno (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# kubectl get clusterpolicy
NAME                               BACKGROUND   ACTION    READY
deployment-has-multiple-replicas   true         audit     true
require-labels                     true         enforce   true
[root@ip-192-168-78-195 kyverno (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# kubectl get policyreport -A
NAMESPACE   NAME               PASS   FAIL   WARN   ERROR   SKIP   AGE
app-test    polr-ns-app-test   1      1      0      0       0      56s
default     polr-ns-default    1      1      0      0       0      60m
[root@ip-192-168-78-195 kyverno (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 clusterpolicy를 확인할 수 있으며, replica가 1개로 등록된 app-test, default namespace 내 deployment가 각각 PASS 1(REQUIRE-LABELS), FAIL 1(DEPLOYMENT-HAS-MULTIPLE-REPLICAS)로 기록되어 있는 것을 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647276245598&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 app (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# policy-replica.sh
kubectl create -f- &amp;lt;&amp;lt; EOF
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: deployment-has-multiple-replicas
  annotations:
    policies.kyverno.io/title: Require Multiple Replicas
    policies.kyverno.io/category: Sample
    policies.kyverno.io/severity: medium
    policies.kyverno.io/subject: Deployment
    policies.kyverno.io/description: &amp;gt;-
      Deployments with a single replica cannot be highly available and thus the application
      may suffer downtime if that one replica goes down. This policy validates that Deployments
      have more than one replica.
spec:
  validationFailureAction: enforce
  background: true
  rules:
    - name: deployment-has-multiple-replicas
      match:
        resources:
          kinds:
          - Deployment
      validate:
        message: &quot;Deployments should have more than one replica to ensure availability.&quot;
        pattern:
          spec:
            replicas: &quot;&amp;gt;1&quot;
EOF
[root@ip-192-168-78-195 app (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# kubectl apply -f nginx-deployment.yaml
Error from server: error when creating &quot;nginx-deployment.yaml&quot;: admission webhook &quot;validate.kyverno.svc-fail&quot; denied the request:

resource Deployment/app-test/my-nginx was blocked due to the following policies

deployment-has-multiple-replicas:
  deployment-has-multiple-replicas: 'validation error: Deployments should have more
    than one replica to ensure availability. Rule deployment-has-multiple-replicas
    failed at path /spec/replicas/'
[root@ip-192-168-78-195 app (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# kubectl get policyreport -A
NAMESPACE   NAME               PASS   FAIL   WARN   ERROR   SKIP   AGE
app-test    polr-ns-app-test   0      0      0      0       0      4m57s
default     polr-ns-default    1      1      0      0       0      64m
[root@ip-192-168-78-195 app (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 ENFORCE로 수정 반영 시 deployment-has-multiple-replicas 항목과 함께 validation error가 발생하는 것을 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;kube-score (yaml 구성 권고사항)&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;kube-score는 Kubernetes object definition을 분석하는 도구이다. kubernetes를 적용하는 object 즉 yaml 파일을 분석하여&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;보다 안전하고 탄력적으로 만들기 위해 개선사항을 제시해 준다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;a. 설치&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;설치는 수동설치가 가능하지만 krew kubectl 패키지 매니저를 활용하여 원스탭 설치가 가능하다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647277572538&quot; class=&quot;stata&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 ~ (kubeapp:default)]# kubectl krew install score
Updated the local copy of plugin index.
Installing plugin: score
Installed plugin: score
\
 | Use this plugin:
 |      kubectl score
 | Documentation:
 |      https://github.com/zegl/kube-score
/
WARNING: You installed plugin &quot;score&quot; from the krew-index plugin repository.
   These plugins are not audited for security by the Krew maintainers.
   Run them at your own risk.
[root@ip-192-168-78-195 ~ (kubeapp:default)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;b. 복사&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647277572538&quot; class=&quot;angelscript&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 / (kubeapp:default)]# cp /root/.krew/store/score/v1.10.0/kube-score /usr/local/bin/
[root@ip-192-168-78-195 / (kubeapp:default)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;c. 검사 수행&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;앞서 살펴본 nginx-deployment.yaml 파일을 score를 돌려 결과를 확인해 보자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647277572539&quot; class=&quot;yaml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
    # namespace: app-test
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 1
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx
        command: [&quot;/bin/bash&quot;]
        args: [&quot;-c&quot;, &quot;echo \&quot;&amp;lt;p&amp;gt;Hello from $(hostname)&amp;lt;/p&amp;gt;\&quot; &amp;gt; index.html; sleep 30000 &amp;amp;&amp;amp; python -m SimpleHTTPServer 8080&quot;]
        ports:
        - containerPort: 80&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;kube-score를 확인해 보면 아래와 같이 yaml 파일에 대한 수정 권고사항이 출력되는 것을 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647277572539&quot; class=&quot;routeros&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 app (kubeapp:default)]# kube-score score nginx-deployment.yaml
apps/v1/Deployment my-nginx                                                   뮙
    [CRITICAL] Container Security Context
        . my-nginx -&amp;gt; Container has no configured security context
            Set securityContext to run the container in a more secure context.
    [CRITICAL] Container Resources
        . my-nginx -&amp;gt; CPU limit is not set
            Resource limits are recommended to avoid resource DDOS. Set resources.limits.cpu
        . my-nginx -&amp;gt; Memory limit is not set
            Resource limits are recommended to avoid resource DDOS. Set resources.limits.memory
        . my-nginx -&amp;gt; CPU request is not set
            Resource requests are recommended to make sure that the application can start and run without crashing. Set resources.requests.cpu
        . my-nginx -&amp;gt; Memory request is not set
            Resource requests are recommended to make sure that the application can start and run without crashing. Set resources.requests.memory
    [CRITICAL] Container Image Tag
        . my-nginx -&amp;gt; Image with latest tag
            Using a fixed tag is recommended to avoid accidental upgrades
    [CRITICAL] Pod NetworkPolicy
        . The pod does not have a matching NetworkPolicy
            Create a NetworkPolicy that targets this pod to control who/what can communicate with this pod. Note, this feature needs to be supported by the CNI implementation used in the Kubernetes cluster to have an effect.
[root@ip-192-168-78-195 app (kubeapp:default)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 securityContext 구성, Resource Limit 구성, Image Tag, Pod NetworkPolicy 등의 권고사항이 표시되는 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;그 밖에 지원하는 Check 리스트는 아래와 같다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.7907%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;ingress-targets-service&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23.2559%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Ingress&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.0697%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Makes sure that the Ingress targets a Service&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.76744%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;default&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.7907%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;cronjob-has-deadline&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23.2559%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;CronJob&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.0697%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Makes sure that all CronJobs has a configured deadline&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.76744%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;default&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.7907%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;container-resources&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23.2559%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Pod&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.0697%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Makes sure that all pods have resource limits and requests set. The --ignore-container-cpu-limit flag can be used to disable the requirement of having a CPU limit&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.76744%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;default&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.7907%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;container-resource-requests-equal-limits&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23.2559%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Pod&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.0697%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Makes sure that all pods have the same requests as limits on resources set.&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.76744%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;optional&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.7907%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;container-cpu-requests-equal-limits&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23.2559%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Pod&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.0697%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Makes sure that all pods have the same CPU requests as limits set.&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.76744%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;optional&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.7907%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;container-memory-requests-equal-limits&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23.2559%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Pod&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.0697%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Makes sure that all pods have the same memory requests as limits set.&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.76744%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;optional&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.7907%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;container-image-tag&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23.2559%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Pod&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.0697%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Makes sure that a explicit non-latest tag is used&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.76744%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;default&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.7907%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;container-image-pull-policy&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23.2559%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Pod&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.0697%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Makes sure that the pullPolicy is set to Always. This makes sure that imagePullSecrets are always validated.&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.76744%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;default&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.7907%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;container-ephemeral-storage-request-and-limit&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23.2559%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Pod&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.0697%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Makes sure all pods have ephemeral-storage requests and limits set&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.76744%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;default&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.7907%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;container-ephemeral-storage-request-equals-limit&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23.2559%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Pod&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.0697%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Make sure all pods have matching ephemeral-storage requests and limits&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.76744%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;optional&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.7907%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;container-ports-check&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23.2559%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Pod&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.0697%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Container Ports Checks&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.76744%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;optional&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.7907%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;statefulset-has-poddisruptionbudget&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23.2559%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;StatefulSet&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.0697%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Makes sure that all StatefulSets are targeted by a PDB&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.76744%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;default&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.7907%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;deployment-has-poddisruptionbudget&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23.2559%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Deployment&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.0697%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Makes sure that all Deployments are targeted by a PDB&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.76744%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;default&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.7907%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;poddisruptionbudget-has-policy&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23.2559%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;PodDisruptionBudget&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.0697%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Makes sure that PodDisruptionBudgets specify minAvailable or maxUnavailable&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.76744%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;default&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.7907%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;pod-networkpolicy&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23.2559%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Pod&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.0697%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Makes sure that all Pods are targeted by a NetworkPolicy&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.76744%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;default&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.7907%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;networkpolicy-targets-pod&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23.2559%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;NetworkPolicy&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.0697%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Makes sure that all NetworkPolicies targets at least one Pod&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.76744%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;default&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.7907%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;pod-probes&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23.2559%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Pod&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.0697%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Makes sure that all Pods have safe probe configurations&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.76744%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;default&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.7907%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;container-security-context-user-group-id&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23.2559%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Pod&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.0697%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Makes sure that all pods have a security context with valid UID and GID set&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.76744%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;default&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.7907%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;container-security-context-privileged&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23.2559%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Pod&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.0697%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Makes sure that all pods have a unprivileged security context set&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.76744%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;default&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.7907%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;container-security-context-readonlyrootfilesystem&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23.2559%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Pod&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.0697%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Makes sure that all pods have a security context with read only filesystem set&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.76744%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;default&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.7907%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;container-seccomp-profile&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23.2559%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Pod&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.0697%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Makes sure that all pods have at a seccomp policy configured.&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.76744%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;optional&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.7907%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;service-targets-pod&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23.2559%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Service&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.0697%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Makes sure that all Services targets a Pod&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.76744%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;default&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.7907%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;service-type&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23.2559%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Service&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.0697%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Makes sure that the Service type is not NodePort&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.76744%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;default&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.7907%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;stable-version&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23.2559%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;all&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.0697%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Checks if the object is using a deprecated apiVersion&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.76744%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;default&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.7907%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;deployment-has-host-podantiaffinity&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23.2559%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Deployment&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.0697%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Makes sure that a podAntiAffinity has been set that prevents multiple pods from being scheduled on the same node.&amp;nbsp;&lt;a href=&quot;https://kubernetes.io/docs/concepts/configuration/assign-pod-node/&quot;&gt;https://kubernetes.io/docs/concepts/configuration/assign-pod-node/&lt;/a&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.76744%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;default&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.7907%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;statefulset-has-host-podantiaffinity&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23.2559%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;StatefulSet&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.0697%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Makes sure that a podAntiAffinity has been set that prevents multiple pods from being scheduled on the same node.&amp;nbsp;&lt;a href=&quot;https://kubernetes.io/docs/concepts/configuration/assign-pod-node/&quot;&gt;https://kubernetes.io/docs/concepts/configuration/assign-pod-node/&lt;/a&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.76744%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;default&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.7907%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;deployment-targeted-by-hpa-does-not-have-replicas-configured&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23.2559%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Deployment&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.0697%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Makes sure that Deployments using a HorizontalPodAutoscaler doesn't have a statically configured replica count set&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.76744%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;default&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.7907%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;statefulset-has-servicename&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23.2559%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;StatefulSet&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.0697%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Makes sure that StatefulSets have an existing headless serviceName.&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.76744%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;default&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.7907%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;deployment-pod-selector-labels-match-template-metadata-labels&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23.2559%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Deployment&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.0697%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Ensure the StatefulSet selector labels match the template metadata labels.&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.76744%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;default&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.7907%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;statefulset-pod-selector-labels-match-template-metadata-labels&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23.2559%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;StatefulSet&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.0697%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Ensure the StatefulSet selector labels match the template metadata labels.&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.76744%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;default&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.7907%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;label-values&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23.2559%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;all&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.0697%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Validates label values&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.76744%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;default&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.7907%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;horizontalpodautoscaler-has-target&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23.2559%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;HorizontalPodAutoscaler&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.0697%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Makes sure that the HPA targets a valid object&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.76744%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;default&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 kube-score는 yaml 파일 내 검증항목에 대한 모범사례를 기준으로 권고사항을 제시해 준다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;결론&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Kubernetes의 보안 취약점에 대한 대응 방안을 수립하는 것은 쉽지 않은 일이다. 특히 무엇보다 이를 운영부서에서 수동으로 관리할 경우 비용은 물론 안정성 측면에서 휴먼 에러를 방지할 수 없을 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위에 소개한 도구들은 대부분 kubernetes 환경에 완전한 통합을 지원하므로, 가능한 CI/CD 파이프라인에 적용하여 자동화된 환경을 구성하는 것을 권고한다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>③ 클라우드/ⓚ Kubernetes</category>
      <category>kube-bench</category>
      <category>kube-hunter</category>
      <category>kube-score</category>
      <category>kubernetes policy</category>
      <category>Kubernetes 보안</category>
      <category>kyverno</category>
      <category>yaml 보안</category>
      <category>클러스터 보안</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/767</guid>
      <comments>https://waspro.tistory.com/767#entry767comment</comments>
      <pubDate>Mon, 14 Mar 2022 23:47:24 +0900</pubDate>
    </item>
    <item>
      <title>Polaris - Kubernetes 워크로드 모범 사례 적용 검증</title>
      <link>https://waspro.tistory.com/766</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;개요&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Polaris는 Kubernetes Pod 및 Controller가 모범 사례를 사용하여 구성되었는지 확인하기 위해 다양한 검사를 실행하여 향후 발생 가능한 문제를 사전에 방지하는데 도움을 주는 도구이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Polaris는 세 가지 모드로 실행할 수 있다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;대시보드로 클러스터 내에서 실행 중인 항목을 감사할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;승인 컨트롤러로서 조직의 정책을 준수하지 않는 워크로드를 자동으로 거부할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;CLI로 CI/CD 프로세스의 일부로 로컬 YAML 파일을 테스트할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;설치&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;대시보드는 아래와 같이 yaml 파일을 통해 다운로드 받아 설치 할 수 있다. yaml 파일위치는 각 최신 버전을 기준으로 아래 경로에서 다운로드 받을 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://github.com/FairwindsOps/polaris/blob/v5.0.1/deploy/dashboard.yaml&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/FairwindsOps/polaris/blob/v5.0.1/deploy/dashboard.yaml&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1647116710359&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 - FairwindsOps/polaris: Validation of best practices in your Kubernetes clusters&quot; data-og-description=&quot;Validation of best practices in your Kubernetes clusters - GitHub - FairwindsOps/polaris: Validation of best practices in your Kubernetes clusters&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/FairwindsOps/polaris/blob/v5.0.1/deploy/dashboard.yaml&quot; data-og-url=&quot;https://github.com/FairwindsOps/polaris&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ca9eBM/hyNGPblsPb/yY33yTHPFqvSKAPwGPyme1/img.png?width=1020&amp;amp;height=493&amp;amp;face=0_0_1020_493&quot;&gt;&lt;a href=&quot;https://github.com/FairwindsOps/polaris/blob/v5.0.1/deploy/dashboard.yaml&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/FairwindsOps/polaris/blob/v5.0.1/deploy/dashboard.yaml&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ca9eBM/hyNGPblsPb/yY33yTHPFqvSKAPwGPyme1/img.png?width=1020&amp;amp;height=493&amp;amp;face=0_0_1020_493');&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 - FairwindsOps/polaris: Validation of best practices in your Kubernetes clusters&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Validation of best practices in your Kubernetes clusters - GitHub - FairwindsOps/polaris: Validation of best practices in your Kubernetes clusters&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;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;아래와 같이 대시보드 접근을 위해 Service를 NodePort로 변경하여 반영한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647118153877&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: v1
kind: Service
metadata:
  name: polaris-dashboard
  namespace: polaris
  labels:
    app: polaris
  annotations:
spec:
  ports:
  - nodePort: 30005
    name: http-dashboard
    port: 80
    protocol: TCP
    targetPort: 8080
  selector:
    app: polaris
    component: dashboard
  type: NodePort&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;반영 및 확인 결과는 아래와 같다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647117154974&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-84-159 minikube]# kubectl apply -f dashboard.yaml 
namespace/polaris created
serviceaccount/polaris created
clusterrole.rbac.authorization.k8s.io/polaris created
clusterrolebinding.rbac.authorization.k8s.io/polaris-view created
clusterrolebinding.rbac.authorization.k8s.io/polaris created
service/polaris-dashboard created
deployment.apps/polaris-dashboard created
[root@ip-192-168-84-159 minikube]# kubectl get all -n polaris
NAME                                     READY   STATUS    RESTARTS   AGE
pod/polaris-dashboard-6975976fff-hbsm2   1/1     Running   0          76s
pod/polaris-dashboard-6975976fff-hjccm   1/1     Running   0          76s

NAME                        TYPE       CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
service/polaris-dashboard   NodePort   10.102.7.93   &amp;lt;none&amp;gt;        80:30005/TCP   76s

NAME                                READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/polaris-dashboard   2/2     2            2           76s

NAME                                           DESIRED   CURRENT   READY   AGE
replicaset.apps/polaris-dashboard-6975976fff   2         2         2       76s
[root@ip-192-168-84-159 minikube]#&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;대시보드 활용&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Polaris 대시보드는 Kubernetes 워크로드의 현재 상태에 대한 간단한 시각적 개요와 개선할 수 있는 사항에 대한 로드맵을 얻을 수 있다.&amp;nbsp;대시보드는 클러스터 전체의 개요를 제공할 뿐만 아니라 범주, 네임스페이스 및 워크로드별로 결과를 분류한다. Polaris 대시보드를 통해 확인 가능한 사항은 아래와 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1) Cluster Overview&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;661&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/besM3q/btrvLJuRTI0/Qh1DdlRUYgW2TltkgI2600/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/besM3q/btrvLJuRTI0/Qh1DdlRUYgW2TltkgI2600/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/besM3q/btrvLJuRTI0/Qh1DdlRUYgW2TltkgI2600/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbesM3q%2FbtrvLJuRTI0%2FQh1DdlRUYgW2TltkgI2600%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;661&quot; data-origin-width=&quot;1225&quot; data-origin-height=&quot;661&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: 'Noto Serif KR'; color: #000000;&quot;&gt;먼저 연결되어 있는 Cluster의 상태 Overview를 볼 수 있다. Warning Checks, Dangerous Checks를 기준으로 Grade와 Score을 측정한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2) Result by Catagory&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;1214&quot; data-origin-height=&quot;603&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7RRWK/btrvQfZ6GrK/9yPiSwxeJZtZpboGbpFDgk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7RRWK/btrvQfZ6GrK/9yPiSwxeJZtZpboGbpFDgk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7RRWK/btrvQfZ6GrK/9yPiSwxeJZtZpboGbpFDgk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7RRWK%2FbtrvQfZ6GrK%2F9yPiSwxeJZtZpboGbpFDgk%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;1214&quot; height=&quot;603&quot; data-origin-width=&quot;1214&quot; data-origin-height=&quot;603&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; font-family: 'Noto Serif KR';&quot;&gt;측정 결과는 아래 세가지 측면에서 판단한다.&lt;/span&gt;&lt;/p&gt;
&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: 'Noto Serif KR'; color: #000000;&quot;&gt;Efficiency(효율성) : Kubernetes에서 실행되는 워크로드에 대한 Resource 확인. Resource Request 및 Limit이 설정되어 있는지 여부와 지정된 범위 내에 구성되어 있는지 확인.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Reliability(신뢰성) : &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;Kubernetes의 안정성을 위한 구성이 적용되어 있는지 확인.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Security(보안성) : &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;Kubernetes에서 제공하는 보안 관련 구성이 적용되어 있는지 확인.&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;액세스 수준 제한 설정 확인.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Polaris는 Kubernetes 컴퓨팅 리소스의 효율성을 높여 클라우드에서 비용을 절약하거나 데이터 센터에서 용량을 절약할 수 있는 가이드라인을 제시한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;또한, Kubernetes는 기본적으로 안전하지 않으므로 Polaris는 보안 구성에 대해 여러 클러스터를 지속적으로 모니터링하여 컨테이너 및 Kubernetes의 취약사항을 찾아내, 우선 순위를 지정하고, 조치 방안을 제시한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;마지막으로 거버넌스를 일관되게 검사하고 적용하여 여러 클러스터에 대한 가시성을 확보한다.&amp;nbsp;발생 가능한 문제를 진단하여 서비스 중지 시간을 최소화할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;3) Filter by Namespace &amp;amp; Namespace&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;1224&quot; data-origin-height=&quot;911&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3Cc7V/btrvMIa9I0L/BF0ghc1KaLbgzZ50E6NYF0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3Cc7V/btrvMIa9I0L/BF0ghc1KaLbgzZ50E6NYF0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3Cc7V/btrvMIa9I0L/BF0ghc1KaLbgzZ50E6NYF0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3Cc7V%2FbtrvMIa9I0L%2FBF0ghc1KaLbgzZ50E6NYF0%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;1224&quot; height=&quot;911&quot; data-origin-width=&quot;1224&quot; data-origin-height=&quot;911&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: 'Noto Serif KR'; color: #000000;&quot;&gt;해당 클러스터 내 생성되어 있는 namespace를 지정하여 검사할 수 있다. 각각의 상세 내용은 Namesapce 항목을 펼쳐 확인한다. &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;1222&quot; data-origin-height=&quot;813&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/de5woQ/btrvRyZqYcI/lJK99bksDj7UQr3LGCMI6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/de5woQ/btrvRyZqYcI/lJK99bksDj7UQr3LGCMI6k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/de5woQ/btrvRyZqYcI/lJK99bksDj7UQr3LGCMI6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fde5woQ%2FbtrvRyZqYcI%2FlJK99bksDj7UQr3LGCMI6k%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;1222&quot; height=&quot;813&quot; data-origin-width=&quot;1222&quot; data-origin-height=&quot;813&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: 'Noto Serif KR'; color: #000000;&quot;&gt;위 사항 중 첫번째 Spec: &quot;Only one replica is scheduled&quot;를 해결하고 확인해 보도록 하자. 아래와 같이 replicas를 2로 변경하여 nginx를 기동하고 다시 deployment: my-nginx를 확인해 보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647166293150&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-84-159 minikube]# kubectl get pods
NAME                        READY   STATUS    RESTARTS        AGE
my-nginx-6645fdd559-524kw   1/1     Running   0               4s
my-nginx-6645fdd559-dkj56   1/1     Running   1 (4h15m ago)   12h
[root@ip-192-168-84-159 minikube]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;아래와 같이 Warning이 Spec: Multiple replicas are scheduled로 변경된 것을 확인할 수 있다.&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;1284&quot; data-origin-height=&quot;800&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kzdqI/btrvL4F36eg/acnKjTKRzn3UeczYyUImck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kzdqI/btrvL4F36eg/acnKjTKRzn3UeczYyUImck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kzdqI/btrvL4F36eg/acnKjTKRzn3UeczYyUImck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkzdqI%2FbtrvL4F36eg%2FacnKjTKRzn3UeczYyUImck%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;1284&quot; height=&quot;800&quot; data-origin-width=&quot;1284&quot; data-origin-height=&quot;800&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: 'Noto Serif KR'; color: #000000;&quot;&gt;다음으로 Dangerous도 조치를 해보도록 하자. Container my-nginx: &quot;Image tag should be specified&quot;는 Container를 기동하는 Image가 명시되어 있지 않거나, latest를 사용할 경우 변조 가능성이 있으므로 명확한 버전을 명시하라는 경고이다. 아래와 같이 nginx 이미지를 latest에서 1.21.6 버전으로 변경하고 반영한 결과이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; deployment.yaml&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647166891628&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
    # namespace: app-test
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx:1.21.6
        command: [&quot;/bin/bash&quot;]
        args: [&quot;-c&quot;, &quot;echo \&quot;&amp;lt;p&amp;gt;Hello from $(hostname)&amp;lt;/p&amp;gt;\&quot; &amp;gt; index.html; sleep 30000 &amp;amp;&amp;amp; python -m SimpleHTTPServer 8080&quot;]
        ports:
        - containerPort: 80&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; Pod restart&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647166837159&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-84-159 minikube]# kubectl get pods
NAME                        READY   STATUS        RESTARTS   AGE
my-nginx-594c77778-274vf    1/1     Terminating   0          113s
my-nginx-594c77778-drjn8    1/1     Terminating   0          109s
my-nginx-7b76897769-ts7p8   1/1     Running       0          7s
my-nginx-7b76897769-z2bn7   1/1     Running       0          11s
[root@ip-192-168-84-159 minikube]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;아래와 같이 Image Tag 관련 사항도 조치된 것을 확인할 수 있다.&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;1284&quot; data-origin-height=&quot;799&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cuORCZ/btrvOhdCEOI/f1fzswUY5koY55a0a3rlD1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cuORCZ/btrvOhdCEOI/f1fzswUY5koY55a0a3rlD1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cuORCZ/btrvOhdCEOI/f1fzswUY5koY55a0a3rlD1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcuORCZ%2FbtrvOhdCEOI%2Ff1fzswUY5koY55a0a3rlD1%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;1284&quot; height=&quot;799&quot; data-origin-width=&quot;1284&quot; data-origin-height=&quot;799&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;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Polaris CLI 활용&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Polaris CLI는 yaml 파일에 저장된 Kubernetes manifest를 감사하는데 사용할 수 있다. 이는 CI/CD 파이프라인의 일부로 Polaris를 실행하는데 사용할 수 있다. Polaris Score가 특정 임계값 아래로 떨어지거나 Dangerous Check가 발생하는 경우 CI/CD가 실패하도록 처리하여 yaml 파일에 대한 검증을 파이프라인에 통합할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1) Polaris CLI 설치&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647177104362&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; wget https://github.com/FairwindsOps/polaris/releases/download/v5.0.1/polaris_linux_amd64.tar.gz&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 바이너리를 직접 다운로드 받아 압축 해제 후 path에 포함되어 있는 /usr/local로 복사하는 것으로 사용 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2) Polaris audit&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647177182457&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-84-159 minikube]# polaris audit --help
Runs a one-time audit.

Usage:
  polaris audit [flags]

Flags:
      --audit-path string               If specified, audits one or more YAML files instead of a cluster.
      --color                           Whether to use color in pretty format. (default true)
      --display-name string             An optional identifier for the audit.
  -f, --format string                   Output format for results - json, yaml, pretty, or score. (default &quot;json&quot;)
      --helm-chart string               Will fill out Helm template
      --helm-values string              Optional flag to add helm values
  -h, --help                            help for audit
      --only-show-failed-tests          If specified, audit output will only show failed tests.
      --output-file string              Destination file for audit results.
      --output-url string               Destination URL to send audit results.
      --resource string                 Audit a specific resource, in the format namespace/kind/version/name, e.g. nginx-ingress/Deployment.apps/v1/default-backend.
      --set-exit-code-below-score int   Set an exit code of 4 when the score is below this threshold (1-100).
      --set-exit-code-on-danger         Set an exit code of 3 when the audit contains danger-level issues.

Global Flags:
  -c, --config string                    Location of Polaris configuration file.
      --disallow-annotation-exemptions   Disallow any exemption defined as a controller annotation.
      --disallow-config-exemptions       Disallow exemptions set within the configuration file.
      --disallow-exemptions              Disallow any configured exemption.
      --kubeconfig string                Paths to a kubeconfig. Only required if out-of-cluster.
      --log-level string                 Logrus log level. (default &quot;info&quot;)
[root@ip-192-168-84-159 minikube]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위 polaris audit 명령어를 통해 ci/cd pipeline에서 yaml 파일에 대한 검증을 수행할 수 있다. 활용 가능한 옵션으로는&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: 'Noto Serif KR'; color: #000000;&quot;&gt;--set-exit-code-on-danger : polaris 감사 결과 dangerous check가 있을 경우 exit code 3 return&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;--set-exit-code-below-score&amp;nbsp;: polaris score가 임계치 이하일 경우 exit code 4 return&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위 두가지 옵션을 포함하여 권고하는 옵션 조합은 아래와 같다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647178517280&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-84-159 minikube]# polaris audit --audit-path /root/minikube/deployment.yaml --set-exit-code-on-danger --set-exit-code-below-score 90 --only-show-failed-tests true --format=pretty


Polaris audited Path /root/minikube/deployment.yaml at 2022-03-13T13:37:23Z
    Nodes: 0 | Namespaces: 0 | Controllers: 1
    Final score: 55

Deployment my-nginx
  Container my-nginx
    memoryRequestsMissing                삱 Warning
        Efficiency - Memory requests should be set
    pullPolicyNotAlways                  삱 Warning
        Reliability - Image pull policy should be &quot;Always&quot;
    insecureCapabilities                 삱 Warning
        Security - Container should not have insecure capabilities
    notReadOnlyRootFilesystem            삱 Warning
        Security - Filesystem should be read only
    memoryLimitsMissing                  삱 Warning
        Efficiency - Memory limits should be set
    readinessProbeMissing                삱 Warning
        Reliability - Readiness probe should be configured
    runAsRootAllowed                     Danger
        Security - Should not be allowed to run as root
    cpuLimitsMissing                     삱 Warning
        Efficiency - CPU limits should be set
    privilegeEscalationAllowed           Danger
        Security - Privilege escalation should not be allowed
    cpuRequestsMissing                   삱 Warning
        Efficiency - CPU requests should be set
    livenessProbeMissing                 삱 Warning
        Reliability - Liveness probe should be configured


INFO[0000] 2 danger items found in audit                
[root@ip-192-168-84-159 minikube]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&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: 'Noto Serif KR'; color: #000000;&quot;&gt;--audit-path : 감사 대상 yaml 파일이 저장된 위치이다. 파일명 또는 디렉토리 지정이 가능하다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;--only-show-failed-tests : 실패한 테스트만 보여준다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;--format=pretty : 포맷을 정돈하여 보여준다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;위와 같이 2 danger items가 확인된 것을 알 수 있다. 해당 명령어 실행 결과를 확인해 보자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647178893263&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-84-159 minikube]# echo $?
3
[root@ip-192-168-84-159 minikube]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;exit code 3으로 끝난 것을 알 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Shell Script 또는 CLI 실행 결과에 대한 결과를 확인하는 exit code에는 Well-Known code가 있다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;exit code&amp;nbsp;0 : Successful completion of the command&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;exit code&amp;nbsp;1 : General unknown error&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;exit code&amp;nbsp;2 : Misuse of shell command&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;exit code&amp;nbsp;126 : The command can't execute&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;exit code&amp;nbsp;127 : Command not found&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;exit code&amp;nbsp;128 : Invalid exit argument&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;exit code&amp;nbsp;128+x : Fatal error with Linux signal x&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;exit code&amp;nbsp;130 : Command terminated with Ctrl-C&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;exit code&amp;nbsp;255 : Exit status out of range&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;그 밖의 범위는 사용자 정의에 의해 지정하여 사용할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;다음으로 --set-exit-code-on-danger 옵션을 빼고 감사 후 결과를 확인해 보자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647178979375&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-84-159 minikube]# polaris audit --audit-path /root/minikube/deployment.yaml --set-exit-code-below-score 90 --only-show-failed-tests true --format=pretty


Polaris audited Path /root/minikube/deployment.yaml at 2022-03-13T13:42:47Z
    Nodes: 0 | Namespaces: 0 | Controllers: 1
    Final score: 55

Deployment my-nginx
  Container my-nginx
    livenessProbeMissing                 삱 Warning
        Reliability - Liveness probe should be configured
    privilegeEscalationAllowed           Danger
        Security - Privilege escalation should not be allowed
    memoryLimitsMissing                  삱 Warning
        Efficiency - Memory limits should be set
    insecureCapabilities                 삱 Warning
        Security - Container should not have insecure capabilities
    memoryRequestsMissing                삱 Warning
        Efficiency - Memory requests should be set
    notReadOnlyRootFilesystem            삱 Warning
        Security - Filesystem should be read only
    cpuRequestsMissing                   삱 Warning
        Efficiency - CPU requests should be set
    pullPolicyNotAlways                  삱 Warning
        Reliability - Image pull policy should be &quot;Always&quot;
    readinessProbeMissing                삱 Warning
        Reliability - Readiness probe should be configured
    cpuLimitsMissing                     삱 Warning
        Efficiency - CPU limits should be set
    runAsRootAllowed                     Danger
        Security - Should not be allowed to run as root


INFO[0000] Audit score of 55 is less than the provided minimum of 90 
[root@ip-192-168-84-159 minikube]# echo $?
4
[root@ip-192-168-84-159 minikube]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;위와 같이 exit code 4로 끝난 것을 알 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;--set-exit-code-below-score 90 옵션까지 빼고 감사 후 결과를 확인해 보자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647179022913&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-84-159 minikube]# polaris audit --audit-path /root/minikube/deployment.yaml --only-show-failed-tests true --format=pretty


Polaris audited Path /root/minikube/deployment.yaml at 2022-03-13T13:43:30Z
    Nodes: 0 | Namespaces: 0 | Controllers: 1
    Final score: 55

Deployment my-nginx
  Container my-nginx
    insecureCapabilities                 삱 Warning
        Security - Container should not have insecure capabilities
    pullPolicyNotAlways                  삱 Warning
        Reliability - Image pull policy should be &quot;Always&quot;
    readinessProbeMissing                삱 Warning
        Reliability - Readiness probe should be configured
    runAsRootAllowed                     Danger
        Security - Should not be allowed to run as root
    livenessProbeMissing                 삱 Warning
        Reliability - Liveness probe should be configured
    cpuLimitsMissing                     삱 Warning
        Efficiency - CPU limits should be set
    cpuRequestsMissing                   삱 Warning
        Efficiency - CPU requests should be set
    privilegeEscalationAllowed           Danger
        Security - Privilege escalation should not be allowed
    memoryLimitsMissing                  삱 Warning
        Efficiency - Memory limits should be set
    memoryRequestsMissing                삱 Warning
        Efficiency - Memory requests should be set
    notReadOnlyRootFilesystem            삱 Warning
        Security - Filesystem should be read only


[root@ip-192-168-84-159 minikube]# echo $?
0
[root@ip-192-168-84-159 minikube]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 exit code가 0으로 성공하는 것을 확인할 수 있다. 이와 같이 dangerous check 발생 여부와 score를 통해 배포 전 CI 단계에서 yaml 파일의 안정성, 신뢰성을 검증할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이를 CI 도구(Jenkins, GitLabCI 등)에서 활용하는 것은 간단한 일이다. exit code가 정해져 있기 때문에 exit code 3 또는 exit code 4가 나올 경우 실패 처리하거나, exit code가 0이 아닌 경우 실패 처리하면 손쉽게 파이프라인을 관리하고, yaml 파일 검증과 CI를 통합할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;결론&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Polaris에서 권고하는 기본 내장된 RuleSet은 아래에서 확인 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://github.com/FairwindsOps/polaris/tree/master/checks&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/FairwindsOps/polaris/tree/master/checks&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1647167000027&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 - FairwindsOps/polaris: Validation of best practices in your Kubernetes clusters&quot; data-og-description=&quot;Validation of best practices in your Kubernetes clusters - GitHub - FairwindsOps/polaris: Validation of best practices in your Kubernetes clusters&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/FairwindsOps/polaris/tree/master/checks&quot; data-og-url=&quot;https://github.com/FairwindsOps/polaris&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bbq4Ly/hyNGNkUYA7/vZpyHO2VrOZVn77RgLDU40/img.png?width=1020&amp;amp;height=493&amp;amp;face=0_0_1020_493&quot;&gt;&lt;a href=&quot;https://github.com/FairwindsOps/polaris/tree/master/checks&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/FairwindsOps/polaris/tree/master/checks&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bbq4Ly/hyNGNkUYA7/vZpyHO2VrOZVn77RgLDU40/img.png?width=1020&amp;amp;height=493&amp;amp;face=0_0_1020_493');&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 - FairwindsOps/polaris: Validation of best practices in your Kubernetes clusters&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Validation of best practices in your Kubernetes clusters - GitHub - FairwindsOps/polaris: Validation of best practices in your Kubernetes clusters&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;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;때때로 놓치기 쉬운 보안 설정이나, 관리 측면에서 권고하는 여러 모범 사례를 기준으로 가이드라인을 제공해주는 Polaris를 활용하여 보다 안전하고, 활용도 높은 Kubernetes를 구축해 보도록 하자.&lt;/span&gt;&lt;/p&gt;</description>
      <category>③ 클라우드/ⓚ Kubernetes</category>
      <category>Kubernetes 보안</category>
      <category>Polaris</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/766</guid>
      <comments>https://waspro.tistory.com/766#entry766comment</comments>
      <pubDate>Sun, 13 Mar 2022 18:47:51 +0900</pubDate>
    </item>
    <item>
      <title>Kubernetes 활용성을 높이는 플러그인 &amp;amp; krew 패키지 매니저</title>
      <link>https://waspro.tistory.com/765</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Kubernetes Tools 활용&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Kubernetes는 수많은 api의 조합으로 이뤄져 있다. 이를 조합하여 Kubernetes를 효율적으로 운영할 수 있는 다양한 도구를 만들어 낼 수 있다. &lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;이미 수많은 플러그인이 개발되어 활용되고 있으며, 개발환경은 물론 운영환경에서도 효과적으로 사용할 수 있다. 지금부터는 Kubernetes를 사용하는 환경에 적용하기 용이한 플러그인들을 소개하고 직접 구축해 보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;kubectl krew&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;먼저 살펴볼 내용은 kubernetes cli 도구 kubectl의 플러그인을 관리하는 패키지 매니저 krew에 대해 알아보자. krew를 사용하면, 손쉽게 kubernetes 관련 플러그인들을 설치할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://github.com/kubernetes-sigs/krew&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/kubernetes-sigs/krew&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1646663275820&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 - kubernetes-sigs/krew:   Find and install kubectl plugins&quot; data-og-description=&quot;  Find and install kubectl plugins. Contribute to kubernetes-sigs/krew development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/kubernetes-sigs/krew&quot; data-og-url=&quot;https://github.com/kubernetes-sigs/krew&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bq9cgD/hyNC0EZRo4/vs7IsKrg5zmdq6vAseZkn0/img.png?width=3412&amp;amp;height=1706&amp;amp;face=0_0_3412_1706&quot;&gt;&lt;a href=&quot;https://github.com/kubernetes-sigs/krew&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/kubernetes-sigs/krew&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bq9cgD/hyNC0EZRo4/vs7IsKrg5zmdq6vAseZkn0/img.png?width=3412&amp;amp;height=1706&amp;amp;face=0_0_3412_1706');&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 - kubernetes-sigs/krew:   Find and install kubectl plugins&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;  Find and install kubectl plugins. Contribute to kubernetes-sigs/krew development by creating an account on GitHub.&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;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://krew.sigs.k8s.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://krew.sigs.k8s.io/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1646663399064&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;Krew &amp;ndash; kubectl plugin manager&quot; data-og-description=&quot;&amp;copy; 2022 The Kubernetes Authors. Krew is a Kubernetes SIG CLI project. Edit Page &amp;middot;&quot; data-og-host=&quot;krew.sigs.k8s.io&quot; data-og-source-url=&quot;https://krew.sigs.k8s.io/&quot; data-og-url=&quot;https://krew.sigs.k8s.io/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://krew.sigs.k8s.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://krew.sigs.k8s.io/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&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;Krew &amp;ndash; kubectl plugin manager&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;copy; 2022 The Kubernetes Authors. Krew is a Kubernetes SIG CLI project. Edit Page &amp;middot;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;krew.sigs.k8s.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: 'Noto Serif KR'; color: #000000;&quot;&gt;현재 130개가 넘는 kubectl 플러그인을 사용할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;a. 설치&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;아래와 같이 &quot;(&quot;부터 &quot;)&quot;까지 9줄 command 라인으로 원스탭으로 설치가 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1646663477521&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 ~ (kubeapp:default)]# (
  set -x; cd &quot;$(mktemp -d)&quot; &amp;amp;&amp;amp;
  OS=&quot;$(uname | tr '[:upper:]' '[:lower:]')&quot; &amp;amp;&amp;amp;
  ARCH=&quot;$(uname -m | sed -e 's/x86_64/amd64/' -e 's/\(arm\)\(64\)\?.*/\1\2/' -e 's/aarch64$/arm64/')&quot; &amp;amp;&amp;amp;
  KREW=&quot;krew-${OS}_${ARCH}&quot; &amp;amp;&amp;amp;
  curl -fsSLO &quot;https://github.com/kubernetes-sigs/krew/releases/latest/download/${KREW}.tar.gz&quot; &amp;amp;&amp;amp;
  tar zxvf &quot;${KREW}.tar.gz&quot; &amp;amp;&amp;amp;
  ./&quot;${KREW}&quot; install krew
)
++ mktemp -d
+ cd /tmp/tmp.DxLnkaVs48
++ uname
++ tr '[:upper:]' '[:lower:]'
+ OS=linux
++ uname -m
++ sed -e s/x86_64/amd64/ -e 's/\(arm\)\(64\)\?.*/\1\2/' -e 's/aarch64$/arm64/'
+ ARCH=amd64
+ KREW=krew-linux_amd64
+ curl -fsSLO https://github.com/kubernetes-sigs/krew/releases/latest/download/krew-linux_amd64.tar.gz
+ tar zxvf krew-linux_amd64.tar.gz
./LICENSE
./krew-linux_amd64
+ ./krew-linux_amd64 install krew
Adding &quot;default&quot; plugin index from https://github.com/kubernetes-sigs/krew-index.git.
Updated the local copy of plugin index.
Installing plugin: krew
Installed plugin: krew
\
 | Use this plugin:
 |      kubectl krew
 | Documentation:
 |      https://krew.sigs.k8s.io/
 | Caveats:
 | \
 |  | krew is now installed! To start using kubectl plugins, you need to add
 |  | krew's installation directory to your PATH:
 |  | 
 |  |   * macOS/Linux:
 |  |     - Add the following to your ~/.bashrc or ~/.zshrc:
 |  |         export PATH=&quot;${KREW_ROOT:-$HOME/.krew}/bin:$PATH&quot;
 |  |     - Restart your shell.
 |  | 
 |  |   * Windows: Add %USERPROFILE%\.krew\bin to your PATH environment variable
 |  | 
 |  | To list krew commands and to get help, run:
 |  |   $ kubectl krew
 |  | For a full list of available plugins, run:
 |  |   $ kubectl krew search
 |  | 
 |  | You can find documentation at
 |  |   https://krew.sigs.k8s.io/docs/user-guide/quickstart/.
 | /
/
[root@ip-192-168-78-195 ~ (kubeapp:default)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;b. 환경변수 적용&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1646663769481&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 ~ (kubeapp:default)]# export PATH=&quot;${KREW_ROOT:-$HOME/.krew}/bin:$PATH&quot;
[root@ip-192-168-78-195 ~ (kubeapp:default)]# kubectl krew
krew is the kubectl plugin manager.
You can invoke krew through kubectl: &quot;kubectl krew [command]...&quot;

Usage:
  kubectl krew [command]

Available Commands:
  completion  generate the autocompletion script for the specified shell
  help        Help about any command
  index       Manage custom plugin indexes
  info        Show information about an available plugin
  install     Install kubectl plugins
  list        List installed kubectl plugins
  search      Discover kubectl plugins
  uninstall   Uninstall plugins
  update      Update the local copy of the plugin index
  upgrade     Upgrade installed plugins to newer versions
  version     Show krew version and diagnostics

Flags:
  -h, --help      help for krew
  -v, --v Level   number for the log level verbosity

Use &quot;kubectl krew [command] --help&quot; for more information about a command.
[root@ip-192-168-78-195 ~ (kubeapp:default)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 손쉽게 설치가 완료된 것을 확인할 수 있다. 이후 아래 많은 도구 설치에서 krew를 통해 플러그인을 설치하는 과정에 대해서도 알아보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Multi Cluster 환경에 적용하기 용이한 Tools&lt;/span&gt;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1) kubectx(context 관리), kubens(namespace 관리)&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;kubectx, kubens는 하나의 도구 쌍으로 multi cluster에서 가장 많이 사용되는 도구이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;kubectx는 kubeconfig로 연동되어 있는 Context 목록을 확인할 수 있다. Context 변경을 원할 경우 kubectx [CONTEXT_NAME]로 변경이 가능하다. -c 옵션으로 CurrentContext를 확인할 수 있으며, -d 옵션으로 삭제할 수 있으며, - 옵션으로 이전 Context로 돌아온다. kubectx는 kubectl config get-contexts 명령어와 비슷하지만, set과 같은 일부 옵션을 지원하지 않는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;kubens는 현재 Context의 Namespace를 확인할 수 있다. Context의 Default Namespace 변경을 원할 경우 kubens [NAMESPACE_NAME]로 변경이 가능하다. -c 옵션으로 CurrentNamespace를 확인할 수 있으며, - 옵션으로 이전 Namespace로 돌아온다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;설치는 앞서 살펴본 krew를 통해 설치할 수 있으며, 폐쇄망 등을 고려하여 수동으로 설치도 가능하다. krew를 통해 설치할 경우 얼마나 간단히 구축이 가능한지 먼저 살펴보고 직접 수동으로 설치도 진행해 보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1646664318305&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt; kubectx 설치
[root@ip-192-168-78-195 ~ (kubeapp:default)]# kubectl krew install ctx
Updated the local copy of plugin index.
Installing plugin: ctx
Installed plugin: ctx
\
 | Use this plugin:
 |      kubectl ctx
 | Documentation:
 |      https://github.com/ahmetb/kubectx
 | Caveats:
 | \
 |  | If fzf is installed on your machine, you can interactively choose
 |  | between the entries using the arrow keys, or by fuzzy searching
 |  | as you type.
 |  | See https://github.com/ahmetb/kubectx for customization and details.
 | /
/
WARNING: You installed plugin &quot;ctx&quot; from the krew-index plugin repository.
   These plugins are not audited for security by the Krew maintainers.
   Run them at your own risk.
[root@ip-192-168-78-195 ~ (kubeapp:default)]#

&amp;gt; kubens 설치
[root@ip-192-168-78-195 ~ (kubeapp:default)]# kubectl krew install ns
Updated the local copy of plugin index.
Installing plugin: ns
Installed plugin: ns
\
 | Use this plugin:
 |      kubectl ns
 | Documentation:
 |      https://github.com/ahmetb/kubectx
 | Caveats:
 | \
 |  | If fzf is installed on your machine, you can interactively choose
 |  | between the entries using the arrow keys, or by fuzzy searching
 |  | as you type.
 | /
/
WARNING: You installed plugin &quot;ns&quot; from the krew-index plugin repository.
   These plugins are not audited for security by the Krew maintainers.
   Run them at your own risk.
[root@ip-192-168-78-195 ~ (kubeapp:default)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 kubectl krew ctx, kubectl krew ns 명령어 만으로 플러그인 설치가 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;a. git clone&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1646508817588&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 eks]# sudo git clone https://github.com/ahmetb/kubectx ./kubectx
Cloning into './kubectx'...
remote: Enumerating objects: 1457, done.
remote: Counting objects: 100% (172/172), done.
remote: Compressing objects: 100% (115/115), done.
remote: Total 1457 (delta 85), reused 97 (delta 51), pack-reused 1285
Receiving objects: 100% (1457/1457), 905.30 KiB | 1.75 MiB/s, done.
Resolving deltas: 100% (817/817), done.
[root@ip-192-168-78-195 eks]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;b. 권한부여&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1646508841076&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 kubectx]# chmod +x kube
kubectx  kubens   
[root@ip-192-168-78-195 kubectx]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;c. 복사&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1646508887652&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 kubectx]# cp kubectx /usr/local/sbin/
[root@ip-192-168-78-195 kubectx]# cp kubens /usr/local/sbin/
[root@ip-192-168-78-195 kubectx]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;d. kubectx 활용&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1646508979779&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 ~]# kubectl config get-contexts
CURRENT   NAME                                                          CLUSTER                                      AUTHINFO                                                      NAMESPACE
          eks-default                                                   NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io   iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io   kube-system
*         iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io   NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io   iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io   kube-system
          minikube                                                      minikube                                     minikube                                                      default
[root@ip-192-168-78-195 ~]# kubectx
eks-default
iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io
minikube
[root@ip-192-168-78-195 ~]# kubectx -c
iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io
[root@ip-192-168-78-195 ~]# kubectx minikube
Switched to context &quot;minikube&quot;.
[root@ip-192-168-78-195 ~]# kubectx -c
minikube
[root@ip-192-168-78-195 ~]# kubectl config get-contexts
CURRENT   NAME                                                          CLUSTER                                      AUTHINFO                                                      NAMESPACE
          eks-default                                                   NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io   iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io   kube-system
          iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io   NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io   iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io   kube-system
*         minikube                                                      minikube                                     minikube                                                      default
[root@ip-192-168-78-195 ~]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;e. kubens 활용&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1646509012411&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt; kubens 확인
[root@ip-192-168-78-195 ~]# kubectl config get-contexts
CURRENT   NAME                                                          CLUSTER                                      AUTHINFO                                                      NAMESPACE
          eks-default                                                   NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io   iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io   kube-system
          iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io   NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io   iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io   kube-system
*         minikube                                                      minikube                                     minikube                                                      default
[root@ip-192-168-78-195 ~]# kubectl get namespaces
NAME              STATUS   AGE
default           Active   8d
kube-node-lease   Active   8d
kube-public       Active   8d
kube-system       Active   8d
[root@ip-192-168-78-195 ~]# 

&amp;gt; minikube namespace 추가
[root@ip-192-168-84-159 ~]# kubectl apply -f namespace.yaml 
namespace/app-test created
[root@ip-192-168-84-159 ~]# 

&amp;gt; kubens 확인
[root@ip-192-168-78-195 app]# kubectl get namespaces
NAME              STATUS   AGE
app-test          Active   15s
default           Active   8d
kube-node-lease   Active   8d
kube-public       Active   8d
kube-system       Active   8d
[root@ip-192-168-78-195 app]# kubectl get pods
No resources found in default namespace.
[root@ip-192-168-78-195 app]# kubens
app-test
default
kube-node-lease
kube-public
kube-system
[root@ip-192-168-78-195 app]# kubens kube-system
Context &quot;minikube&quot; modified.
Active namespace is &quot;kube-system&quot;.
[root@ip-192-168-78-195 app]# kubectl get pods
NAME                                                                        READY   STATUS    RESTARTS        AGE
coredns-64897985d-25ndz                                                     1/1     Running   1 (7d14h ago)   8d
etcd-ip-192-168-84-159.ap-northeast-2.compute.internal                      1/1     Running   1 (7d14h ago)   8d
kube-apiserver-ip-192-168-84-159.ap-northeast-2.compute.internal            1/1     Running   1 (7d14h ago)   8d
kube-controller-manager-ip-192-168-84-159.ap-northeast-2.compute.internal   1/1     Running   1 (7d14h ago)   8d
kube-proxy-srclw                                                            1/1     Running   1 (7d14h ago)   8d
kube-scheduler-ip-192-168-84-159.ap-northeast-2.compute.internal            1/1     Running   1 (7d14h ago)   8d
storage-provisioner                                                         1/1     Running   2 (10h ago)     8d
[root@ip-192-168-78-195 app]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 kubens로 변경된 namespace를 default로 지정하여 해당 context내 사용할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2) kube_ps1(프롬프트 출력)&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;kube_ps1은 multi cluster 환경에서 사용자의 실수를 줄이고, 작업 시간을 단축시키기 위해 CurrentContext와 CurrentNamespace를 표시하는 명령어로 이를 PS1(Shell Prompt)에 적용하여 직관적으로 Shell 상에서 확인할 수 있도록 도와주는 Command이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;a. git clone&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1646543733855&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 eks]# git clone https://github.com/jonmosco/kube-ps1.git
Cloning into 'kube-ps1'...
remote: Enumerating objects: 585, done.
remote: Counting objects: 100% (20/20), done.
remote: Compressing objects: 100% (14/14), done.
remote: Total 585 (delta 10), reused 15 (delta 6), pack-reused 565
Receiving objects: 100% (585/585), 7.22 MiB | 10.36 MiB/s, done.
Resolving deltas: 100% (304/304), done.
[root@ip-192-168-78-195 eks]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2) .bashrc 추가 및 반영&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;# 주의 - 색상지원이 되지 않는 Shell에서는 아래와 같이 KUBE_PS1_XXX_COLOR 3개 환경변수를 null로 변경한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1646543815461&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt; .bashrc 추가
~~~~~
source ~/eks/kube-ps1/kube-ps1.sh
PS1='[\u@\h \W $(kube_ps1)]\$ '
KUBE_PS1_SYMBOL_ENABLE=false
KUBE_PS1_SYMBOL_COLOR=null
KUBE_PS1_CTX_COLOR=null
KUBE_PS1_NS_COLOR=null
~~~~~

&amp;gt; 반영
[root@ip-192-168-78-195 ~ ]# source ./.bashrc
[root@ip-192-168-78-195 ~ (kube:default)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;3) context name 변경&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1646545175006&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 ~ (kube:default)]# cat ~/.kube/config
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM1ekNDQWMrZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRJeU1ETXdOVEU1TURNd00xb1hEVE15TURNd01qRTVNRE13TTFvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTExPClZzZGV0Rk9rNzRNRXdHa1R2WGgzMXBMWG50TisvNDdLUzZIbno2dEJCWXJMMHNPaXV0MXQvQWRlcCs5ckNlZmsKNytKWUxNR3JnN3piUzZCUys0UGZ4eTMyMldiL2FNMXEyVGN3ZVRPZWtzdlcyejRjcGZEZE51dldsYWJyVFpPZgppZVJZVG1TMmkwWXpCL1ZPZ3Z5YjZPT3ZjejBHMnp1TVVsZkcrVWE5TDdNM3pIK1c1ZVllOThjVFlhM1hxdnZDCno0TFRBSmVJZndleENYanFOYjdWVDBQS3hTUGkvbnRpb2xFbFk1MnJXamhwSTVvNitUeFlJLzZoYVhFWFg4ZVYKblhMRUdlSU91a3RmSHl6MDUzaU9tdlVOMGU2UlFUMldQTUVWcEdHd3F4eEdNODVNS1I5TG1UYjAyQURlK01hYwpjV3V2SFJ4OUVXYmYrZXI5MWw4Q0F3RUFBYU5DTUVBd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0hRWURWUjBPQkJZRUZNY3NDTTAyU21kZ1JIbmZwMXd3WnR2MmtRZWdNQTBHQ1NxR1NJYjMKRFFFQkN3VUFBNElCQVFBZXZxT0k1d1VMOTNOeEt3bXhpYWUxQzQyeXRsaFJhRCtxdXV2NHVFZ1RwUUo0MXJTUgpQL2FLWUFzZmVBUmxCNnlXZDA2Tzl5UXVhOEF0QktTbEkxVHdUVjlUVVlSYnU2VHgwQ0RMTEczSU9aMXJLWUxBCjZtSGZyVFdHU0QwdXN5ejcxZDFiUzd6M2JjK2hRdnY3RkJzVGp0VHMvV2xRbjUrckdhanZLSTNNa0o1VEFBRlYKamQ0cUZIa1pWV3U5L0dWeUV0TndZdi9iWUdiYndTdzc2cWphQWFVY0c2dmxTNk9uNDFOdkVGTkx0dHZVRk0wegpxZFl6bHllaE5JNENJcUJ2aWtIZDVrOWw1QzlUVTlrWTJobE5KQUZVS2I1MXp3bTZ4bU9QREx5UjFoay80ZHM2CnpablQyZmNCQmszNHFGUTNGS1Q1WE5pbXZoQlRidHZucUx4TQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
    server: https://407B39524D80486F1EECD325C3180677.yl4.ap-northeast-2.eks.amazonaws.com
  name: NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io
contexts:
- context:
    cluster: NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io
    namespace: kube-system
    user: iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io
  name: eks-default
- context:
    cluster: NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io
    namespace: default
    user: iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io
  name: kube	=================&amp;gt; kubeapp으로 변경
current-context: kube
kind: Config
preferences: {}
users:
- name: iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io
  user:
    exec:
      apiVersion: client.authentication.k8s.io/v1alpha1
      args:
      - eks
      - get-token
      - --cluster-name
      - NRSON-EKS-CLUSTER
      - --region
      - ap-northeast-2
      command: aws
      env:
      - name: AWS_STS_REGIONAL_ENDPOINTS
        value: regional
[root@ip-192-168-78-195 ~ (kube:default)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 context name을 kube에서 kubeapp으로 변경할 아래와 같이 context를 변경함으로써 반영이 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1646545365020&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 ~ (kube:default)]# kubectx
eks-default
kubeapp
[root@ip-192-168-78-195 ~ (kube:default)]# kubectx -c
kube
[root@ip-192-168-78-195 ~ (kube:default)]# kubectx kubeapp
Switched to context &quot;kubeapp&quot;.
[root@ip-192-168-78-195 ~ (kubeapp:default)]#&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;유지보수에 용이한 Tools&lt;/span&gt;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1) neat(manifests 정돈)&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;neat는 kubernetes manifests를 깔끔하게 정돈하여 보여주는 kubectl 옵션이다. 이후는 가능하면 krew를 통해 설치과정을 간소화 하도록 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;a. 설치&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1646664919153&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 ~ (kubeapp:default)]# kubectl krew install neat
Updated the local copy of plugin index.
Installing plugin: neat
Installed plugin: neat
\
 | Use this plugin:
 |      kubectl neat
 | Documentation:
 |      https://github.com/itaysk/kubectl-neat
/
WARNING: You installed plugin &quot;neat&quot; from the krew-index plugin repository.
   These plugins are not audited for security by the Krew maintainers.
   Run them at your own risk.
[root@ip-192-168-78-195 ~ (kubeapp:default)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;b. kubectl get pods -o yaml vs kubectl neat&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;먼저 kubectl get pods -o yaml을 살펴보자. 적용한 deployment.yaml 파일은 아래와 같다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1646665341889&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
    # namespace: app-test
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 1
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx
        command: [&quot;/bin/bash&quot;]
        args: [&quot;-c&quot;, &quot;echo \&quot;&amp;lt;p&amp;gt;Hello from $(hostname)&amp;lt;/p&amp;gt;\&quot; &amp;gt; index.html; sleep 30000 &amp;amp;&amp;amp; python -m SimpleHTTPServer 8080&quot;]
        ports:
        - containerPort: 80&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;적용한 deployment.yaml 파일은 위와 같이 간단하지만, -o yaml 파일을 확인해 보면 아래와 같이 현재 status까지 함께 저장되서 출력되어 굉장히 길게 yaml 파일이 출력된다. 결국 이는 이후 유지보수 시점에 불필요한 yaml 파일의 내용을 제거하고 수정해야 하는 번거로움이 생긴다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1646665283370&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# kubectl get deployment my-nginx -o yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    deployment.kubernetes.io/revision: &quot;1&quot;
    kubectl.kubernetes.io/last-applied-configuration: |
      {&quot;apiVersion&quot;:&quot;apps/v1&quot;,&quot;kind&quot;:&quot;Deployment&quot;,&quot;metadata&quot;:{&quot;annotations&quot;:{},&quot;name&quot;:&quot;my-nginx&quot;,&quot;namespace&quot;:&quot;default&quot;},&quot;spec&quot;:{&quot;replicas&quot;:1,&quot;selector&quot;:{&quot;matchLabels&quot;:{&quot;run&quot;:&quot;my-nginx&quot;}},&quot;template&quot;:{&quot;metadata&quot;:{&quot;labels&quot;:{&quot;run&quot;:&quot;my-nginx&quot;}},&quot;spec&quot;:{&quot;containers&quot;:[{&quot;args&quot;:[&quot;-c&quot;,&quot;echo \&quot;\u003cp\u003eHello from $(hostname)\u003c/p\u003e\&quot; \u003e index.html; sleep 30000 \u0026\u0026 python -m SimpleHTTPServer 8080&quot;],&quot;command&quot;:[&quot;/bin/bash&quot;],&quot;image&quot;:&quot;nginx&quot;,&quot;name&quot;:&quot;my-nginx&quot;,&quot;ports&quot;:[{&quot;containerPort&quot;:80}]}]}}}}
  creationTimestamp: &quot;2022-03-07T15:00:07Z&quot;
  generation: 1
  managedFields:
  - apiVersion: apps/v1
    fieldsType: FieldsV1
    fieldsV1:
      f:metadata:
        f:annotations:
          .: {}
          f:kubectl.kubernetes.io/last-applied-configuration: {}
      f:spec:
        f:progressDeadlineSeconds: {}
        f:replicas: {}
        f:revisionHistoryLimit: {}
        f:selector: {}
        f:strategy:
          f:rollingUpdate:
            .: {}
            f:maxSurge: {}
            f:maxUnavailable: {}
          f:type: {}
        f:template:
          f:metadata:
            f:labels:
              .: {}
              f:run: {}
          f:spec:
            f:containers:
              k:{&quot;name&quot;:&quot;my-nginx&quot;}:
                .: {}
                f:args: {}
                f:command: {}
                f:image: {}
                f:imagePullPolicy: {}
                f:name: {}
                f:ports:
                  .: {}
                  k:{&quot;containerPort&quot;:80,&quot;protocol&quot;:&quot;TCP&quot;}:
                    .: {}
                    f:containerPort: {}
                    f:protocol: {}
                f:resources: {}
                f:terminationMessagePath: {}
                f:terminationMessagePolicy: {}
            f:dnsPolicy: {}
            f:restartPolicy: {}
            f:schedulerName: {}
            f:securityContext: {}
            f:terminationGracePeriodSeconds: {}
    manager: kubectl
    operation: Update
    time: &quot;2022-03-07T15:00:07Z&quot;
  - apiVersion: apps/v1
    fieldsType: FieldsV1
    fieldsV1:
      f:metadata:
        f:annotations:
          f:deployment.kubernetes.io/revision: {}
      f:status:
        f:availableReplicas: {}
        f:conditions:
          .: {}
          k:{&quot;type&quot;:&quot;Available&quot;}:
            .: {}
            f:lastTransitionTime: {}
            f:lastUpdateTime: {}
            f:message: {}
            f:reason: {}
            f:status: {}
            f:type: {}
          k:{&quot;type&quot;:&quot;Progressing&quot;}:
            .: {}
            f:lastTransitionTime: {}
            f:lastUpdateTime: {}
            f:message: {}
            f:reason: {}
            f:status: {}
            f:type: {}
        f:observedGeneration: {}
        f:readyReplicas: {}
        f:replicas: {}
        f:updatedReplicas: {}
    manager: kube-controller-manager
    operation: Update
    time: &quot;2022-03-07T15:00:16Z&quot;
  name: my-nginx
  namespace: default
  resourceVersion: &quot;362051&quot;
  uid: a4b0096f-9830-474c-add6-049ae870530d
spec:
  progressDeadlineSeconds: 600
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      run: my-nginx
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      creationTimestamp: null
      labels:
        run: my-nginx
    spec:
      containers:
      - args:
        - -c
        - echo &quot;&amp;lt;p&amp;gt;Hello from $(hostname)&amp;lt;/p&amp;gt;&quot; &amp;gt; index.html; sleep 30000 &amp;amp;&amp;amp; python
          -m SimpleHTTPServer 8080
        command:
        - /bin/bash
        image: nginx
        imagePullPolicy: Always
        name: my-nginx
        ports:
        - containerPort: 80
          protocol: TCP
        resources: {}
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: {}
      terminationGracePeriodSeconds: 30
status:
  availableReplicas: 1
  conditions:
  - lastTransitionTime: &quot;2022-03-07T15:00:16Z&quot;
    lastUpdateTime: &quot;2022-03-07T15:00:16Z&quot;
    message: Deployment has minimum availability.
    reason: MinimumReplicasAvailable
    status: &quot;True&quot;
    type: Available
  - lastTransitionTime: &quot;2022-03-07T15:00:07Z&quot;
    lastUpdateTime: &quot;2022-03-07T15:00:16Z&quot;
    message: ReplicaSet &quot;my-nginx-6c6c46694f&quot; has successfully progressed.
    reason: NewReplicaSetAvailable
    status: &quot;True&quot;
    type: Progressing
  observedGeneration: 1
  readyReplicas: 1
  replicas: 1
  updatedReplicas: 1
#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이를 kubectl neat를 통해 아래와 같이 yaml 파일을 추출할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1646665546112&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# kubectl get deployment my-nginx -o yaml | kubectl neat
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    deployment.kubernetes.io/revision: &quot;1&quot;
  name: my-nginx
  namespace: default
spec:
  progressDeadlineSeconds: 600
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      run: my-nginx
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      creationTimestamp: null
      labels:
        run: my-nginx
    spec:
      containers:
      - args:
        - -c
        - echo &quot;&amp;lt;p&amp;gt;Hello from $(hostname)&amp;lt;/p&amp;gt;&quot; &amp;gt; index.html; sleep 30000 &amp;amp;&amp;amp; python
          -m SimpleHTTPServer 8080
        command:
        - /bin/bash
        image: nginx
        imagePullPolicy: Always
        name: my-nginx
        ports:
        - containerPort: 80
          protocol: TCP
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      schedulerName: default-scheduler
      terminationGracePeriodSeconds: 30
#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 보다 간결하고 default 옵션으로 숨겨있던 주요 옵션까지 포함하여 yaml 파일을 추출할 수 있다. 물론 status 정보에 대해서는 제외하고 출력한다. 해당 옵션은 백업 시점의 상태 정보를 제외하고 출력하기 때문에 yaml 파일에 대한 검증이나, 타 환경에 이전 구축하는 용도로 사용하기 용이하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;다만, 현재 status를 기준으로 백업하고, 이후 동일한 상태로 복원하고자 할 경우에는 이전 -o yaml 옵션만으로 백업하는 것을 권장한다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2) kail(multi pod log 모니터링)&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;kubernetes와 같이 container 환경에서 반드시 고려되어야 하는 Telemetry 요소 중 특히 로깅 요소는 무엇보다 중요하다. 로깅은 개발단계에서부터 유용하게 활용이 가능한 Telemetry 컴포넌트로 대표적인 EFK를 통해 Visualize를 지원한다. 다만, 모든 환경에서 로그를 Visualize 할 수는 없으며, 때로는 CLI 환경에서 직접 로그를 확인하고자 하는 경우가 있다. 트러블슈팅을 지원하며, 동일 서비스내 Pod 로그를 통합으로 확인하고, 순서를 조합하여 보고자 하는 경우 등에 활용할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;a. 설치&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1646666570866&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 go (kubeapp:default)]# kubectl krew install tail
Updated the local copy of plugin index.
Installing plugin: tail
Installed plugin: tail
\
 | Use this plugin:
 |      kubectl tail
 | Documentation:
 |      https://github.com/boz/kail
/
WARNING: You installed plugin &quot;tail&quot; from the krew-index plugin repository.
   These plugins are not audited for security by the Krew maintainers.
   Run them at your own risk.
[root@ip-192-168-78-195 go (kubeapp:default)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;b. kail 활용&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1646667879308&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 go (kubeapp:default)]# kail
...
...
kube-logging/elasticsearch-master-745c995d88-ksldq[elasticsearch-master]: {&quot;type&quot;: &quot;server&quot;, &quot;timestamp&quot;: &quot;2022-03-07T15:41:50,374+0000&quot;, &quot;level&quot;: &quot;INFO&quot;, &quot;component&quot;: &quot;o.e.c.s.ClusterApplierService&quot;, &quot;cluster.name&quot;: &quot;elasticsearch&quot;, &quot;node.name&quot;: &quot;elasticsearch-master&quot;, &quot;cluster.uuid&quot;: &quot;w4yuNKxZRi2BxpDgrM37eg&quot;, &quot;node.id&quot;: &quot;4D8M6FE7Tsqmml7IaddNww&quot;,  &quot;message&quot;: &quot;added {{elasticsearch-client}{tHAltQHwSK-JAbfVGY-lTw}{DvjfXlbHQiubOqm2HdNCkw}{192.168.161.189}{192.168.161.189:9300}{i}{ml.machine_memory=8124866560, ml.max_open_jobs=20, xpack.installed=true},{elasticsearch-data}{lykb7kBAR5SvmTuSFs_O-g}{cgBjsrwIRWuIs2Ysf6kgkQ}{192.168.167.246}{192.168.167.246:9300}{d}{ml.machine_memory=8124866560, ml.max_open_jobs=20, xpack.installed=true},}, term: 1, version: 12, reason: Publication{term=1, version=12}&quot;  }
kube-logging/elasticsearch-master-745c995d88-ksldq[elasticsearch-master]: {&quot;type&quot;: &quot;server&quot;, &quot;timestamp&quot;: &quot;2022-03-07T15:41:50,412+0000&quot;, &quot;level&quot;: &quot;INFO&quot;, &quot;component&quot;: &quot;o.e.x.i.a.TransportPutLifecycleAction&quot;, &quot;cluster.name&quot;: &quot;elasticsearch&quot;, &quot;node.name&quot;: &quot;elasticsearch-master&quot;, &quot;cluster.uuid&quot;: &quot;w4yuNKxZRi2BxpDgrM37eg&quot;, &quot;node.id&quot;: &quot;4D8M6FE7Tsqmml7IaddNww&quot;,  &quot;message&quot;: &quot;adding index lifecycle policy [watch-history-ilm-policy]&quot;  }
kube-logging/elasticsearch-client-578dd48f84-lnmx8[elasticsearch-client]: {&quot;type&quot;: &quot;server&quot;, &quot;timestamp&quot;: &quot;2022-03-07T15:41:50,601+0000&quot;, &quot;level&quot;: &quot;INFO&quot;, &quot;component&quot;: &quot;o.e.x.m.e.l.LocalExporter&quot;, &quot;cluster.name&quot;: &quot;elasticsearch&quot;, &quot;node.name&quot;: &quot;elasticsearch-client&quot;, &quot;cluster.uuid&quot;: &quot;w4yuNKxZRi2BxpDgrM37eg&quot;, &quot;node.id&quot;: &quot;tHAltQHwSK-JAbfVGY-lTw&quot;,  &quot;message&quot;: &quot;waiting for elected master node [{elasticsearch-master}{4D8M6FE7Tsqmml7IaddNww}{2CWU2-ZqTeK1gCd6uklb0A}{192.168.144.190}{192.168.144.190:9300}{m}{ml.machine_memory=8124866560, ml.max_open_jobs=20, xpack.installed=true}] to setup local exporter [default_local] (does it have x-pack installed?)&quot;  }
kube-logging/elasticsearch-data-0[elasticsearch-data]: {&quot;type&quot;: &quot;server&quot;, &quot;timestamp&quot;: &quot;2022-03-07T15:41:50,642+0000&quot;, &quot;level&quot;: &quot;INFO&quot;, &quot;component&quot;: &quot;o.e.x.m.e.l.LocalExporter&quot;, &quot;cluster.name&quot;: &quot;elasticsearch&quot;, &quot;node.name&quot;: &quot;elasticsearch-data&quot;, &quot;cluster.uuid&quot;: &quot;w4yuNKxZRi2BxpDgrM37eg&quot;, &quot;node.id&quot;: &quot;lykb7kBAR5SvmTuSFs_O-g&quot;,  &quot;message&quot;: &quot;waiting for elected master node [{elasticsearch-master}{4D8M6FE7Tsqmml7IaddNww}{2CWU2-ZqTeK1gCd6uklb0A}{192.168.144.190}{192.168.144.190:9300}{m}{ml.machine_memory=8124866560, ml.max_open_jobs=20, xpack.installed=true}] to setup local exporter [default_local] (does it have x-pack installed?)&quot;  }
kube-logging/elasticsearch-client-578dd48f84-lnmx8[elasticsearch-client]: {&quot;type&quot;: &quot;server&quot;, &quot;timestamp&quot;: &quot;2022-03-07T15:41:50,928+0000&quot;, &quot;level&quot;: &quot;INFO&quot;, &quot;component&quot;: &quot;o.e.l.LicenseService&quot;, &quot;cluster.name&quot;: &quot;elasticsearch&quot;, &quot;node.name&quot;: &quot;elasticsearch-client&quot;, &quot;cluster.uuid&quot;: &quot;w4yuNKxZRi2BxpDgrM37eg&quot;, &quot;node.id&quot;: &quot;tHAltQHwSK-JAbfVGY-lTw&quot;,  &quot;message&quot;: &quot;license [1e86dffb-7ce3-40e5-b95f-e79a05cb5a40] mode [basic] - valid&quot;  }
kube-logging/elasticsearch-client-578dd48f84-lnmx8[elasticsearch-client]: {&quot;type&quot;: &quot;server&quot;, &quot;timestamp&quot;: &quot;2022-03-07T15:41:50,929+0000&quot;, &quot;level&quot;: &quot;INFO&quot;, &quot;component&quot;: &quot;o.e.x.s.s.SecurityStatusChangeListener&quot;, &quot;cluster.name&quot;: &quot;elasticsearch&quot;, &quot;node.name&quot;: &quot;elasticsearch-client&quot;, &quot;cluster.uuid&quot;: &quot;w4yuNKxZRi2BxpDgrM37eg&quot;, &quot;node.id&quot;: &quot;tHAltQHwSK-JAbfVGY-lTw&quot;,  &quot;message&quot;: &quot;Active license is now [BASIC]; Security is enabled&quot;  }
kube-logging/elasticsearch-client-578dd48f84-lnmx8[elasticsearch-client]: {&quot;type&quot;: &quot;server&quot;, &quot;timestamp&quot;: &quot;2022-03-07T15:41:50,973+0000&quot;, &quot;level&quot;: &quot;INFO&quot;, &quot;component&quot;: &quot;o.e.x.m.e.l.LocalExporter&quot;, &quot;cluster.name&quot;: &quot;elasticsearch&quot;, &quot;node.name&quot;: &quot;elasticsearch-client&quot;, &quot;cluster.uuid&quot;: &quot;w4yuNKxZRi2BxpDgrM37eg&quot;, &quot;node.id&quot;: &quot;tHAltQHwSK-JAbfVGY-lTw&quot;,  &quot;message&quot;: &quot;waiting for elected master node [{elasticsearch-master}{4D8M6FE7Tsqmml7IaddNww}{2CWU2-ZqTeK1gCd6uklb0A}{192.168.144.190}{192.168.144.190:9300}{m}{ml.machine_memory=8124866560, ml.max_open_jobs=20, xpack.installed=true}] to setup local exporter [default_local] (does it have x-pack installed?)&quot;  }
kube-logging/elasticsearch-data-0[elasticsearch-data]: {&quot;type&quot;: &quot;server&quot;, &quot;timestamp&quot;: &quot;2022-03-07T15:41:50,996+0000&quot;, &quot;level&quot;: &quot;INFO&quot;, &quot;component&quot;: &quot;o.e.l.LicenseService&quot;, &quot;cluster.name&quot;: &quot;elasticsearch&quot;, &quot;node.name&quot;: &quot;elasticsearch-data&quot;, &quot;cluster.uuid&quot;: &quot;w4yuNKxZRi2BxpDgrM37eg&quot;, &quot;node.id&quot;: &quot;lykb7kBAR5SvmTuSFs_O-g&quot;,  &quot;message&quot;: &quot;license [1e86dffb-7ce3-40e5-b95f-e79a05cb5a40] mode [basic] - valid&quot;  }
kube-logging/elasticsearch-data-0[elasticsearch-data]: {&quot;type&quot;: &quot;server&quot;, &quot;timestamp&quot;: &quot;2022-03-07T15:41:51,007+0000&quot;, &quot;level&quot;: &quot;INFO&quot;, &quot;component&quot;: &quot;o.e.x.s.s.SecurityStatusChangeListener&quot;, &quot;cluster.name&quot;: &quot;elasticsearch&quot;, &quot;node.name&quot;: &quot;elasticsearch-data&quot;, &quot;cluster.uuid&quot;: &quot;w4yuNKxZRi2BxpDgrM37eg&quot;, &quot;node.id&quot;: &quot;lykb7kBAR5SvmTuSFs_O-g&quot;,  &quot;message&quot;: &quot;Active license is now [BASIC]; Security is enabled&quot;  }
kube-logging/elasticsearch-data-0[elasticsearch-data]: {&quot;type&quot;: &quot;server&quot;, &quot;timestamp&quot;: &quot;2022-03-07T15:41:51,028+0000&quot;, &quot;level&quot;: &quot;INFO&quot;, &quot;component&quot;: &quot;o.e.x.m.e.l.LocalExporter&quot;, &quot;cluster.name&quot;: &quot;elasticsearch&quot;, &quot;node.name&quot;: &quot;elasticsearch-data&quot;, &quot;cluster.uuid&quot;: &quot;w4yuNKxZRi2BxpDgrM37eg&quot;, &quot;node.id&quot;: &quot;lykb7kBAR5SvmTuSFs_O-g&quot;,  &quot;message&quot;: &quot;waiting for elected master node [{elasticsearch-master}{4D8M6FE7Tsqmml7IaddNww}{2CWU2-ZqTeK1gCd6uklb0A}{192.168.144.190}{192.168.144.190:9300}{m}{ml.machine_memory=8124866560, ml.max_open_jobs=20, xpack.installed=true}] to setup local exporter [default_local] (does it have x-pack installed?)&quot;  }
kube-logging/elasticsearch-master-745c995d88-ksldq[elasticsearch-master]: {&quot;type&quot;: &quot;server&quot;, &quot;timestamp&quot;: &quot;2022-03-07T15:41:51,125+0000&quot;, &quot;level&quot;: &quot;INFO&quot;, &quot;component&quot;: &quot;o.e.l.LicenseService&quot;, &quot;cluster.name&quot;: &quot;elasticsearch&quot;, &quot;node.name&quot;: &quot;elasticsearch-master&quot;, &quot;cluster.uuid&quot;: &quot;w4yuNKxZRi2BxpDgrM37eg&quot;, &quot;node.id&quot;: &quot;4D8M6FE7Tsqmml7IaddNww&quot;,  &quot;message&quot;: &quot;license [1e86dffb-7ce3-40e5-b95f-e79a05cb5a40] mode [basic] - valid&quot;  }
kube-logging/elasticsearch-master-745c995d88-ksldq[elasticsearch-master]: {&quot;type&quot;: &quot;server&quot;, &quot;timestamp&quot;: &quot;2022-03-07T15:41:51,130+0000&quot;, &quot;level&quot;: &quot;INFO&quot;, &quot;component&quot;: &quot;o.e.x.s.s.SecurityStatusChangeListener&quot;, &quot;cluster.name&quot;: &quot;elasticsearch&quot;, &quot;node.name&quot;: &quot;elasticsearch-master&quot;, &quot;cluster.uuid&quot;: &quot;w4yuNKxZRi2BxpDgrM37eg&quot;, &quot;node.id&quot;: &quot;4D8M6FE7Tsqmml7IaddNww&quot;,  &quot;message&quot;: &quot;Active license is now [BASIC]; Security is enabled&quot;  }
kube-logging/elasticsearch-client-578dd48f84-lnmx8[elasticsearch-client]: {&quot;type&quot;: &quot;server&quot;, &quot;timestamp&quot;: &quot;2022-03-07T15:41:51,242+0000&quot;, &quot;level&quot;: &quot;INFO&quot;, &quot;component&quot;: &quot;o.e.x.m.e.l.LocalExporter&quot;, &quot;cluster.name&quot;: &quot;elasticsearch&quot;, &quot;node.name&quot;: &quot;elasticsearch-client&quot;, &quot;cluster.uuid&quot;: &quot;w4yuNKxZRi2BxpDgrM37eg&quot;, &quot;node.id&quot;: &quot;tHAltQHwSK-JAbfVGY-lTw&quot;,  &quot;message&quot;: &quot;waiting for elected master node [{elasticsearch-master}{4D8M6FE7Tsqmml7IaddNww}{2CWU2-ZqTeK1gCd6uklb0A}{192.168.144.190}{192.168.144.190:9300}{m}{ml.machine_memory=8124866560, ml.max_open_jobs=20, xpack.installed=true}] to setup local exporter [default_local] (does it have x-pack installed?)&quot;  }
kube-logging/elasticsearch-data-0[elasticsearch-data]: {&quot;type&quot;: &quot;server&quot;, &quot;timestamp&quot;: &quot;2022-03-07T15:41:51,252+0000&quot;, &quot;level&quot;: &quot;INFO&quot;, &quot;component&quot;: &quot;o.e.x.m.e.l.LocalExporter&quot;, &quot;cluster.name&quot;: &quot;elasticsearch&quot;, &quot;node.name&quot;: &quot;elasticsearch-data&quot;, &quot;cluster.uuid&quot;: &quot;w4yuNKxZRi2BxpDgrM37eg&quot;, &quot;node.id&quot;: &quot;lykb7kBAR5SvmTuSFs_O-g&quot;,  &quot;message&quot;: &quot;waiting for elected master node [{elasticsearch-master}{4D8M6FE7Tsqmml7IaddNww}{2CWU2-ZqTeK1gCd6uklb0A}{192.168.144.190}{192.168.144.190:9300}{m}{ml.machine_memory=8124866560, ml.max_open_jobs=20, xpack.installed=true}] to setup local exporter [default_local] (does it have x-pack installed?)&quot;  }
kube-logging/elasticsearch-master-745c995d88-ksldq[elasticsearch-master]: {&quot;type&quot;: &quot;server&quot;, &quot;timestamp&quot;: &quot;2022-03-07T15:41:53,041+0000&quot;, &quot;level&quot;: &quot;INFO&quot;, &quot;component&quot;: &quot;o.e.c.m.MetaDataCreateIndexService&quot;, &quot;cluster.name&quot;: &quot;elasticsearch&quot;, &quot;node.name&quot;: &quot;elasticsearch-master&quot;, &quot;cluster.uuid&quot;: &quot;w4yuNKxZRi2BxpDgrM37eg&quot;, &quot;node.id&quot;: &quot;4D8M6FE7Tsqmml7IaddNww&quot;,  &quot;message&quot;: &quot;[.monitoring-es-7-2022.03.07] creating index, cause [auto(bulk api)], templates [.monitoring-es], shards [1]/[0], mappings [_doc]&quot;  }
kube-logging/elasticsearch-master-745c995d88-ksldq[elasticsearch-master]: {&quot;type&quot;: &quot;server&quot;, &quot;timestamp&quot;: &quot;2022-03-07T15:41:54,352+0000&quot;, &quot;level&quot;: &quot;INFO&quot;, &quot;component&quot;: &quot;o.e.c.r.a.AllocationService&quot;, &quot;cluster.name&quot;: &quot;elasticsearch&quot;, &quot;node.name&quot;: &quot;elasticsearch-master&quot;, &quot;cluster.uuid&quot;: &quot;w4yuNKxZRi2BxpDgrM37eg&quot;, &quot;node.id&quot;: &quot;4D8M6FE7Tsqmml7IaddNww&quot;,  &quot;message&quot;: &quot;Cluster health status changed from [YELLOW] to [GREEN] (reason: [shards started [[.monitoring-es-7-2022.03.07][0]] ...]).&quot;  }
...
...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 별도로 옵션을 주지 않을 경우 클러스터 내 모든 pod를 대상으로 로깅을 찾는다. 그 밖에 아래와 같은 옵션으로 좀 더 범위를 좁혀 로깅할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;-l, --label LABEL-SELECTOR&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;match pods based on a&amp;nbsp;standard label selector&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;-p, --pod NAME&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;match pods by name&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;-n, --ns NAMESPACE-NAME&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;match pods in the given namespace&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;--svc NAME&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;match pods belonging to the given service&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;--rc NAME&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;match pods belonging to the given replication controller&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;--rs NAME&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;match pods belonging to the given replica set&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;-d, --deploy NAME&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;match pods belonging to the given deployment&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;--sts NAME&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;match pods belonging to the given statefulset&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;-j, --job NAME&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;match pods belonging to the given job&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;--node NODE-NAME&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;match pods running on the given node&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;--ing NAME&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;match pods belonging to services targeted by the given ingress&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;-c, --containers CONTAINER-NAME&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;restrict which containers logs are shown for&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;--ignore LABEL-SELECTOR&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Ignore pods that the selector matches. (default:&amp;nbsp;kail.ignore=true)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;--current-ns&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Match pods in the namespace specified in Kubernetes' &quot;current context&quot;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;--ignore-ns NAME&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Ignore pods in the given namespaces. Overridden by&amp;nbsp;--ns,&amp;nbsp;--current-ns. (default:&amp;nbsp;kube-system)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;3) sniff(tcpdump 생성)&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;sniff는 Pod 내 TCP Dump를 생성하는 명령어이다. 마이크로서비스를 개발할때 서비스간 네트워크 활동을 캡처하는데 활용하기 용이하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;a. 설치&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1646671897283&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 app (kubeapp:default)]# kubectl krew install sniff
Updated the local copy of plugin index.
Installing plugin: sniff
Installed plugin: sniff
\
 | Use this plugin:
 |      kubectl sniff
 | Documentation:
 |      https://github.com/eldadru/ksniff
 | Caveats:
 | \
 |  | This plugin needs the following programs:
 |  | * wireshark (optional, used for live capture)
 | /
/
WARNING: You installed plugin &quot;sniff&quot; from the krew-index plugin repository.
   These plugins are not audited for security by the Krew maintainers.
   Run them at your own risk.
[root@ip-192-168-78-195 app (kubeapp:default)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;b. sniff를 활용한 tcp dump 생성&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1646672341450&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 app (kubeapp:default)]# kubectl sniff my-nginx-6c6c46694f-qv69b 
INFO[0000] using tcpdump path at: '/root/.krew/store/sniff/v1.6.2/static-tcpdump' 
INFO[0000] no container specified, taking first container we found in pod. 
INFO[0000] selected container: 'my-nginx'               
INFO[0000] sniffing method: upload static tcpdump       
INFO[0000] sniffing on pod: 'my-nginx-6c6c46694f-qv69b' [namespace: 'default', container: 'my-nginx', filter: '', interface: 'any'] 
INFO[0000] uploading static tcpdump binary from: '/root/.krew/store/sniff/v1.6.2/static-tcpdump' to: '/tmp/static-tcpdump' 
INFO[0000] uploading file: '/root/.krew/store/sniff/v1.6.2/static-tcpdump' to '/tmp/static-tcpdump' on container: 'my-nginx' 
INFO[0000] executing command: '[/bin/sh -c test -f /tmp/static-tcpdump]' on container: 'my-nginx', pod: 'my-nginx-6c6c46694f-qv69b', namespace: 'default' 
INFO[0000] command: '[/bin/sh -c test -f /tmp/static-tcpdump]' executing successfully exitCode: '1', stdErr :'' 
INFO[0000] file not found on: '/tmp/static-tcpdump', starting to upload 
INFO[0000] verifying file uploaded successfully         
INFO[0000] executing command: '[/bin/sh -c test -f /tmp/static-tcpdump]' on container: 'my-nginx', pod: 'my-nginx-6c6c46694f-qv69b', namespace: 'default' 
INFO[0000] command: '[/bin/sh -c test -f /tmp/static-tcpdump]' executing successfully exitCode: '0', stdErr :'' 
INFO[0000] file found: ''                               
INFO[0000] file uploaded successfully                   
INFO[0000] tcpdump uploaded successfully                
INFO[0000] spawning wireshark!                          
INFO[0000] starting sniffer cleanup                     
INFO[0000] sniffer cleanup completed successfully       
Error: exec: &quot;wireshark&quot;: executable file not found in $PATH
[root@ip-192-168-78-195 app (kubeapp:default)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 아래 경로에 static-tcpdump 파일이 생성된 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1646672391053&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 app (kubeapp:default)]# ls -lah /root/.krew/store/sniff/v1.6.2/static-tcpdump
-rwxr-xr-x 1 root root 2.8M Mar  7 16:51 /root/.krew/store/sniff/v1.6.2/static-tcpdump
[root@ip-192-168-78-195 app (kubeapp:default)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;wireshark나 tshark 등이 구성되어 있을 경우 연동되어 tcp dump를 바로 기동할수도 있다. 유의할 점은 tcpdump 생성 시 파일이 덮어써지기 때문에 가능하면, sniff로 생성한 파일을 복사해 주는 shell script와 함께 사용하는 것을 권고한다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;4) tree(Object 간 소유권)&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;tree 플러그인은 kubernetes의 Object 간 소유권 관계를 정리하는 옵션이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;a. 설치&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1646673295282&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 app (kubeapp:default)]# kubectl krew install tree
Updated the local copy of plugin index.
Installing plugin: tree
Installed plugin: tree
\
 | Use this plugin:
 |      kubectl tree
 | Documentation:
 |      https://github.com/ahmetb/kubectl-tree
 | Caveats:
 | \
 |  | * For resources that are not in default namespace, currently you must
 |  |   specify -n/--namespace explicitly (the current namespace setting is not
 |  |   yet used).
 | /
/
WARNING: You installed plugin &quot;tree&quot; from the krew-index plugin repository.
   These plugins are not audited for security by the Krew maintainers.
   Run them at your own risk.
[root@ip-192-168-78-195 app (kubeapp:default)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;b. tree plugin 확인&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1646673487325&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 app (kubeapp:default)]# kubectl tree deployment my-nginx        
NAMESPACE  NAME                                 READY  REASON  AGE 
default    Deployment/my-nginx                  -              136m
default    ㄴ--ReplicaSet/my-nginx-6c6c46694f   -              136m
default      ㄴ--Pod/my-nginx-6c6c46694f-qv69b  True           136m
[root@ip-192-168-78-195 app (kubeapp:default)]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 Deployment &amp;gt; ReplicaSet &amp;gt; Pod의 소유권 관계를 Tree 구조로 표시해 준다. 이를 통해 오브젝트간 관계를 파악할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;5) kubespy (kubernetes object status monitoring)&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;kubespy는 kubernetes의 오브젝트에 대한 상태변화를 모니터링하는 도구이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;a. 설치&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647797003281&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-84-159 kubespy]# wget https://github.com/pulumi/kubespy/releases/download/v0.6.0/kubespy-v0.6.0-linux-amd64.tar.gz
--2022-03-16 09:34:08--  https://github.com/pulumi/kubespy/releases/download/v0.6.0/kubespy-v0.6.0-linux-amd64.tar.gz
Resolving github.com (github.com)... 15.164.81.167
Connecting to github.com (github.com)|15.164.81.167|:443... connected.
HTTP request sent, awaiting response... 302 Found
Location: https://objects.githubusercontent.com/github-production-release-asset-2e65be/149165150/0800f600-0a0f-11eb-932f-06ec8a7b8a47?X-Amz-Algorithm=AWS4-HMAC-SHA256&amp;amp;X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20220316%2Fus-east-1%2Fs3%2Faws4_request&amp;amp;X-Amz-Date=20220316T093408Z&amp;amp;X-Amz-Expires=300&amp;amp;X-Amz-Signature=c848a739784f0a6b314b6aa0de5042a8ccf1bdecffee1fd3c0354c74d5cbde7f&amp;amp;X-Amz-SignedHeaders=host&amp;amp;actor_id=0&amp;amp;key_id=0&amp;amp;repo_id=149165150&amp;amp;response-content-disposition=attachment%3B%20filename%3Dkubespy-v0.6.0-linux-amd64.tar.gz&amp;amp;response-content-type=application%2Foctet-stream [following]
--2022-03-16 09:34:08--  https://objects.githubusercontent.com/github-production-release-asset-2e65be/149165150/0800f600-0a0f-11eb-932f-06ec8a7b8a47?X-Amz-Algorithm=AWS4-HMAC-SHA256&amp;amp;X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20220316%2Fus-east-1%2Fs3%2Faws4_request&amp;amp;X-Amz-Date=20220316T093408Z&amp;amp;X-Amz-Expires=300&amp;amp;X-Amz-Signature=c848a739784f0a6b314b6aa0de5042a8ccf1bdecffee1fd3c0354c74d5cbde7f&amp;amp;X-Amz-SignedHeaders=host&amp;amp;actor_id=0&amp;amp;key_id=0&amp;amp;repo_id=149165150&amp;amp;response-content-disposition=attachment%3B%20filename%3Dkubespy-v0.6.0-linux-amd64.tar.gz&amp;amp;response-content-type=application%2Foctet-stream
Resolving objects.githubusercontent.com (objects.githubusercontent.com)... 185.199.110.133, 185.199.111.133, 185.199.108.133, ...
Connecting to objects.githubusercontent.com (objects.githubusercontent.com)|185.199.110.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 16761346 (16M) [application/octet-stream]
Saving to: [17;13Hkubespy-v0.6.0-linux-amd64.tar.gz[19;1H100%[=====================================================================================================================================================================&amp;gt;] 16,761,346  --.-K/s   in 0.1s

2022-03-16 09:34:08 (107 MB/s) - [21;35Hkubespy-v0.6.0-linux-amd64.tar.gz[21;70Hsaved [16761346/16761346]

[root@ip-192-168-84-159 kubespy]# tar -xzvf kubespy-v0.6.0-linux-amd64.tar.gz
LICENSE
README.md
kubespy
[root@ip-192-168-84-159 kubespy]# cp kubespy /usr/bin/
[root@ip-192-168-84-159 kubespy]# kubespy --help
Spy on your Kubernetes resources

Usage:
  kubespy [command]

Available Commands:
  changes     Displays changes made to a Kubernetes resource in real time. Emitted as JSON diffs
  help        Help about any command
  status      Displays changes to a Kubernetes resources's status in real time. Emitted as JSON diffs
  trace       Traces status of complex API objects
  version     Displays version information for this tool

Flags:
  -h, --help   help for kubespy

Use &quot;kubespy [command] --help&quot; for more information about a command.
[root@ip-192-168-84-159 kubespy]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;b. kubespy trace 활용&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;먼저 kubespy trace에 대해 알아보자. trace 옵션은 object의 상태 변화를 모니터링하는 옵션이다. 최초 my-nginx deployment를 추가할 경우 ADDED라는 Status로 표시된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647797099153&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-84-159 minikube]# kubespy trace deployment my-nginx
[ADDED apps/v1/Deployment]  default/my-nginx
    Rolling out Deployment revision 1
    [55;8HDeployment is currently available
    [56;8HRollout successful: new ReplicaSet marked 'available'

ROLLOUT STATUS:
- [Current rollout | Revision 1] [ADDED]  default/my-nginx-65cff45899
    [60;8HReplicaSet is available [2 Pods available of a 2 minimum]
       - [Ready] my-nginx-65cff45899-cmf4w
       - [Ready] my-nginx-65cff45899-kvv2t&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;현재 my-nginx의 기동 중인 상태이다. Pod 두개가 기동되어 Ready 상태로 운영중이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647797173046&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-84-159 minikube]# kubectl delete -f deployment.yaml
deployment.apps &quot;my-nginx&quot; deleted
[root@ip-192-168-84-159 minikube]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 my-nginx 어플리케이션을 삭제해 보자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647797217053&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-84-159 minikube]# kubespy trace deployment my-nginx
[DELETED apps/v1/Deployment]  default/my-nginx
    [61;8HDeployment does not have minimum replicas (0 out of 0)
    [59;8HDeployment has not begun to roll out the change

[61;4HWaiting for Deployment controller to create ReplicaSet&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 상태가 DELETE로 실시간 변하는 것을 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647797245950&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-84-159 minikube]# kubectl apply -f deployment.yaml
deployment.apps/my-nginx created
[root@ip-192-168-84-159 minikube]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;다시 위와 같이 my-nginx를 deploy 할 경우&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647797488757&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-84-159 minikube]# kubespy trace deployment my-nginx
[MODIFIED apps/v1/Deployment]  default/my-nginx
    Rolling out Deployment revision 1
    [61;8HDeployment is currently available
    [61;8HRollout successful: new ReplicaSet marked 'available'

ROLLOUT STATUS:
- [Current rollout | Revision 1] [MODIFIED]  default/my-nginx-65cff45899
    [61;8HReplicaSet is available [2 Pods available of a 2 minimum]
       - [Ready] my-nginx-65cff45899-kgs7l
       - [Ready] my-nginx-65cff45899-95zcc&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;MODIFIED 상태로 변경되는 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;c. kubespy status 활용&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;다음으로 kubespy status에 대해 알아보자. status 옵션은 kubernetes object의 status 변화를 yaml로 비교해서 출력한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647797576661&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata: 
  name: my-nginx
    # namespace: app-test
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 1
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx:1.21.6
        command: [&quot;/bin/bash&quot;]
        args: [&quot;-c&quot;, &quot;echo \&quot;&amp;lt;p&amp;gt;Hello from $(hostname)&amp;lt;/p&amp;gt;\&quot; &amp;gt; index.html; sleep 30000 &amp;amp;&amp;amp; python -m SimpleHTTPServer 8080&quot;]
        ports:
        - containerPort: 80&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 nginx:1.21.6 이미지를 사용하는 Deployment의 replicas를 1에서 2로 증가할 경우 모니터링 결과를 살펴보자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647797661534&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-84-159 minikube]# kubespy status apps/v1 Deployment my-nginx
Watching status of apps/v1 Deployment my-nginx
CREATED
{
  &quot;availableReplicas&quot;: 1,
  &quot;conditions&quot;: [
    {
      &quot;lastTransitionTime&quot;: &quot;2022-03-16T09:36:33Z&quot;,
      &quot;lastUpdateTime&quot;: &quot;2022-03-16T09:36:33Z&quot;,
      &quot;message&quot;: &quot;Deployment has minimum availability.&quot;,
      &quot;reason&quot;: &quot;MinimumReplicasAvailable&quot;,
      &quot;status&quot;: &quot;True&quot;,
      &quot;type&quot;: &quot;Available&quot;
    },
    {
      &quot;lastTransitionTime&quot;: &quot;2022-03-16T09:36:32Z&quot;,
      &quot;lastUpdateTime&quot;: &quot;2022-03-16T09:36:33Z&quot;,
      &quot;message&quot;: &quot;ReplicaSet \&quot;my-nginx-65cff45899\&quot; has successfully progressed.&quot;,
      &quot;reason&quot;: &quot;NewReplicaSetAvailable&quot;,
      &quot;status&quot;: &quot;True&quot;,
      &quot;type&quot;: &quot;Progressing&quot;
    }
  ],
  &quot;observedGeneration&quot;: 1,
  &quot;readyReplicas&quot;: 1,
  &quot;replicas&quot;: 1,
  &quot;updatedReplicas&quot;: 1
}
MODIFIED
MODIFIED
 {
   &quot;availableReplicas&quot;: 1,
   &quot;conditions&quot;: [
-    {
-      &quot;lastTransitionTime&quot;: &quot;2022-03-16T09:36:33Z&quot;,
-      &quot;lastUpdateTime&quot;: &quot;2022-03-16T09:36:33Z&quot;,
-      &quot;message&quot;: &quot;Deployment has minimum availability.&quot;,
-      &quot;reason&quot;: &quot;MinimumReplicasAvailable&quot;,
-      &quot;status&quot;: &quot;True&quot;,
-      &quot;type&quot;: &quot;Available&quot;
-    },
+    {
+      &quot;lastTransitionTime&quot;: &quot;2022-03-16T09:43:30Z&quot;,
+      &quot;lastUpdateTime&quot;: &quot;2022-03-16T09:43:30Z&quot;,
+      &quot;message&quot;: &quot;Deployment does not have minimum availability.&quot;,
+      &quot;reason&quot;: &quot;MinimumReplicasUnavailable&quot;,
+      &quot;status&quot;: &quot;False&quot;,
+      &quot;type&quot;: &quot;Available&quot;
+    }
   ],
-  &quot;observedGeneration&quot;: 1,
+  &quot;observedGeneration&quot;: 2,
   &quot;readyReplicas&quot;: 1,
   &quot;replicas&quot;: 1,
   &quot;updatedReplicas&quot;: 1
 }

MODIFIED
 {
   &quot;availableReplicas&quot;: 1,
   &quot;conditions&quot;: [
     {
       &quot;lastTransitionTime&quot;: &quot;2022-03-16T09:36:32Z&quot;,
       &quot;lastUpdateTime&quot;: &quot;2022-03-16T09:36:33Z&quot;,
       &quot;message&quot;: &quot;ReplicaSet &quot;my-nginx-65cff45899&quot; has successfully progressed.&quot;,
       &quot;reason&quot;: &quot;NewReplicaSetAvailable&quot;,
       &quot;status&quot;: &quot;True&quot;,
       &quot;type&quot;: &quot;Progressing&quot;
     },
     {
       &quot;lastTransitionTime&quot;: &quot;2022-03-16T09:43:30Z&quot;,
       &quot;lastUpdateTime&quot;: &quot;2022-03-16T09:43:30Z&quot;,
       &quot;message&quot;: &quot;Deployment does not have minimum availability.&quot;,
       &quot;reason&quot;: &quot;MinimumReplicasUnavailable&quot;,
       &quot;status&quot;: &quot;False&quot;,
       &quot;type&quot;: &quot;Available&quot;
     }
   ],
   &quot;observedGeneration&quot;: 2,
   &quot;readyReplicas&quot;: 1,
   &quot;replicas&quot;: 1,
   &quot;updatedReplicas&quot;: 1
+  &quot;unavailableReplicas&quot;: 1
 }

MODIFIED
 {
   &quot;availableReplicas&quot;: 1,
   &quot;conditions&quot;: [
     {
       &quot;lastTransitionTime&quot;: &quot;2022-03-16T09:36:32Z&quot;,
       &quot;lastUpdateTime&quot;: &quot;2022-03-16T09:36:33Z&quot;,
       &quot;message&quot;: &quot;ReplicaSet &quot;my-nginx-65cff45899&quot; has successfully progressed.&quot;,
       &quot;reason&quot;: &quot;NewReplicaSetAvailable&quot;,
       &quot;status&quot;: &quot;True&quot;,
       &quot;type&quot;: &quot;Progressing&quot;
     },
     {
       &quot;lastTransitionTime&quot;: &quot;2022-03-16T09:43:30Z&quot;,
       &quot;lastUpdateTime&quot;: &quot;2022-03-16T09:43:30Z&quot;,
       &quot;message&quot;: &quot;Deployment does not have minimum availability.&quot;,
       &quot;reason&quot;: &quot;MinimumReplicasUnavailable&quot;,
       &quot;status&quot;: &quot;False&quot;,
       &quot;type&quot;: &quot;Available&quot;
     }
   ],
   &quot;observedGeneration&quot;: 2,
   &quot;readyReplicas&quot;: 1,
-  &quot;replicas&quot;: 1,
+  &quot;replicas&quot;: 2,
   &quot;unavailableReplicas&quot;: 1,
-  &quot;updatedReplicas&quot;: 1
+  &quot;updatedReplicas&quot;: 2
 }
 MODIFIED
 {
-  &quot;availableReplicas&quot;: 1,
+  &quot;availableReplicas&quot;: 2,
   &quot;conditions&quot;: [
     {
       &quot;lastTransitionTime&quot;: &quot;2022-03-16T09:36:32Z&quot;,
       &quot;lastUpdateTime&quot;: &quot;2022-03-16T09:36:33Z&quot;,
       &quot;message&quot;: &quot;ReplicaSet &quot;my-nginx-65cff45899&quot; has successfully progressed.&quot;,
       &quot;reason&quot;: &quot;NewReplicaSetAvailable&quot;,
       &quot;status&quot;: &quot;True&quot;,
       &quot;type&quot;: &quot;Progressing&quot;
     },
     {
-      &quot;lastTransitionTime&quot;: &quot;2022-03-16T09:43:30Z&quot;,
+      &quot;lastTransitionTime&quot;: &quot;2022-03-16T09:43:31Z&quot;,
-      &quot;lastUpdateTime&quot;: &quot;2022-03-16T09:43:30Z&quot;,
+      &quot;lastUpdateTime&quot;: &quot;2022-03-16T09:43:31Z&quot;,
-      &quot;message&quot;: &quot;Deployment does not have minimum availability.&quot;,
+      &quot;message&quot;: &quot;Deployment has minimum availability.&quot;,
-      &quot;reason&quot;: &quot;MinimumReplicasUnavailable&quot;,
+      &quot;reason&quot;: &quot;MinimumReplicasAvailable&quot;,
-      &quot;status&quot;: &quot;False&quot;,
+      &quot;status&quot;: &quot;True&quot;,
       &quot;type&quot;: &quot;Available&quot;
     }
   ],
   &quot;observedGeneration&quot;: 2,
-  &quot;readyReplicas&quot;: 1,
+  &quot;readyReplicas&quot;: 2,
   &quot;replicas&quot;: 2,
-  &quot;unavailableReplicas&quot;: 1,
   &quot;updatedReplicas&quot;: 2
 }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 상태 변화가 감지되었을 때 status의 변화에 대해 실시간 변경 사항을 표시해 준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;d. kubespy changes 활용&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;kubespy changes는 kubespy status와 다르게 status 정보는 물론 전체 object 구성 정보의 변화를 감지하고 출력한다. kubespy가 yaml의 status를 비교하여 출력한다면, changes는 전체 yaml의 status를 비교하여 출력한다는 차이가 있다.&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;kubespy를 활용하면, 실시간 변화하는 Kubernetes Object를 CLI 환경에서 한눈에 모니터링하기 용이한 정보를 제공한다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>③ 클라우드/ⓚ Kubernetes</category>
      <category>kail</category>
      <category>krew</category>
      <category>kube-score</category>
      <category>kubectl neat</category>
      <category>kubectl plugin</category>
      <category>kubectx</category>
      <category>kubens</category>
      <category>kubespy</category>
      <category>kube_ps1</category>
      <category>sniff</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/765</guid>
      <comments>https://waspro.tistory.com/765#entry765comment</comments>
      <pubDate>Thu, 3 Mar 2022 00:21:37 +0900</pubDate>
    </item>
    <item>
      <title>Pod 생성 및 종료 관리 (Health Check &amp;amp; Graceful Shutdown)</title>
      <link>https://waspro.tistory.com/764</link>
      <description>&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;개요&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Pod는 Kubernetes에 어플리케이션을 배치하기 위한 최소 오브젝트 단위이다. 하나 이상의 컨테이너를 가질 수 있고, 짧은 라이프사이클을 통해 생성되고 삭제된다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;마이크로서비스와 같은 분산 환경에서 수 많은 Pod 들의 상태를 관리하는 것은 굉장히 어려운 일이다. 컨테이너로 세분화 된 어플리케이션은 잦은 상태 변화(Pod의 동작에 이상이 발생하거나, 상태가 변화할 경우)가 발생되며, 이에 따른 변화 요소를 수동으로 찾아가기 어렵기 때문에, 시스템이 스스로 감지하고 해결해야 하며, 이 모든 작업은 자동으로 수행될 수 있도록 구축해야 한다. 또한, 분산 시스템의 경우 실패 처리가 핵심이다. Container Management Platform은 시스템 상태를 감시하고 수행이 중지된 서비스를 다시 시작할 수 있어야하며, 때로는 애플리케이션을 강제로 종료하는 기능을 제공해야 한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;지금부터 Kubernetes에서 지원하는 Pod의 생성 및 종료 시점의 관리 방안에 대해 알아보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Pod 생성 관리 (Health Check)&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Kubernetes는 Pod가 시작될 때 Health Check 기능을 적용하여 보다 안전한 배포 프로세스를 구축할 수 있다. Health Check는 Readiness Probe, Liveness Probe, Startup Probe를 지원하며, 언제 어떤 Probe를 사용하는지, 구성은 어떻게 하는지 알아보자.&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Probe Handler&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;먼저 Probe는 HTTP, Execution 및 TCP 세 가지 유형으로 적용할 수 있다. 각각 Container를 구성하는 어플리케이션의 성향에 따라 적용할 수 있다.&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; font-family: 'Noto Serif KR';&quot;&gt;HTTPGetAction : Kubernetes는 지정한 URL을 호출하여 200 또는 300범위에서 HTTP 응답을 받으면 application을 정상으로 표시한다. 그렇지 않으면 비정상으로 표시된다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;ExecAction : Kubernetes는 컨테이너 내부에서 Command를 실행한다. Command가 종료 코드 0 즉 성공을 반환하면 컨테이너가 정상으로 표시되며, 그렇지 않을 경우 비정상으로 표시된다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;TCPSocketAction : Kubernetes가 지정된 포트에 TCP 연결을 시도한다. 연결에 성공할 경우 컨테이너는 정상적인 것으로 표시되며, 그렇지 않을 경우 비정상으로 표시된다. gRPC 또는 FTP 서비스에 적용이 용이하다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;또한, &lt;/span&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;각 Probe를 적용할 때 initialDelaySeconds 적용에 유의해야 한다. 특히 Liveness Probe가 실패할 경우 Container는 재 시작된다. 따라서 application이 서비스 준비가 완료될때까지 Probe Check기 시작되지 않도록 해야하며, 이는 initialDelaySeconds를 통해 해결할 수 있다. &lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;initialDelaySeconds를 사용하여 Container의 평균 기동 시간 동안 버퍼를 두고 Probe가 동작하도록 설정하는 것을 권고한다. 이는 startupProbe를 적용하여 대체할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;Probe Configure&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;Probe를 구성하는 주요 설정에 대해 알아보자.&lt;/span&gt;&lt;/span&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; font-family: 'Noto Serif KR';&quot;&gt;initialDelaySeconds : Probe가 시작되기 전 대기 시간으로 default는 0초이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;periodSeconds : Probe를 수행하는 빈도(초)로 기본값은 10초이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;timeoutSeconds : Probe 타임아웃 시간(초)으로 기본값은 1초이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;successThreshold : Probe가 실패한 후 성공으로 변경되기 위한 연속 성공횟수이다. 기본값은 1이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;failureThreshold : Probe가 실패하면 Kubernetes는 failureThreshold 횟수 만큼 Container 재시작을 시도한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;terminationGracePeriodSeconds : Probe가 failure 상태가 될 경우 컨테이너를 종료하는데 까지 걸리는 시간이다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;Liveness Probe&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;Liveness Probe를 통해 컨테이너를 언제 재시작해야 하는지 판단할수 있다. 예를 들어 container가 알 수 없는 원인으로 비정상 동작을 하거나, 교착상태에 빠졌을 경우 Liveness Probe를 통해 해당 Container를 재시작하고 일정 횟수 이상 실패할 경우 새로운 Pod로 교체한다.&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;1050&quot; data-origin-height=&quot;826&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfZuy7/btruHwJXDUR/nmv27ukpD8AxJDo2tlsAm1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfZuy7/btruHwJXDUR/nmv27ukpD8AxJDo2tlsAm1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfZuy7/btruHwJXDUR/nmv27ukpD8AxJDo2tlsAm1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfZuy7%2FbtruHwJXDUR%2Fnmv27ukpD8AxJDo2tlsAm1%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;1050&quot; height=&quot;826&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;826&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Liveness Probe가 정의되어 있지 않을 경우 기본 Success로 판단하게 되는데 application이 특정 이유로 인해 비정상 동작하더라도 프로세스는 계속 실행되고 있기 때문에 기본적으로 Kubernetes는 모든 것이 정상이라고 판단하고 트래픽을 지속적으로 유입하게 된다. Liveness Probe를 사용하여 Kubernetes는 application이 더 이상 요청을 처리하지 않음을 감지하고 문제가 되는 pod를 다시 시작하여 이와 같은 문제를 해소할 수 있다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1) ExecAction&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;다음은 livenessprobe execution를 테스트하기 위한 yaml 파일이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;html xml&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-exec
spec:
  containers:
  - name: liveness
    image: k8s.gcr.io/busybox
    args:
    - /bin/sh
    - -c
    - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
    livenessProbe:
      exec:
        command:
        - cat
        - /tmp/healthy
      initialDelaySeconds: 5
      periodSeconds: 5&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;livenessProbe를 정의하기 위해서는 livenessProbe.exec.command의 내용을 Container의 정상 여부를 검증할 수 있는 명령어로 정의해야 한다. 이는 각 어플리케이션 별로 상이하기 때문에 위 예시는 참고용으로 활용하면 될 듯하다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위 livenessProbe에는 /tmp/healthy 파일을 확인하는 cat command를 정의하고 파일이 있을 경우 success하는 시나리오이다. &quot;/bin/sh -c &quot;touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600&quot;와 같이 container 수명이 30초인 liveness container는 파일생성 &amp;gt; sleep 30초 &amp;gt; 파일삭제 &amp;gt; sleep 600초 순으로 동작한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위 예시는 PID 1로 기동되는 container를 강제로 다운 시켜 livenessProbe를 failure로 출력하도록 구성하였지만, 대체로 PID 1로 기동되는 cmd / entrypoint의 process에 대한 ping / ps 검증, http url response 검증 등이 대표적인 적용방안이 될 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;html xml&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 app]# kubectl describe pod liveness-exec 
Events:
Type Reason Age From Message 
---- ------ ---- ---- ------- 
Normal Scheduled 37s default-scheduler Successfully assigned default/liveness-exec to ip-192-168-186-60.ap-northeast-2.compute.internal 
Normal Pulling 36s kubelet, ip-192-168-186-60.ap-northeast-2.compute.internal Pulling image &quot;k8s.gcr.io/busybox&quot; 
Normal Pulled 35s kubelet, ip-192-168-186-60.ap-northeast-2.compute.internal Successfully pulled image &quot;k8s.gcr.io/busybox&quot; in 1.411412542s 
Normal Created 35s kubelet, ip-192-168-186-60.ap-northeast-2.compute.internal Created container liveness 
Normal Started 35s kubelet, ip-192-168-186-60.ap-northeast-2.compute.internal Started container liveness 
Warning Unhealthy 2s kubelet, ip-192-168-186-60.ap-northeast-2.compute.internal Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory
[root@ip-192-168-78-195 app]# kubectl describe pod liveness-exec 
Events: 
Type Reason Age From Message 
---- ------ ---- ---- ------- 
Normal Scheduled 79s default-scheduler Successfully assigned default/liveness-exec to ip-192-168-186-60.ap-northeast-2.compute.internal 
Normal Pulled 77s kubelet, ip-192-168-186-60.ap-northeast-2.compute.internal Successfully pulled image &quot;k8s.gcr.io/busybox&quot; in 1.411412542s 
Warning Unhealthy 34s (x3 over 44s) kubelet, ip-192-168-186-60.ap-northeast-2.compute.internal Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory 
Normal Killing 34s kubelet, ip-192-168-186-60.ap-northeast-2.compute.internal Container liveness failed liveness probe, will be restarted 
Normal Pulling 4s (x2 over 78s) kubelet, ip-192-168-186-60.ap-northeast-2.compute.internal Pulling image &quot;k8s.gcr.io/busybox&quot; 
Normal Pulled 3s kubelet, ip-192-168-186-60.ap-northeast-2.compute.internal Successfully pulled image &quot;k8s.gcr.io/busybox&quot; in 1.472326648s 
Normal Created 2s (x2 over 77s) kubelet, ip-192-168-186-60.ap-northeast-2.compute.internal Created container liveness 
Normal Started 2s (x2 over 77s) kubelet, ip-192-168-186-60.ap-northeast-2.compute.internal Started container liveness
[root@ip-192-168-78-195 app]#&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 initialDelaySeconds 초 만큼 대기 후 periodSeconds 마다 kubelet은 livenessProbe를 실행하며, 약 35초 경과 후 livenessProbe 실패가 발생한다. &quot;initialDelaySeconds 5초 + periodSeconds 5n초&quot;는 container 수명인 30초가 초과되는 시점에 파일이 삭제되므로 35초 시점에 실패가 발생하게되는 것이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이후 terminationGracePeriodSeconds (default 30초)만큼 대기 후 Pod를 재시작한다. 즉, Pod가 리스타트되는 시간은 총 75초 소요된다. (initialDelaySeconds + periodSeconds * n + terminationGracePeriodSeconds)&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;물론 restart가 3회 이상 수행될 경우 failureThreshold에 의해 Pod의 상태를 CrashLoopBackOff로 변경한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;html xml&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 app]# kubectl get pods -w 
NAME READY STATUS RESTARTS AGE 
liveness-exec 1/1 Running 0 2s 
liveness-exec 1/1 Running 1 77s 
liveness-exec 1/1 Running 2 2m32s&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2) HTTPGetAction&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;다음은 livenessprobe http를 테스트하기 위한 yaml 파일이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;html xml&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-http
spec:
  containers:
  - name: liveness
    image: k8s.gcr.io/liveness
    args:
    - /server
    livenessProbe:
      httpGet:
        path: /healthz
        port: 8080
        httpHeaders:
        - name: Custom-Header
          value: Awesome
      initialDelaySeconds: 3
      periodSeconds: 3&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;liveness-http 컨테이너는 초기 10초 간 /healthz에 대한 요청을 200으로 return하고, 이후 500으로 return하는 컨테이너이다. 초기 initialDelaySeconds 3초 후 periodSeconds 3초 마다 한번씩 probe를 실행하여 체크한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;html xml&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 app]# kubectl describe pod liveness-http 
Events: 
Type Reason Age From Message 
---- ------ ---- ---- ------- 
Normal Scheduled 15s default-scheduler Successfully assigned default/liveness-http to ip-192-168-186-60.ap-northeast-2.compute.internal 
Normal Pulling 15s kubelet, ip-192-168-186-60.ap-northeast-2.compute.internal Pulling image &quot;k8s.gcr.io/liveness&quot; 
Normal Pulled 12s kubelet, ip-192-168-186-60.ap-northeast-2.compute.internal Successfully pulled image &quot;k8s.gcr.io/liveness&quot; in 2.120377802s 
Normal Created 12s kubelet, ip-192-168-186-60.ap-northeast-2.compute.internal Created container liveness 
Normal Started 12s kubelet, ip-192-168-186-60.ap-northeast-2.compute.internal Started container liveness 
Warning Unhealthy 0s kubelet, ip-192-168-186-60.ap-northeast-2.compute.internal Liveness probe failed: HTTP probe failed with statuscode: 500 
[root@ip-192-168-78-195 app]#&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;즉 위와 같이 livenessProbe 실패는 초기 기동 완료 후 12초 경과 시점이 될 것이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;3) TCPSocketAction&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;다음은 livenessprobe tcp를 테스트하기 위한 yaml 파일이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;html xml&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;apiVersion: v1
kind: Pod
metadata:
  name: goproxy
  labels:
    app: goproxy
spec:
  containers:
  - name: goproxy
    image: k8s.gcr.io/goproxy:0.1
    ports:
    - containerPort: 8080
    readinessProbe:
      tcpSocket:
        port: 8080
      initialDelaySeconds: 5
      periodSeconds: 10
    livenessProbe:
      tcpSocket:
        port: 8080
      initialDelaySeconds: 15
      periodSeconds: 20&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;최초 15초 경과 후 20초에 한번씩 8080 port로 tcp 연결이 가능한지를 검증한다. 컨테이너 포트로의 연결을 실패할 경우 컨테이너를 재시작 한다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;Readiness Probe&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;Readiness Probe는 Pod 내에 배포한 application이 트래픽을 처리할 준비가 되었을 때 Kubernetes에게 알리도록 설계되어 있다. Kubernetes는 서비스가 포드로 트래픽을 보내도록 허용하기 전에 Readiness Probe가 정상적으로 준비되었는지 확인한다. Readiness Probe가 실패하면 성공하기 전까지 Pod로의 트래픽 전송을 중지하고 서비스 라우팅 대상에서 제외된다.&lt;/span&gt;&lt;br /&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;1050&quot; data-origin-height=&quot;826&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lTFHF/btrutlu14Vb/AIcB6ykS2mZ2ANFtDnOWkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lTFHF/btrutlu14Vb/AIcB6ykS2mZ2ANFtDnOWkk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lTFHF/btrutlu14Vb/AIcB6ykS2mZ2ANFtDnOWkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlTFHF%2Fbtrutlu14Vb%2FAIcB6ykS2mZ2ANFtDnOWkk%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;1050&quot; height=&quot;826&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;826&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Kubernetes는 Listen 되는 Port와 application이 기동되는데까지의 시간차이로 인한 일시적인 504 Bad Gateway와 같은 5xx 에러를 발생 시킬 수 있다. 또한, Pod가 확장되어 늘어날 경우 서비스 준비가 완료되기 전까지 트래픽을 수신하지 않아야 하지만 Kubernetes Service는 Container 내부의 프로세스가 시작되자 마자 트래픽을 전송한다. 이와 같은 경우 Readiness Probe를 적용하여 application이 완전히 시작되었는지를 확인한 후 트래픽을 수신함으로써 위와 같은 문제를 예방할 수 있다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Readiness Probe는 Liveness Probe와 동일하게 구성하고 동작한다. 다만, 차이점은 Liveness Probe는 컨테이너를 재기동한다는 점과 Readiness Probe는 트래픽을 차단한다는 점이다. 이를 이용하여 두 Probe를 함께 적용하는 것이 효과적이다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Startup Probe&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Startup Probe는 컨테이너 내의 application이 시작되었는지 확인한다. Startup Probe는 온전히 어플리케이션 기동에 집중한 Probe로 성공할때 까지 Liveness/Readiness Probe는 활성화 되지 않는다.(즉, 어플리케이션 기동에 다른 Probe가 방해되지 않도록 제어한다) 대체로, 초기 기동 시간이 오래 걸리는 작업인 Legacy 연동, Database 연동, 배치 처리, 초기 데이터 적재 등의 작업이 포함될 경우 StartupProbe를 적용하고, 기동이 완료된 이후부터 LivenessProbe/ReadinessProbe를 적용하여 관리한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;# 참조&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;LivenessProbe의 failureThreshold * periodSeconds를 통해 Container 관리가 가능하지만, 기동 시점에 한번 오래 동작하는 event로 인해 해당 시간과 빈도를 늘려두는 것은 이후 운영 시점의 민첩성에 문제가 될 수 있다. 따라서 StartupProbe를 적용하고 이후 운영단계에서는 LivenessProbe를 적용하는 것이 효과적이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;다음은 startupprobe를 테스트하기 위한 yaml 파일이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;html xml&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-http
spec:
  containers:
  - name: liveness
    image: k8s.gcr.io/liveness
    args:
    - /server
    ports:
    - name: liveness-port
      containerPort: 8080
      hostPort: 8080
    livenessProbe:
      httpGet:
        path: /healthz
        port: liveness-port
      failureThreshold: 1
      periodSeconds: 10
    startupProbe:
      httpGet:
        path: /healthz
        port: liveness-port
      failureThreshold: 30
      periodSeconds: 10&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;startupProbe는 Pod 초기 시작 시간을 delay 하기를 원할 경우 적용한다. initialDelaySeconds와 비슷하게 동작하며, Probe로 인한 교착상태를 방지하기 위해 적용한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;html xml&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 ~]# kubectl get pods -w 
NAME READY STATUS RESTARTS AGE 
liveness-http 0/1 Running 0 3s 
liveness-http 0/1 Running 0 10s 
liveness-http 1/1 Running 0 11s 
liveness-http 0/1 Running 1 22s 
liveness-http 0/1 Running 1 30s 
liveness-http 1/1 Running 1 31s 
liveness-http 0/1 Running 2 42s 
liveness-http 0/1 Running 2 50s 
liveness-http 1/1 Running 2 51s 
liveness-http 0/1 Running 3 62s 
liveness-http 0/1 Running 3 70s 
liveness-http 1/1 Running 3 70s 
liveness-http 0/1 Running 4 82s 
liveness-http 0/1 Running 4 90s 
liveness-http 1/1 Running 4 90s&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 초기 Pod 기동 시간이 startupProbe가 체크되는 10초 이후 이며, livenessProbe 10초 (다운) + &lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;startupProbe(기동딜레이) 10초 총 20초에 한번씩 Pod가 재기동 되고 있는 것을 확인할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Pod 종료 관리 (Graceful Shutdown)&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Kubernetes는 여러 노드에 걸쳐 Pod를 실행하기 위해 복사본을 만들고, 애플리케이션을 업데이트하고, 동시에 여러 버전의 애플리케이션을 실행할 수 있다. 이는 Kubernetes가 정상적으로 컨테이너를 종료할 수 있도록 지원한다. RollingUpdate로 배포하는 경우 Kubernetes는 새 Pod를 실행하는 동안 이전 포드를 Gracefully하게 종료한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;이때, Pod의 배포 시간과 다운타임 최소화를 통해 사용자에게 미치는 영향을 최소화하고 복구 시간을 최대한 빠르게 하기 위해 애플리케이션 종료를 안전하게 처리해야 한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;지금부터 Kubernetes에서 Pod를 종료하는 단계에 대해 알아보자.&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; font-family: 'Noto Serif KR';&quot;&gt;Pod Terminating : Pod가 &quot;Terminating&quot; 상태로 설정되고 모든 서비스의 endpoint에서 제거된다. 이 시점에서 Pod는 새 트래픽 수신을 중지하지만 Pod 내에서 실행 중인 요청은 정상적으로 처리된다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;PreStop Hook : preStop Hook이 실행된다. preStop Hook은 SIGTERM을 수신할 때 애플리케이션이 정상적으로 종료되지 않으면 이 Hook을 사용하여 정상적인 종료를 트리거할 수 있다. 대부분의 프로그램은 SIGTERM을 수신할 때 정상적으로 종료되지만 제어할 수 없는 시스템을 관리하는 경우 preStop 후크는 애플리케이션을 수정하지 않고 정상적인 종료를 트리거하는 좋은 방법이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;SIGTERM signal : Kubernetes는 Pod 내 컨테이너에 SIGTERM 신호를 보낸다. 이 신호는 컨테이너가 곧 종료될 것임을 알린다. 여기에는 오래 지속되는 연결(예: 데이터베이스 연결 또는 WebSocket 스트림)중지, Snapshot 저장 등이 포함될 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Grace Period : Kubernetes는 grace period 시간(terminationGracePeriodSeconds) 만큼 대기한다. Kubernetes는 preStop 후크가 완료될 때까지 기다리지 않고, 종료가 완료되기 전에 app이 종료되면 Kubernetes는 즉시 다음 단계로 이동한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;SIGKILL signal : SIGKILL 신호가 포드로 전송되고 포드가 제거된다. Grace Period 후에도 컨테이너가 계속 실행 중이면 SIGKILL 신호가 전송되어 강제로 제거된다. 이 시점에서 모든 Kubernetes 개체도 정리된다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;유의할 점은 preStop hook, grace Period 및 SIGTERM signal이 모두 병렬로 발생한다는 점이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;preStop과 postStart Hook Handler yaml은 아래와 같이 활용할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;html xml&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;apiVersion: v1
kind: Pod
metadata:
  name: lifecycle-demo
spec:
  containers:
  - name: lifecycle-demo-container
    image: nginx
    lifecycle:
      postStart:
        exec:
          command: [&quot;/bin/sh&quot;, &quot;-c&quot;, &quot;echo Hello from the postStart handler &amp;gt; /usr/share/message&quot;]
      preStop:
        exec:
          command: [&quot;/bin/sh&quot;,&quot;-c&quot;,&quot;nginx -s quit; while killall -0 nginx; do sleep 1; done&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;위와 같이 postStart는 Container 기동 이후 /usr/share/message 파일에 Hello from the postStart handler를 작성한다. preStop은 Container가 종료되기 직전 nginx -s quit으로 현재 연결되어 있는 사용자의 요청이 완료되도록 대기하고, 요청이 완료되면 nginx를 종료한다. 이후 killall -0으로 nginx 프로세스가 종료되었는지 확인한다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;PostStart : 이 Hook은 컨테이너가 생성된 직후에 실행된다. 그러나, Hook이 컨테이너 엔트리포인트에 앞서서 실행된다는 보장은 없다. 파라미터는 핸들러에 전달되지 않는다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;PreStop : 이 Hook은 API 요청이나 liveness probe 실패, 자원 경합 등의 관리 이벤트로 인해 컨테이너가 종료되기 직전에 호출된다. 컨테이너가 이미 terminated 또는 completed 상태인 경우에는 PreStop Hook 요청이 실패하며, Hook은 컨테이너를 중지하기 위한 TERM 신호가 보내지기 이전에 완료되어야 한다. 어떠한 파라미터도 핸들러에게 전달되지 않는다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;결론&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Kubernetes는 이미 훌륭한 완전 관리형 Container Management Platform이지만, 여전히 다양한 상황에서 고려되어야 할 부분들이 존재한다. 특히 어플리케이션을 배포하는 Pod의 기동/종료를 관리하는 것은 무엇보다 중요한 고려사항일 것이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Kubernetes는 다양한 이유로 포드가 종료될 수 있으며 애플리케이션이 이러한 종료를 정상적으로 처리하도록 하는 것은 안정적인 시스템을 만들고 우수한 사용자 경험을 제공하는 핵심요소이다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>③ 클라우드/ⓚ Kubernetes</category>
      <category>failureThreshold</category>
      <category>initialDelaySeconds</category>
      <category>livenessProbe</category>
      <category>periodSeconds</category>
      <category>poststart</category>
      <category>prestop</category>
      <category>readinessProbe</category>
      <category>startupprobe</category>
      <category>terminationGracePeriodSeconds</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/764</guid>
      <comments>https://waspro.tistory.com/764#entry764comment</comments>
      <pubDate>Sun, 27 Feb 2022 23:16:08 +0900</pubDate>
    </item>
    <item>
      <title>Kubernetes Context (Multi Cluster 접근관리)</title>
      <link>https://waspro.tistory.com/763</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;개요&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Kubernetes는 Cluster, User, Namespace를 조합한 Context라는 오브젝트를 제공한다. Context는 독립적인 단위로 흔히 우리가 생각하는 클러스터를 Context 단위로 볼 수도 있지만, 사실 그보다 더 세분화된 단위라고 볼 수 있다. &lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이번 포스팅에서는 멀티 Cluster 환경에 각 클러스터에 보다 빠르게 접근하여 변경을 관리할 수 있는 Context 적용&lt;span style=&quot;color: #000000;&quot;&gt; 방법에 대해 알아보도록 하자.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;멀티 클러스터 접근 구성&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Kubernetes 클러스터를 처음 설정할 때 $HOME/.kube 디렉토리에 config 파일이 생성된다. config 파일은 우리가 흔히 이야기 하는 kubeconfig 파일이며, Kubernetes 클러스터와의 연결에 대한 정보를 저장하는데 사용된다. kubectl을 사용하여 명령을 실행하면 이 kubeconfig 파일을 통해 연결 정보를 얻어 온다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;kubeconfig 파일에는 클러스터 정보를 포함하여 user id/pw, 인증서 또는 token과 같은 인증 정보와 context를 함께 저장한다. &lt;/span&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;context는 앞서 정의를 내렸지만, 클러스터 액세스 정보를 그룹화한 것이라 할 수 있다. 따라서 context에는 cluster, user 및 namespace가 포함된다.&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;1350&quot; data-origin-height=&quot;843&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wu7xe/btrunPpZZJo/2U2FPhnhjQIcYrn70PfRi1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wu7xe/btrunPpZZJo/2U2FPhnhjQIcYrn70PfRi1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wu7xe/btrunPpZZJo/2U2FPhnhjQIcYrn70PfRi1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fwu7xe%2FbtrunPpZZJo%2F2U2FPhnhjQIcYrn70PfRi1%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;1350&quot; height=&quot;843&quot; data-origin-width=&quot;1350&quot; data-origin-height=&quot;843&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: 'Noto Serif KR'; color: #000000;&quot;&gt;앞서 언급한데로 Context는 Cluster와 비슷한 개념으로 동작하지만, Cluster 내에 User와 Namespace를 기준으로 여러 Context로 구분하여 관리도 가능하다. 즉 NRSON-EKS-CLUSTER내에 여러개의 Context를 생성하고, User별로 접근 권한을 분리하여, 하나의 Cluster를 여러개의 논리적인 Cluster로 동작하게 관리할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1. 사전준비 구성&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;멀티 클러스터를 테스트하기 위해 아래와 같이 AWS EKS와 MINIKUBE를 사전 구성해 둔 상태로 context 테스트를 진행한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1645820125991&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[AWS EKS]
[root@ip-192-168-78-195 ~]# kubectl config get-contexts
CURRENT   NAME                                                          CLUSTER                                      AUTHINFO                                                      NAMESPACE
*         iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io   NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io   iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io   
[root@ip-192-168-78-195 ~]#

[MINIKUBE]
[root@ip-192-168-84-159 ~]# kubectl config get-contexts
CURRENT   NAME                                                          CLUSTER                                      AUTHINFO                                                      NAMESPACE
*         minikube                                                      minikube                                     minikube                                                      default
[root@ip-192-168-84-159 ~]#&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2. &lt;span style=&quot;color: #000000;&quot;&gt;kubeconfig &lt;/span&gt;복사&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;kubenetes는 클러스터 구축 시점에 ~/.kube/config 파일을 생성한다. multi cluster 환경에서 각각 생성된 파일을 아래와 같이 kubeconfig2라는 파일이름으로 복사한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1645820327667&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 .kube]# ls -al
total 36
drwxr-xr-x  4 root root   131 Feb 25 19:59 .
dr-xr-x--- 12 root root   323 Feb 25 19:57 ..
drwxr-x---  3 root root    23 Jan 25 07:30 cache
-rw-------  1 root root  2330 Feb 25 19:59 config
-rw-------  1 root root     0 Jan 25 07:24 config.eksctl.lock
drwxr-x---  3 root root 16384 Feb 25 20:17 http-cache
-rw-r--r--  1 root root  3057 Feb 25 19:04 kubeconfig2
[root@ip-192-168-78-195 .kube]#&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: 'Noto Serif KR'; color: #000000;&quot;&gt;config : AWS EKS kubeconfig&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;kubeconfig2 : MINIKUBE kubeconfig&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;3. kubeconfig 파일 반영&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;두개의 서로 다른 kubeconfig 파일을 아래와 같이 반영 후 context를 확인한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1645820559452&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 .kube]# export KUBECONFIG=~/.kube/config:~/.kube/kubeconfig2
[root@ip-192-168-78-195 .kube]# env | grep KUBECONFIG
KUBECONFIG=/root/.kube/config:/root/.kube/kubeconfig2
[root@ip-192-168-78-195 .kube]# kubectl config get-contexts
CURRENT   NAME                                                          CLUSTER                                      AUTHINFO                                                      NAMESPACE
*         iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io   NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io   iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io   
          minikube                                                      minikube                                     minikube                                                      default
[root@ip-192-168-78-195 .kube]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 kubeconfig2로 추가한 minikube context가 추가된 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;4. 현재 context 확인 (kubectl config current-context)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;현재 사용 중인 context는 다음과 같이 확인할 수 있다.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1645820877754&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 .kube]# kubectl config current-context
iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io
[root@ip-192-168-78-195 .kube]#&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;5. 전체 context 리스트 (kubectl config get-contexts)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;전체 context 리스트는 다음과 같이 확인한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1645821010883&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 .kube]# kubectl config get-contexts
CURRENT   NAME                                                          CLUSTER                                      AUTHINFO                                                      NAMESPACE
*         iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io   NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io   iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io   
          minikube                                                      minikube                                     minikube                                                      default
[root@ip-192-168-78-195 .kube]#&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;6. context 변경 (kubectl config use-context minikube)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;아래와 같이 context name을 기준으로 context를 변경할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1645821085459&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 .kube]# kubectl get nodes
NAME                                                 STATUS   ROLES    AGE   VERSION
ip-192-168-109-189.ap-northeast-2.compute.internal   Ready    &amp;lt;none&amp;gt;   93m   v1.21.5-eks-9017834
ip-192-168-129-19.ap-northeast-2.compute.internal    Ready    &amp;lt;none&amp;gt;   93m   v1.21.5-eks-9017834
[root@ip-192-168-78-195 .kube]# kubectl config use-context minikube
Switched to context &quot;minikube&quot;.
[root@ip-192-168-78-195 .kube]# kubectl config get-contexts
CURRENT   NAME                                                          CLUSTER                                      AUTHINFO                                                      NAMESPACE
          iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io   NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io   iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io   
*         minikube                                                      minikube                                     minikube                                                      default
[root@ip-192-168-78-195 .kube]# kubectl config current-context
minikube
[root@ip-192-168-78-195 .kube]# kubectl get nodes
NAME                                                STATUS   ROLES                  AGE    VERSION
ip-192-168-84-159.ap-northeast-2.compute.internal   Ready    control-plane,master   100m   v1.23.3
[root@ip-192-168-78-195 .kube]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 하나의 노드에서 multi cluster에 접근하기 위한 구성을 손쉽게 진행할 수 있다. context를 변경하기 전과 후의 nodes 정보를 통해 서로 다른 cluster에 접근한 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;7. kubeconfig 확인 (kubectl config view)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;kubeconfig는 아래와 같이 3가지 구성요소로 kubeconfig가 구성된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1645821503267&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 .kube]# kubectl config view
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: DATA+OMITTED
    server: https://D521C278FE3ABBAFA91D288C8490A4D0.gr7.ap-northeast-2.eks.amazonaws.com
  name: NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io
- cluster:
    certificate-authority: /root/.minikube/ca.crt
    extensions:
    - extension:
        last-update: Fri, 25 Feb 2022 18:52:48 UTC
        provider: minikube.sigs.k8s.io
        version: v1.25.2
      name: cluster_info
    server: https://192.168.84.159:8443
  name: minikube
contexts:
- context:
    cluster: NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io
    user: iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io
  name: iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io
- context:
    cluster: minikube
    extensions:
    - extension:
        last-update: Fri, 25 Feb 2022 18:52:48 UTC
        provider: minikube.sigs.k8s.io
        version: v1.25.2
      name: context_info
    namespace: default
    user: minikube
  name: minikube
current-context: iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io
kind: Config
preferences: {}
users:
- name: iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io
  user:
    exec:
      apiVersion: client.authentication.k8s.io/v1alpha1
      args:
      - eks
      - get-token
      - --cluster-name
      - NRSON-EKS-CLUSTER
      - --region
      - ap-northeast-2
      command: aws
      env:
      - name: AWS_STS_REGIONAL_ENDPOINTS
        value: regional
- name: minikube
  user:
    client-certificate: /root/.minikube/profiles/minikube/client.crt
    client-key: /root/.minikube/profiles/minikube/client.key
[root@ip-192-168-78-195 .kube]#&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: 'Noto Serif KR'; color: #000000;&quot;&gt;cluster : kubernetes로 구성되어 있는 클러스터 정보. Private은 물론, Public CSP Service, MSP Managed PaaS를 모두 포함한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;user : cluster에 접근하기 위한 user 정보. ID/PW, 인증서, Token 인증 등을 통해 Cluster에 접근할 수 있다. 인증서로 로그인하는 경우 해당 인증서 파일을 복사해야 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;context : user, cluster, namespace 정보를 기준으로 context 단위를 생성하며, context 단위별로 multi cluster를 운영할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;현재 사용중인 context의 정보만 확인하고자 할 경우에는 &quot;--minify&quot;을 붙여 준다.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1645822243051&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 .kube]# kubectl config view --minify
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: DATA+OMITTED
    server: https://D521C278FE3ABBAFA91D288C8490A4D0.gr7.ap-northeast-2.eks.amazonaws.com
  name: NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io
contexts:
- context:
    cluster: NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io
    user: iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io
  name: iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io
current-context: iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io
kind: Config
preferences: {}
users:
- name: iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io
  user:
    exec:
      apiVersion: client.authentication.k8s.io/v1alpha1
      args:
      - eks
      - get-token
      - --cluster-name
      - NRSON-EKS-CLUSTER
      - --region
      - ap-northeast-2
      command: aws
      env:
      - name: AWS_STS_REGIONAL_ENDPOINTS
        value: regional
[root@ip-192-168-78-195 .kube]#&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;8. context 추가 (kubectl config set-context)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;다음으로 context를 추가해 보자. NRSON-EKS-CLUSTER를 사용하는 CLUSTER에 아래와 같이 NAMESPACE를 KUBE-SYSTEM을 사용하는 eks-default라는 context를 추가해 보자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1645883635794&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 .kube]# kubectl config get-contexts
CURRENT   NAME                                                          CLUSTER                                      AUTHINFO                                                      NAMESPACE
          iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io   NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io   iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io   
*         minikube                                                      minikube                                     minikube                                                      default
[root@ip-192-168-78-195 .kube]# kubectl config set-context eks-default --namespace=kube-system --cluster=NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io --user=iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io
Context &quot;eks-default&quot; created.
[root@ip-192-168-78-195 .kube]# kubectl config use-context eks-default
Switched to context &quot;eks-default&quot;.
[root@ip-192-168-78-195 .kube]# kubectl get pods
NAME                       READY   STATUS    RESTARTS   AGE
aws-node-2hwdl             1/1     Running   0          18h
aws-node-bqmvx             1/1     Running   0          18h
coredns-6dbb778559-flm4z   1/1     Running   0          18h
coredns-6dbb778559-kr44p   1/1     Running   0          18h
kube-proxy-bndss           1/1     Running   0          18h
kube-proxy-schg7           1/1     Running   0          18h
[root@ip-192-168-78-195 .kube]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 kubectl get pods 결과가 kube-system으로 나오는 것을 확인할 수 있다. 즉 별도로 namespace를 지정하지 않을 경우에는 deafult namespace가 자동으로 매핑된다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;9. kubeconfig 삭제 (kubectl unset cluster + context + user)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;아래와 같이 생성한 context를 삭제할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1645822530651&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 .kube]# kubectl config unset clusters.minikube
Property &quot;clusters.minikube&quot; unset.
[root@ip-192-168-78-195 .kube]# kubectl config unset contexts.minikube
Property &quot;contexts.minikube&quot; unset.
[root@ip-192-168-78-195 .kube]# kubectl config unset users.minikube
Property &quot;users.minikube&quot; unset.
[root@ip-192-168-78-195 .kube]# kubectl config get-contexts
CURRENT   NAME                                                          CLUSTER                                      AUTHINFO                                                      NAMESPACE
*         iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io   NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io   iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io   
[root@ip-192-168-78-195 .kube]#&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;결론&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;kubernetes는 이제 Hybrid의 전환기에 놓여 있다. kubernetes context를 활용하여 이미 많은 상용 대시보드에서는 multi/hybrid 환경 상에서 접근이 가능하도록 구성을 지원하고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;context 기능을 통해 개발/테스트/운영 환경 또는 각 도메인 영역을 구분하고, 통합 접근 관리 대시보드 또는 CLI 노드에서 관리한다면, 보다 효율적인 운영관리가 될 수 있지 않을까 싶다.&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>③ 클라우드/ⓚ Kubernetes</category>
      <category>kubernetes context</category>
      <category>kubernetes multi cluster</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/763</guid>
      <comments>https://waspro.tistory.com/763#entry763comment</comments>
      <pubDate>Sat, 26 Feb 2022 06:04:42 +0900</pubDate>
    </item>
    <item>
      <title>ElasticSearch를 활용한 Kubernetes 로깅 환경 구성</title>
      <link>https://waspro.tistory.com/762</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;개요&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;MSA 환경에서 Telemetry의 중요성은 이미 수많은 포스팅과 수많은 포스터들로 부터 강조되어 왔으며, 이미 많은 자료들을 통해 활용 방안들이 다뤄지고 있다. Telemetry는 로깅, 모니터링, 추적 기능을 포괄하여 분산 트랜잭션 환경에서 효과적인 유지보수를 수행할 수 있도록 지원하는 도구이자, 무엇보다 자동화된 수집체계를 구성하는 것이 중요하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이번 포스팅에서는 msa 환경에서 가장 많이 활용되는 로깅 컴포넌트로 ElasticSearch 기반의 EFK를 다뤄보도록 하자. 포스팅에서는 EFK 구성 설계, EFK 구축, EFK 활용으로 나누어 작성하고자 한다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;EFK 구성 설계&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;ElasticSearch는 실시간 검색/분석 기능을 제공하고, 분산환경에 저장되어 있는 로그를 통합으로 수집함으로써 통합 저장소의 역할을 수행할 수 있다. 또한, 데이터의 사용빈도, 중요도에 따라 로그의 라이프사이클을 관리하여 효과적인 디스크 관리를 지원한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;EFK는 ElasticSeach + FluentD + Kibana의 조합을 의미한다. &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: 'Noto Serif KR'; color: #000000;&quot;&gt;ElasticSearch : 저장을 위한 모듈로 수집한 데이터가 라이프사이클에 의해 저장되는 공간&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;FluentD : 수집 및 정제를 위한 모듈로 Kubernetes 환경에 DaemonSet으로 구성&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Kibana : 분석을 위한 모듈로 ElasticSearch에 저장된 데이터를 Visualize하는 대시보드&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;수집&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;수집모듈은 FluentD를 대신하여 Kafka + Logstash를 구성할 수 있으며, 이렇게 구성되는 환경을 ELK Stack이라고 한다. 물론 FluentD + Logstash로 구성하여 수집과 정제를 구분하여 설계할 수도 있다. &lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;수집이 가능한 포맷으로는 로그파일, 데이터베이스, Streaming 또는 수집 API를 제공하여 데이터를 수집할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;정제&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;정제 모듈은 수집 대상으로 부터 수집한 데이터의 변환과 필터링을 통해 Visualize 하기 위한 기틀을 잡는 역할이다. Logstash를 추가하여 구성할 경우 수집 모듈은 Logstash로 로그를 전송하는 역할만 담당하게 되지만, FluentD와 같이 필터링 작업은 사전에 진행할 경우 변환이 완료된 형태의 데이터를 수집 대상 노드에서 전송하게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;저장&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;저장 모듈은 ElasticSearch를 의미한다. EFK, ELK 모두 ElasticSearch가 핵심이며, 이 저장소를 기반으로 동작한다고 볼 수 있다. ElasticSearch는 역색인구조로 저장되는 NoSQL DB로 데이터의 라이프사이클을 관리하고 백업/복구를 관리하는 저장소이다. &lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Elasticsearch 클러스터는 하나 이상의 노드들로 이루어지며,&amp;nbsp;대표적인 노드는 마스터 노드와 데이터 노드가 있다.&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;font-family: 'Noto Serif KR';&quot;&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; font-size: 16px; letter-spacing: 0px;&quot;&gt;마스터 노드는 인덱스의 메타 데이터(생성, 삭제), 샤드의 위치와 같은 클러스터 상태(Cluster Status) 정보, 데이터 저장을 관리하는 역할을 수행한다. 클러스터마다 하나의 마스터 노드가 존재하며 마스터 노드의 역할을 수행할 수 있는 노드가 없다면 클러스터는 작동이 중지된다. (후보 선출 방식으로 장애 발생시 즉시&amp;nbsp;대체가 가능하다.)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;클러스터가 커져서 노드와 샤드들의 개수가 많아지게 되면 모든 노드들이 마스터 노드의 정보를 계속 공유하는 것은 부담이 될 수 있다. 이때는 마스터 노드의 역할을 수행 할 후보 노드들만 따로 설정해서 유지하는 것이 전체 클러스터 성능에 도움이 될 수 있다. 마스터 노드로 사용하지 않는 노드들은 설정값을 node.master: false 로 하여 마스터 노드의 역할을 하지 않도록 구성한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;데이터 노드는 실제로 색인된 데이터를 저장하고 있는 노드이다. 클러스터에서 마스터 노드와 데이터 노드를 분리하여 설정 할 때 마스터 후보 노드들은 node.data: false 로 설정하여 마스터 노드 역할만 하고 데이터는 저장하지 않도록 할 수 있다. 이렇게 하면 마스터 노드는 데이터는 저장하지 않고 클러스터 관리만 하게 되고, 데이터 노드는 클러스터 관리 작업으로부터 자유롭게 되어 데이터 처리에만 집중할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;그 밖에 데이터 변환을 위한 Ingest 노드, 다중 클러스터를 관리하는 Tribe 노드, 복잡한 조회 및 집계를 포함할 경우 사용하는 Coordinating Only 노드(Client 노드) 등이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;분석&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;분석 모듈은 Kibana를 통해 저장된 데이터를 분석하여 시각화하는 도구이다. 수집데이터에 대한 통합검색, 실시간 모니터링을 지원하며, 장애관리, 이상감지, 자동알림을 통해 유지보수 효율성을 제고해 주는 모듈이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이와 같이 주요 모듈을 기반으로 설계하고자 할때 아래와 같은 아키텍처로 마이크로서비스 환경에 구축해 볼 수 있을 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ay3mb/btrsDSfC6Hs/63knXLv3Y6dQOXgEQgLP31/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ay3mb/btrsDSfC6Hs/63knXLv3Y6dQOXgEQgLP31/img.png&quot; data-origin-width=&quot;1429&quot; data-origin-height=&quot;959&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ay3mb/btrsDSfC6Hs/63knXLv3Y6dQOXgEQgLP31/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAy3mb%2FbtrsDSfC6Hs%2F63knXLv3Y6dQOXgEQgLP31%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;1429&quot; height=&quot;959&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cb9IyS/btrstLbUPRo/rYxcV8u9zv0EuR8YPRMT6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cb9IyS/btrstLbUPRo/rYxcV8u9zv0EuR8YPRMT6k/img.png&quot; data-origin-width=&quot;1429&quot; data-origin-height=&quot;959&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cb9IyS/btrstLbUPRo/rYxcV8u9zv0EuR8YPRMT6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcb9IyS%2FbtrstLbUPRo%2FrYxcV8u9zv0EuR8YPRMT6k%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;1429&quot; height=&quot;959&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cQUSPb/btrsxkc8JaF/7PXZvKZmdMAb5OxXhYeBvk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cQUSPb/btrsxkc8JaF/7PXZvKZmdMAb5OxXhYeBvk/img.png&quot; data-origin-width=&quot;1429&quot; data-origin-height=&quot;959&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5581%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cQUSPb/btrsxkc8JaF/7PXZvKZmdMAb5OxXhYeBvk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcQUSPb%2Fbtrsxkc8JaF%2F7PXZvKZmdMAb5OxXhYeBvk%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;1429&quot; height=&quot;959&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 세가지 아키텍처를 고려해 볼 수 있을&amp;nbsp; 것이다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;Case 1 : 수집은 Fluentd, 수집 안정성을 위해 Kafka, 정제는 Logstash, 저장은 ElasticSearch, 분석은 Kibana로 구성&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Case 2 : 수집은 Fluentd, 정제는 Logstash, 저장은 ElasticSearch, 분석은 Kibana로 구성&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Case 3 :&amp;nbsp;수집 및 정제는 Fluentd, 저장은 ElasticSearch, 분석은 Kibana로 구성&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;지금부터는 Case 3을 기준으로하여 EFK를 직접 구축해 보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;ElasticSearch 구축&lt;/span&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;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;namespace 생성&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;elasticsearch 마스터 노드 생성&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;elasticsearch 데이터 노드 생성&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;elasticsearch 클라이언트 노드 생성&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;a. namespace 생성&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; namespace.yaml&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1644131361606&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: v1
kind: Namespace
metadata:
    name: kube-logging&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; 반영&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1644131393368&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: v1
kind: Namespace
metadata:
    name: kube-logging&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; 확인&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1644131575929&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 efk]# kubectl get namespaces
NAME              STATUS   AGE
default           Active   3d
kube-logging      Active   2m56s
kube-node-lease   Active   3d
kube-public       Active   3d
kube-system       Active   3d
[root@ip-192-168-78-195 efk]#&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;b. elasticsearch 마스터 노드 생성&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; elasticsearch-master-configmap.yaml&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1644131526369&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;---
apiVersion: v1
kind: ConfigMap
metadata:
  namespace: kube-logging
  name: elasticsearch-master-config
  labels:
    app: elasticsearch
    role: master
data:
  elasticsearch.yml: |-
    cluster.name: ${CLUSTER_NAME}
    node.name: ${NODE_NAME}
    discovery.seed_hosts: ${NODE_LIST}
    cluster.initial_master_nodes: ${MASTER_NODES}
    network.host: 0.0.0.0
    node:
      master: true
      data: false
      ingest: false
    xpack.security.enabled: true
    xpack.monitoring.collection.enabled: true
---&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; elasticsearch-master-service.yaml&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1644131723474&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;---
apiVersion: v1
kind: Service
metadata:
  namespace: kube-logging
  name: elasticsearch-master
  labels:
    app: elasticsearch
    role: master
spec:
  ports:
  - port: 9300
    name: transport
  selector:
    app: elasticsearch
    role: master
---&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; elasticsearch-master-deployment.yaml&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1644131744362&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;---
apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: kube-logging
  name: elasticsearch-master
  labels:
    app: elasticsearch
    role: master
spec:
  replicas: 1
  selector:
    matchLabels:
      app: elasticsearch
      role: master
  template:
    metadata:
      labels:
        app: elasticsearch
        role: master
    spec:
      containers:
      - name: elasticsearch-master
        image: docker.elastic.co/elasticsearch/elasticsearch:7.3.0
        env:
        - name: CLUSTER_NAME
          value: elasticsearch
        - name: NODE_NAME
          value: elasticsearch-master
        - name: NODE_LIST
          value: elasticsearch-master,elasticsearch-data,elasticsearch-client
        - name: MASTER_NODES
          value: elasticsearch-master
        - name: &quot;ES_JAVA_OPTS&quot;
          value: &quot;-Xms256m -Xmx256m&quot;
        ports:
        - containerPort: 9300
          name: transport
        volumeMounts:
        - name: config
          mountPath: /usr/share/elasticsearch/config/elasticsearch.yml
          readOnly: true
          subPath: elasticsearch.yml
        - name: storage
          mountPath: /data
      volumes:
      - name: config
        configMap:
          name: elasticsearch-master-config
      - name: &quot;storage&quot;
        emptyDir:
          medium: &quot;&quot;
      initContainers:
      - name: increase-vm-max-map
        image: busybox
        command: [&quot;sysctl&quot;, &quot;-w&quot;, &quot;vm.max_map_count=262144&quot;]
        securityContext:
          privileged: true
---&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; 반영&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1644131552897&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 efk]# kubectl apply -f elasticsearch-master-configmap.yaml -f elasticsearch-master-service.yaml -f elasticsearch-master-deployment.yaml
configmap/elasticsearch-master-config created
service/elasticsearch-master created
deployment.apps/elasticsearch-master created
[root@ip-192-168-78-195 efk]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; 확인&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1644131911857&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 efk]# kubectl get pods -n kube-logging
NAME                                    READY   STATUS    RESTARTS   AGE
elasticsearch-master-745c995d88-4vb2s   1/1     Running   0          45s
[root@ip-192-168-78-195 efk]#&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;c. elasticsearch 데이터 노드 생성&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; elasticsearch-data-configmap.yaml&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1644132039480&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;---
apiVersion: v1
kind: ConfigMap
metadata:
  namespace: kube-logging
  name: elasticsearch-data-config
  labels:
    app: elasticsearch
    role: data
data:
  elasticsearch.yml: |-
    cluster.name: ${CLUSTER_NAME}
    node.name: ${NODE_NAME}
    discovery.seed_hosts: ${NODE_LIST}
    cluster.initial_master_nodes: ${MASTER_NODES}
    network.host: 0.0.0.0
    node:
      master: false
      data: true
      ingest: false
    xpack.security.enabled: true
    xpack.monitoring.collection.enabled: true
---&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; elasticsearch-data-service.yaml&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1644132048401&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;---
apiVersion: v1
kind: Service
metadata:
  namespace: kube-logging
  name: elasticsearch-data
  labels:
    app: elasticsearch
    role: data
spec:
  ports:
  - port: 9300
    name: transport
  selector:
    app: elasticsearch
    role: data
---&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; elasticsearch-data-statefulset.yaml&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1644132060577&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  namespace: kube-logging
  name: elasticsearch-data
  labels:
    app: elasticsearch
    role: data
spec:
  serviceName: &quot;elasticsearch-data&quot;
  selector:
    matchLabels:
      app: elasticsearch-data
      role: data
  replicas: 1
  template:
    metadata:
      labels:
        app: elasticsearch-data
        role: data
    spec:
      containers:
      - name: elasticsearch-data
        image: docker.elastic.co/elasticsearch/elasticsearch:7.3.0
        env:
        - name: CLUSTER_NAME
          value: elasticsearch
        - name: NODE_NAME
          value: elasticsearch-data
        - name: NODE_LIST
          value: elasticsearch-master,elasticsearch-data,elasticsearch-client
        - name: MASTER_NODES
          value: elasticsearch-master
        - name: &quot;ES_JAVA_OPTS&quot;
          value: &quot;-Xms300m -Xmx300m&quot;
        ports:
        - containerPort: 9300
          name: transport
        volumeMounts:
        - name: config
          mountPath: /usr/share/elasticsearch/config/elasticsearch.yml
          readOnly: true
          subPath: elasticsearch.yml
        - name: elasticsearch-data-persistent-storage
          mountPath: /data/db
      volumes:
      - name: config
        configMap:
          name: elasticsearch-data-config
      initContainers:
      - name: increase-vm-max-map
        image: busybox
        command: [&quot;sysctl&quot;, &quot;-w&quot;, &quot;vm.max_map_count=262144&quot;]
        securityContext:
          privileged: true
  volumeClaimTemplates:
  - metadata:
      name: elasticsearch-data-persistent-storage
      annotations:
        volume.beta.kubernetes.io/storage-class: &quot;gp2&quot;
    spec:
      accessModes: [ &quot;ReadWriteOnce&quot; ]
      storageClassName: standard
      resources:
        requests:
          storage: 10Gi
---&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; 반영&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1644132119232&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 efk]# kubectl apply -f elasticsearch-data-configmap.yaml -f elasticsearch-data-service.yaml -f elasticsearch-data-statefulset.yaml
configmap/elasticsearch-data-config created
service/elasticsearch-data created
statefulset.apps/elasticsearch-data created
[root@ip-192-168-78-195 efk]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; 확인&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1644132145144&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 efk]# kubectl get pods -n kube-logging
NAME                                    READY   STATUS    RESTARTS   AGE
elasticsearch-data-0                    1/1     Running   0          35s
elasticsearch-master-745c995d88-4vb2s   1/1     Running   0          4m40s
[root@ip-192-168-78-195 efk]#&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;d. elasticsearch 클라이언트 노드 생성&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; elasticsearch-client-configmap.yaml&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1644132219951&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;---
apiVersion: v1
kind: ConfigMap
metadata:
  namespace: kube-logging
  name: elasticsearch-client-config
  labels:
    app: elasticsearch
    role: client
data:
  elasticsearch.yml: |-
    cluster.name: ${CLUSTER_NAME}
    node.name: ${NODE_NAME}
    discovery.seed_hosts: ${NODE_LIST}
    cluster.initial_master_nodes: ${MASTER_NODES}
    network.host: 0.0.0.0
    node:
      master: false
      data: false
      ingest: true
    xpack.security.enabled: true
    xpack.monitoring.collection.enabled: true
---&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; elasticsearch-client-service.yaml&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1644132230632&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;---
apiVersion: v1
kind: Service
metadata:
  namespace: kube-logging
  name: elasticsearch-client
  labels:
    app: elasticsearch
    role: client
spec:
  ports:
  - port: 9200
    name: client
  - port: 9300
    name: transport
  selector:
    app: elasticsearch
    role: client
---&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; elasticsearch-client-deployment.yaml&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1644132248688&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;---
apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: kube-logging
  name: elasticsearch-client
  labels:
    app: elasticsearch
    role: client
spec:
  replicas: 1
  selector:
    matchLabels:
      app: elasticsearch
      role: client
  template:
    metadata:
      labels:
        app: elasticsearch
        role: client
    spec:
      containers:
      - name: elasticsearch-client
        image: docker.elastic.co/elasticsearch/elasticsearch:7.3.0
        env:
        - name: CLUSTER_NAME
          value: elasticsearch
        - name: NODE_NAME
          value: elasticsearch-client
        - name: NODE_LIST
          value: elasticsearch-master,elasticsearch-data,elasticsearch-client
        - name: MASTER_NODES
          value: elasticsearch-master
        - name: &quot;ES_JAVA_OPTS&quot;
          value: &quot;-Xms256m -Xmx256m&quot;
        ports:
        - containerPort: 9200
          name: client
        - containerPort: 9300
          name: transport
        volumeMounts:
        - name: config
          mountPath: /usr/share/elasticsearch/config/elasticsearch.yml
          readOnly: true
          subPath: elasticsearch.yml
        - name: storage
          mountPath: /data
      volumes:
      - name: config
        configMap:
          name: elasticsearch-client-config
      - name: &quot;storage&quot;
        emptyDir:
          medium: &quot;&quot;
      initContainers:
      - name: increase-vm-max-map
        image: busybox
        command: [&quot;sysctl&quot;, &quot;-w&quot;, &quot;vm.max_map_count=262144&quot;]
        securityContext:
          privileged: true
---&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; 반영&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1644132292208&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 efk]# kubectl apply -f elasticsearch-client-configmap.yaml -f elasticsearch-client-service.yaml -f elasticsearch-client-deployment.yaml
configmap/elasticsearch-client-config created
service/elasticsearch-client created
deployment.apps/elasticsearch-client created
[root@ip-192-168-78-195 efk]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; 확인&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1644132314824&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 efk]# kubectl get pods -n kube-logging
NAME                                    READY   STATUS    RESTARTS   AGE
elasticsearch-client-578dd48f84-kx2rf   1/1     Running   0          22s
elasticsearch-data-0                    1/1     Running   0          3m23s
elasticsearch-master-745c995d88-4vb2s   1/1     Running   0          7m28s
[root@ip-192-168-78-195 efk]#&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;e. 구축 상태 확인&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 각 노드 설치가 완료되면, master node에 아래와 같은 문구가 출력되는지 확인한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1644132496775&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 efk]# kubectl logs -f -n kube-logging $(kubectl get pods -n kube-logging | grep elasticsearch-master | sed -n 1p | awk '{print $1}') | grep &quot;Cluster health status changed from \[YELLOW\] to \[GREEN\]&quot;
{&quot;type&quot;: &quot;server&quot;, &quot;timestamp&quot;: &quot;2022-02-06T07:25:06,260+0000&quot;, &quot;level&quot;: &quot;INFO&quot;, &quot;component&quot;: &quot;o.e.c.r.a.AllocationService&quot;, &quot;cluster.name&quot;: &quot;elasticsearch&quot;, &quot;node.name&quot;: &quot;elasticsearch-master&quot;, &quot;cluster.uuid&quot;: &quot;FqOtUobfRF-g46URNGZKfA&quot;, &quot;node.id&quot;: &quot;jglC7I-tRaqCXt7ru_uZKQ&quot;,  &quot;message&quot;: &quot;Cluster health status changed from [YELLOW] to [GREEN] (reason: [shards started [[.monitoring-es-7-2022.02.06][0]] ...]).&quot;  }&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;f. X-Pack 적용&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;X-Pack은 보안, 알림, 모니터링, 보고, 그래프 기능을 설치하기 편리한 단일 패키지로 번들 구성한 Elastic Stack 확장 프로그램이다. X-Pack 구성 요소는 서로 원활하게 연동할 수 있도록 설계되었지만 사용할 기능을 손쉽게 활성화하거나 비활성화할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;클러스터 보안을 위해 X-Pack 보안 모듈을 활성화했고(각 노드 별 configmap 확인), 암호를 초기화 해보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1644133408338&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 efk]# kubectl exec -it $(kubectl get pods -n kube-logging | grep elasticsearch-client | sed -n 1p | awk '{print $1}') -n kube-logging -- bin/elasticsearch-setup-passwords auto -b
Changed password for user apm_system
PASSWORD apm_system = xxxxxxxxxxxxxxxxx

Changed password for user kibana
PASSWORD kibana = xxxxxxxxxxxxxxxxx

Changed password for user logstash_system
PASSWORD logstash_system = xxxxxxxxxxxxxxxxx

Changed password for user beats_system
PASSWORD beats_system = xxxxxxxxxxxxxxxxx

Changed password for user remote_monitoring_user
PASSWORD remote_monitoring_user = xxxxxxxxxxxxxxxxx

Changed password for user elastic
PASSWORD elastic = aaaaaaaaaaaaaaa

[root@ip-192-168-78-195 efk]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;마지막 user elastic password를 기록해 두고, kubernetes secret을 추가한다.&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1644133520150&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 efk]# kubectl create secret generic elasticsearch-pw-elastic -n kube-logging --from-literal password=aaaaaaaaaaaaaaaa
secret/elasticsearch-pw-elastic created
[root@ip-192-168-78-195 efk]#&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Kibana 구축&lt;/span&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;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;kibana 생성&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;대시보드 접속&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;a. kibana 생성&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; kibana-configmap.yaml&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1644133741574&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;---
apiVersion: v1
kind: ConfigMap
metadata:
  namespace: kube-logging
  name: kibana-config
  labels:
    app: kibana
data:
  kibana.yml: |-
    server.host: 0.0.0.0
    elasticsearch:
      hosts: ${ELASTICSEARCH_HOSTS}
      username: ${ELASTICSEARCH_USER}
      password: ${ELASTICSEARCH_PASSWORD}
---&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; kibana-service.yaml&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1644133750406&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;---
apiVersion: v1
kind: Service
metadata:
  namespace: kube-logging
  name: kibana
  labels:
    app: kibana
spec:
  type: LoadBalancer
  ports:
  - port: 80
    name: webinterface
    targetPort: 5601
  selector:
    app: kibana
---&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; kibana-deployment.yaml&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1644133763023&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;---
apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: kube-logging
  name: kibana
  labels:
    app: kibana
spec:
  replicas: 1
  selector:
    matchLabels:
      app: kibana
  template:
    metadata:
      labels:
        app: kibana
    spec:
      containers:
      - name: kibana
        image: docker.elastic.co/kibana/kibana:7.3.0
        ports:
        - containerPort: 5601
          name: webinterface
        env:
        - name: ELASTICSEARCH_HOSTS
          value: &quot;http://elasticsearch-client.kube-logging.svc.cluster.local:9200&quot;
        - name: ELASTICSEARCH_USER
          value: &quot;elastic&quot;
        - name: ELASTICSEARCH_PASSWORD
          valueFrom:
            secretKeyRef:
              name: elasticsearch-pw-elastic
              key: password
        volumeMounts:
        - name: config
          mountPath: /usr/share/kibana/config/kibana.yml
          readOnly: true
          subPath: kibana.yml
      volumes:
      - name: config
        configMap:
          name: kibana-config
---&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; 반영&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1644133808119&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 efk]# kubectl apply -f kibana-configmap.yaml -f kibana-service.yaml -f kibana-deployment.yaml
configmap/kibana-config created
service/kibana created
deployment.apps/kibana created
[root@ip-192-168-78-195 efk]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; 확인&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1644134021072&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 efk]# kubectl get pods -n kube-logging
NAME                                    READY   STATUS    RESTARTS   AGE
elasticsearch-client-578dd48f84-kx2rf   1/1     Running   0          28m
elasticsearch-data-0                    1/1     Running   0          31m
elasticsearch-master-745c995d88-4vb2s   1/1     Running   0          35m
kibana-5cb685c5f4-x66xv                 1/1     Running   0          3m31s
[root@ip-192-168-78-195 efk]# kubectl get service -n kube-logging
NAME                   TYPE           CLUSTER-IP       EXTERNAL-IP                                                                   PORT(S)             AGE
elasticsearch-client   ClusterIP      10.100.4.148     &amp;lt;none&amp;gt;                                                                        9200/TCP,9300/TCP   29m
elasticsearch-data     ClusterIP      10.100.216.144   &amp;lt;none&amp;gt;                                                                        9300/TCP            32m
elasticsearch-master   ClusterIP      10.100.1.255     &amp;lt;none&amp;gt;                                                                        9300/TCP            36m
kibana                 LoadBalancer   10.100.142.131   aaaaaa259dae34aa1acab098bd9cbeab-590462194.ap-northeast-2.elb.amazonaws.com   80:32111/TCP        3m51s
[root@ip-192-168-78-195 efk]#&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;b. 대시보드 접속&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1315&quot; data-origin-height=&quot;880&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d7PjC7/btrsswyFPfb/iYiREAhz4oQXYqYvEgS1c0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d7PjC7/btrsswyFPfb/iYiREAhz4oQXYqYvEgS1c0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d7PjC7/btrsswyFPfb/iYiREAhz4oQXYqYvEgS1c0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd7PjC7%2FbtrsswyFPfb%2FiYiREAhz4oQXYqYvEgS1c0%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;1315&quot; height=&quot;880&quot; data-origin-width=&quot;1315&quot; data-origin-height=&quot;880&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: 'Noto Serif KR'; color: #000000;&quot;&gt;id는 elastic, password는 앞서 초기화 한 암호(aaaaaaaaa)를 입력하면 된다. 현재 시점에는 Fluentd가 설치되어 있지 않아 수집이 진행되고 있는 상태는 아니며, 기본 환경에 대해 확인 후 Fluentd 설치를 진행해 보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; Management&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;1318&quot; data-origin-height=&quot;880&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nEVYh/btrsFsVy9Yt/eeTNZoKXP4GfFyXpUqVAgK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nEVYh/btrsFsVy9Yt/eeTNZoKXP4GfFyXpUqVAgK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nEVYh/btrsFsVy9Yt/eeTNZoKXP4GfFyXpUqVAgK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnEVYh%2FbtrsFsVy9Yt%2FeeTNZoKXP4GfFyXpUqVAgK%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;1318&quot; height=&quot;880&quot; data-origin-width=&quot;1318&quot; data-origin-height=&quot;880&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: 'Noto Serif KR'; color: #000000;&quot;&gt;왼쪽 하단의 톱니바퀴(Management) 메뉴를 선택한다. 먼저 살펴볼 내용은 Management &amp;gt; Security &amp;gt; Users이다.&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;1321&quot; data-origin-height=&quot;929&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHLkpk/btrsDRHOftg/6SY1kyg7DTWBsnaWO8ELdk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHLkpk/btrsDRHOftg/6SY1kyg7DTWBsnaWO8ELdk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHLkpk/btrsDRHOftg/6SY1kyg7DTWBsnaWO8ELdk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHLkpk%2FbtrsDRHOftg%2F6SY1kyg7DTWBsnaWO8ELdk%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;1321&quot; height=&quot;929&quot; data-origin-width=&quot;1321&quot; data-origin-height=&quot;929&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: 'Noto Serif KR'; color: #000000;&quot;&gt;User 정보를 수정하거나, Create User를 통해 신규 유저를 할당할 수 있다. 특히 사전에 정의되어 있는 27개의 Role을 기반으로 사용자를 추가할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;a href=&quot;https://www.elastic.co/guide/en/elasticsearch/reference/current/built-in-roles.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;User Role : https://www.elastic.co/guide/en/elasticsearch/reference/current/built-in-roles.html&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;index management의 경우 Fluentd 설치 이후 살펴보도록 하고, Management 바로 위 메뉴인 Monitoring을 살펴보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; Monitoring&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;1320&quot; data-origin-height=&quot;930&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nfTxW/btrsytVxTPZ/QsQV6Zq7FMLA7df0bGF5F0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nfTxW/btrsytVxTPZ/QsQV6Zq7FMLA7df0bGF5F0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nfTxW/btrsytVxTPZ/QsQV6Zq7FMLA7df0bGF5F0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnfTxW%2FbtrsytVxTPZ%2FQsQV6Zq7FMLA7df0bGF5F0%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;1320&quot; height=&quot;930&quot; data-origin-width=&quot;1320&quot; data-origin-height=&quot;930&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;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;모니터링 화면에서는 ElasticSearch와 Kibana 관련 정보를 확인할 수 있다. &lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;먼저 ElasticSearch에서는 Resource 정보와 Node, Indice, Log 정보를 다음과 같이 각각 확인 가능하다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;- Overview (리소스 정보)&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;1319&quot; data-origin-height=&quot;928&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GGmJl/btrsC9IK9wp/8ER0gwXUkZXDHxQq6WrO41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GGmJl/btrsC9IK9wp/8ER0gwXUkZXDHxQq6WrO41/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GGmJl/btrsC9IK9wp/8ER0gwXUkZXDHxQq6WrO41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGGmJl%2FbtrsC9IK9wp%2F8ER0gwXUkZXDHxQq6WrO41%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;1319&quot; height=&quot;928&quot; data-origin-width=&quot;1319&quot; data-origin-height=&quot;928&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: 'Noto Serif KR'; color: #000000;&quot;&gt;- Nodes (노드 정보)&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;1321&quot; data-origin-height=&quot;930&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Cu88B/btrsvdF7Wf3/0EI9DKBLXxek4wwcLWKn4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Cu88B/btrsvdF7Wf3/0EI9DKBLXxek4wwcLWKn4k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Cu88B/btrsvdF7Wf3/0EI9DKBLXxek4wwcLWKn4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCu88B%2FbtrsvdF7Wf3%2F0EI9DKBLXxek4wwcLWKn4k%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;1321&quot; height=&quot;930&quot; data-origin-width=&quot;1321&quot; data-origin-height=&quot;930&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: 'Noto Serif KR'; color: #000000;&quot;&gt;Nodes 정보에서는 ElasticSearch 노드에 대해 확인할 수 있다. 이 중 앞에 별표가 붙어 있는 노드가 Master 노드이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;- Indices (통계 지표)&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;1321&quot; data-origin-height=&quot;930&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Hoqmv/btrsA6FxEFB/hkUOJnqGFO9tsSKM7aLEkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Hoqmv/btrsA6FxEFB/hkUOJnqGFO9tsSKM7aLEkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Hoqmv/btrsA6FxEFB/hkUOJnqGFO9tsSKM7aLEkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHoqmv%2FbtrsA6FxEFB%2FhkUOJnqGFO9tsSKM7aLEkK%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;1321&quot; height=&quot;930&quot; data-origin-width=&quot;1321&quot; data-origin-height=&quot;930&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: 'Noto Serif KR'; color: #000000;&quot;&gt;Log 정보는 Fluentd 설치 이후 살펴보도록 하자. Kibana 항목에서는 Client Request, Response Time, Instance 정보를 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;- Overview&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;1319&quot; data-origin-height=&quot;927&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cGItx8/btrsysI7p54/CBz7B2ddEWjWwAGjGQEH81/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cGItx8/btrsysI7p54/CBz7B2ddEWjWwAGjGQEH81/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cGItx8/btrsysI7p54/CBz7B2ddEWjWwAGjGQEH81/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcGItx8%2FbtrsysI7p54%2FCBz7B2ddEWjWwAGjGQEH81%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;1319&quot; height=&quot;927&quot; data-origin-width=&quot;1319&quot; data-origin-height=&quot;927&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: 'Noto Serif KR'; color: #000000;&quot;&gt;- Instances&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;1320&quot; data-origin-height=&quot;930&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tzIKS/btrsysI7qJM/5qphSHZl7XPudAVBx4QQkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tzIKS/btrsysI7qJM/5qphSHZl7XPudAVBx4QQkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tzIKS/btrsysI7qJM/5qphSHZl7XPudAVBx4QQkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtzIKS%2FbtrsysI7qJM%2F5qphSHZl7XPudAVBx4QQkK%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;1320&quot; height=&quot;930&quot; data-origin-width=&quot;1320&quot; data-origin-height=&quot;930&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;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Fluentd 구축&lt;/span&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;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Fluentd 생성&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;로그 수집 확인&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;index 생성&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;a. Fluentd 생성&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; fluentd-config-map.yaml&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1644138403754&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: v1
kind: ConfigMap
metadata:
  name: fluentd-config
  namespace: kube-logging
data:
  fluent.conf: |
    &amp;lt;match fluent.**&amp;gt;
        # this tells fluentd to not output its log on stdout
        @type null
    &amp;lt;/match&amp;gt;
    # here we read the logs from Docker's containers and parse them
    &amp;lt;source&amp;gt;
      @type tail
      path /var/log/containers/*.log
      pos_file /var/log/app.log.pos
      tag kubernetes.*
      read_from_head true
      &amp;lt;parse&amp;gt;
        @type json
        time_format %Y-%m-%dT%H:%M:%S.%NZ
      &amp;lt;/parse&amp;gt;
    &amp;lt;/source&amp;gt;
    # we use kubernetes metadata plugin to add metadatas to the log
    &amp;lt;filter kubernetes.**&amp;gt;
        @type kubernetes_metadata
    &amp;lt;/filter&amp;gt;
     # we send the logs to Elasticsearch
    &amp;lt;match **&amp;gt;
       @type elasticsearch_dynamic
       @log_level info
       include_tag_key true
       host &quot;#{ENV['FLUENT_ELASTICSEARCH_HOST']}&quot;
       port &quot;#{ENV['FLUENT_ELASTICSEARCH_PORT']}&quot;
       user &quot;#{ENV['FLUENT_ELASTICSEARCH_USER']}&quot;
       password &quot;#{ENV['FLUENT_ELASTICSEARCH_PASSWORD']}&quot;
       scheme &quot;#{ENV['FLUENT_ELASTICSEARCH_SCHEME'] || 'http'}&quot;
       ssl_verify &quot;#{ENV['FLUENT_ELASTICSEARCH_SSL_VERIFY'] || 'true'}&quot;
       reload_connections true
       logstash_format true
       logstash_prefix logstash
       &amp;lt;buffer&amp;gt;
           @type file
           path /var/log/fluentd-buffers/kubernetes.system.buffer
           flush_mode interval
           retry_type exponential_backoff
           flush_thread_count 2
           flush_interval 5s
           retry_forever true
           retry_max_interval 30
           chunk_limit_size 2M
           queue_limit_length 32
           overflow_action block
       &amp;lt;/buffer&amp;gt;
    &amp;lt;/match&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Fluentd는 Input(source) &amp;gt; Filter(filter) &amp;gt; Buffer(buffer) &amp;gt; Output(match) 순으로 처리된다고 볼 수 있다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;source :&amp;nbsp; 수집 대상 정의&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;source.@type : 수집 방식 정의. tail은 파일을 tail하여 읽어오는 방식&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;source.pos_file : 수집 파일의 inode를 추적하기 위한 파일로 마지막 읽은 위치 기록&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;source.parse.@type : 전달 받은 데이터를 파싱. json 타입으로 파싱하여 전달. 정규표현식이나 별도의 가공하지 않고 전달할 수 도 있음&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;filter : 특정 필드에 대한 필터링 조건을 정의. grep, parser 등을 지정할 수 있으며, kubernetes_metadata를 사용하기 위해 별도의 plugin을 설치하여 구성&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;match : 출력할 로그 형태 정의. stdout, forward, file 등을 지정할 수 있으며, elasticsearch_dynamic으로 지정하면, 유동적으로 선언하여 처리할 수 있음&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;match.buffer : input 에서 들어온 log를 특정데이터 크기 제한까지 도달하면 output 출력&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; fluentd-daemonset.yaml&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1644138416938&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: v1
kind: ServiceAccount
metadata:
  name: fluentd
  namespace: kube-logging
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: fluentd
  namespace: kube-logging
rules:
- apiGroups:
  - &quot;&quot;
  resources:
  - pods
  - namespaces
  verbs:
  - get
  - list
  - watch
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: fluentd
roleRef:
  kind: ClusterRole
  name: fluentd
  apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
  name: fluentd
  namespace: kube-logging
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd
  namespace: kube-logging
  labels:
    k8s-app: fluentd-logging
    version: v1
    kubernetes.io/cluster-service: &quot;true&quot;
spec:
  selector:
    matchLabels:
      k8s-app: fluentd-logging
      version: v1
      kubernetes.io/cluster-service: &quot;true&quot;
  template:
    metadata:
      labels:
        k8s-app: fluentd-logging
        version: v1
        kubernetes.io/cluster-service: &quot;true&quot;
    spec:
      serviceAccount: fluentd # if RBAC is enabled
      serviceAccountName: fluentd # if RBAC is enabled
      tolerations:
      - key: node-role.kubernetes.io/master
        effect: NoSchedule
      containers:
      - name: fluentd
        image: fluent/fluentd-kubernetes-daemonset:v1.1-debian-elasticsearch
        env:
        - name:  FLUENT_ELASTICSEARCH_HOST
          value: &quot;elasticsearch-client.kube-logging.svc.cluster.local&quot;
        - name:  FLUENT_ELASTICSEARCH_PORT
          value: &quot;9200&quot;
        - name: FLUENT_ELASTICSEARCH_SCHEME
          value: &quot;http&quot;
        - name: FLUENT_ELASTICSEARCH_USER # even if not used they are necessary
          value: &quot;elastic&quot;
        - name: FLUENT_ELASTICSEARCH_PASSWORD # even if not used they are necessary
          valueFrom:
            secretKeyRef:
              name: elasticsearch-pw-elastic
              key: password
        resources:
          limits:
            memory: 200Mi
          requests:
            cpu: 100m
            memory: 200Mi
        volumeMounts:
        - name: varlog
          mountPath: /var/log
        - name: varlibdockercontainers
          mountPath: /var/lib/docker/containers
          readOnly: true
        - name: fluentd-config
          mountPath: /fluentd/etc # path of fluentd config file
      terminationGracePeriodSeconds: 30
      volumes:
      - name: varlog
        hostPath:
          path: /var/log
      - name: varlibdockercontainers
        hostPath:
          path: /var/lib/docker/containers
      - name: fluentd-config
        configMap:
          name: fluentd-config # name of the config map we will create&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; 반영&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1644138558497&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 efk]# kubectl apply -f fluentd-config-map.yaml -f fluentd-daemonset.yaml
configmap/fluentd-config created
serviceaccount/fluentd created
clusterrole.rbac.authorization.k8s.io/fluentd created
clusterrolebinding.rbac.authorization.k8s.io/fluentd created
daemonset.apps/fluentd created
[root@ip-192-168-78-195 efk]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; 확인&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1644138581793&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 efk]# kubectl get pods -n kube-logging
NAME                                    READY   STATUS    RESTARTS   AGE
elasticsearch-client-578dd48f84-8trwh   1/1     Running   0          54m
elasticsearch-data-0                    1/1     Running   0          54m
elasticsearch-master-745c995d88-mk9qs   1/1     Running   0          54m
fluentd-lnzhw                           1/1     Running   0          26s
fluentd-vzxvg                           1/1     Running   0          27s
kibana-5cb685c5f4-vbb6j                 1/1     Running   0          52m
[root@ip-192-168-78-195 efk]#&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;b. 로그 수집 확인&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;FluentD를 커스터마이징 하기 전에 Log 수집여부를 확인해 보도록 하자.&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;1321&quot; data-origin-height=&quot;930&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbdM9V/btrsFtf8Xni/SAHP7XXvyO2Ue2KYGKor91/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbdM9V/btrsFtf8Xni/SAHP7XXvyO2Ue2KYGKor91/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbdM9V/btrsFtf8Xni/SAHP7XXvyO2Ue2KYGKor91/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbdM9V%2FbtrsFtf8Xni%2FSAHP7XXvyO2Ue2KYGKor91%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;1321&quot; height=&quot;930&quot; data-origin-width=&quot;1321&quot; data-origin-height=&quot;930&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: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 default로 logstash-*로 시작하는 index pattern이 추가되어 있는 것을 확인할 수 있다.&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;1303&quot; data-origin-height=&quot;928&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SJr5C/btrsxFB72p9/eiW6mkkpL4heCkf9zSLmrk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SJr5C/btrsxFB72p9/eiW6mkkpL4heCkf9zSLmrk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SJr5C/btrsxFB72p9/eiW6mkkpL4heCkf9zSLmrk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSJr5C%2FbtrsxFB72p9%2FeiW6mkkpL4heCkf9zSLmrk%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;1303&quot; height=&quot;928&quot; data-origin-width=&quot;1303&quot; data-origin-height=&quot;928&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;c. index 생성&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;fluentd-plugin-kubernetes_metadata_filter를 사용하여 kubernetes.metadata를 활용할 수 있다. 해당 플러그인은 이미 이미지에 포함되어 있거나, gem install을 이용하여 수동 설치한 커스텀이미지를 생성할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;본 포스팅에서 사용한 fluent/fluentd-kubernetes-daemonset:v1.1-debian-elasticsearch에는 이미 플러그인이 설치되어 있어 별도로 커스텀할 필요는 없다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; fluentd-config-map-custome-index.yaml&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1644173563213&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: v1
kind: ConfigMap
metadata:
  name: fluentd-config
  namespace: kube-logging
data:
  fluent.conf: |
    &amp;lt;match fluent.**&amp;gt;
        # this tells fluentd to not output its log on stdout
        @type null
    &amp;lt;/match&amp;gt;
    # here we read the logs from Docker's containers and parse them
    &amp;lt;source&amp;gt;
      @type tail
      path /var/log/containers/*.log
      pos_file /var/log/containers.log.pos
      tag kubernetes.*
      read_from_head true
      &amp;lt;parse&amp;gt;
        @type json
        time_format %Y-%m-%dT%H:%M:%S.%NZ
      &amp;lt;/parse&amp;gt;
    &amp;lt;/source&amp;gt;
    # we use kubernetes metadata plugin to add metadatas to the log
    &amp;lt;filter kubernetes.**&amp;gt;
        @type kubernetes_metadata
    &amp;lt;/filter&amp;gt;
    &amp;lt;match kubernetes.var.log.containers.**kube-logging**.log&amp;gt;
    @type null
    &amp;lt;/match&amp;gt;
    &amp;lt;match kubernetes.var.log.containers.**kube-system**.log&amp;gt;
    @type null
    &amp;lt;/match&amp;gt;
    &amp;lt;match kubernetes.var.log.containers.**monitoring**.log&amp;gt;
    @type null
    &amp;lt;/match&amp;gt;
    &amp;lt;match kubernetes.var.log.containers.**infra**.log&amp;gt;
    @type null
    &amp;lt;/match&amp;gt;
     # we send the logs to Elasticsearch
    &amp;lt;match kubernetes.**&amp;gt;
       @type elasticsearch_dynamic
       @log_level info
       include_tag_key true
       host &quot;#{ENV['FLUENT_ELASTICSEARCH_HOST']}&quot;
       port &quot;#{ENV['FLUENT_ELASTICSEARCH_PORT']}&quot;
       user &quot;#{ENV['FLUENT_ELASTICSEARCH_USER']}&quot;
       password &quot;#{ENV['FLUENT_ELASTICSEARCH_PASSWORD']}&quot;
       scheme &quot;#{ENV['FLUENT_ELASTICSEARCH_SCHEME'] || 'http'}&quot;
       ssl_verify &quot;#{ENV['FLUENT_ELASTICSEARCH_SSL_VERIFY'] || 'true'}&quot;
       reload_connections true
       logstash_format true
       logstash_prefix ${record['kubernetes']['pod_name']}
       &amp;lt;buffer&amp;gt;
           @type file
           path /var/log/fluentd-buffers/kubernetes.system.buffer
           flush_mode interval
           retry_type exponential_backoff
           flush_thread_count 2
           flush_interval 5s
           retry_forever true
           retry_max_interval 30
           chunk_limit_size 2M
           queue_limit_length 32
           overflow_action block
       &amp;lt;/buffer&amp;gt;
    &amp;lt;/match&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Default ConfigMap과의 두가지 구성을 추가/변경하였다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; index pattern 변경&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: 'Noto Serif KR'; color: #000000;&quot;&gt;Default ConfigMap : &amp;lt;match **&amp;gt; / logstash_prefix logstash&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Custom ConfigMap : &amp;lt;match kubernetes.**&amp;gt; / logstash_prefix ${record['kubernetes']['pod_name']}&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Kuberentes Metadata를 사용하여 pod_name으로 index를 생성한다. 이와 같은 index로 활용 가능한 Kubernetes Metadata는 pod_name은 물론 namespace_name, container_name 등을 사용할 수 있다. 추가 시 logstash_prefix를 나열하여 처리할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;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: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;lt;match kubernetes.var.log.containers.**kube-logging**.log&amp;gt; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;@type null &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;lt;/match&amp;gt; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;lt;match kubernetes.var.log.containers.**kube-system**.log&amp;gt; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;@type null &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;lt;/match&amp;gt; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;lt;match kubernetes.var.log.containers.**monitoring**.log&amp;gt; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;@type null &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;lt;/match&amp;gt; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;lt;match kubernetes.var.log.containers.**infra**.log&amp;gt; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;@type null &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;lt;/match&amp;gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Fluentd에서 ElasticSearch로 전송할 로그 대상 중 제외하고자 하는 로그 형태를 정의한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; 반영&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1644174855205&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 efk]# kubectl apply -f fluentd-config-map-custome-index.yaml
configmap/fluentd-config configured
[root@ip-192-168-78-195 efk]# kubectl rollout restart daemonset/fluentd -n kube-logging
daemonset.apps/fluentd restarted
[root@ip-192-168-78-195 efk]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;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;1322&quot; data-origin-height=&quot;929&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pErqB/btrszl4hnZb/G39cH9kBv4OLBraPxIFHFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pErqB/btrszl4hnZb/G39cH9kBv4OLBraPxIFHFk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pErqB/btrszl4hnZb/G39cH9kBv4OLBraPxIFHFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpErqB%2Fbtrszl4hnZb%2FG39cH9kBv4OLBraPxIFHFk%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;1322&quot; height=&quot;929&quot; data-origin-width=&quot;1322&quot; data-origin-height=&quot;929&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: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 index pattern에 logstash 이외에 pod_name으로 기동되는 my-nginx-* pod가 추가되었다. index를 추가하고 Discover에서 아래와 같이 확인이 가능하다.&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;1321&quot; data-origin-height=&quot;928&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cbvpwh/btrsyGtqOSz/kCTas2K2xL89tkmBNdDDf1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cbvpwh/btrsyGtqOSz/kCTas2K2xL89tkmBNdDDf1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cbvpwh/btrsyGtqOSz/kCTas2K2xL89tkmBNdDDf1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcbvpwh%2FbtrsyGtqOSz%2FkCTas2K2xL89tkmBNdDDf1%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;1321&quot; height=&quot;928&quot; data-origin-width=&quot;1321&quot; data-origin-height=&quot;928&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: 'Noto Serif KR'; color: #000000;&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;1321&quot; data-origin-height=&quot;241&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l9Js4/btrsH9uMizi/xnbgBZpikvYQzqih55ggQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l9Js4/btrsH9uMizi/xnbgBZpikvYQzqih55ggQ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l9Js4/btrsH9uMizi/xnbgBZpikvYQzqih55ggQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl9Js4%2FbtrsH9uMizi%2FxnbgBZpikvYQzqih55ggQ0%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;1321&quot; height=&quot;241&quot; data-origin-width=&quot;1321&quot; data-origin-height=&quot;241&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: 'Noto Serif KR'; color: #000000;&quot;&gt;아래와 같이 2회 호출 후 Refresh를 확인해 보면 로그가 출력되는 것을 확인할 수 있다.&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;1303&quot; data-origin-height=&quot;931&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b20Nfz/btrszmhPN2v/SPi3HgDlNknYge5RrbdbuK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b20Nfz/btrszmhPN2v/SPi3HgDlNknYge5RrbdbuK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b20Nfz/btrszmhPN2v/SPi3HgDlNknYge5RrbdbuK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb20Nfz%2FbtrszmhPN2v%2FSPi3HgDlNknYge5RrbdbuK%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;1303&quot; height=&quot;931&quot; data-origin-width=&quot;1303&quot; data-origin-height=&quot;931&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: 'Noto Serif KR'; color: #000000;&quot;&gt;또한, 앞서 로그 수집대상으로 정의한 logstash를 확인해 보면,&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;1301&quot; data-origin-height=&quot;929&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DKkWE/btrsHG0A6pu/KU9E7IkUY53FyMymBkGrmK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DKkWE/btrsHG0A6pu/KU9E7IkUY53FyMymBkGrmK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DKkWE/btrsHG0A6pu/KU9E7IkUY53FyMymBkGrmK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDKkWE%2FbtrsHG0A6pu%2FKU9E7IkUY53FyMymBkGrmK%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;1301&quot; height=&quot;929&quot; data-origin-width=&quot;1301&quot; data-origin-height=&quot;929&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: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 configmap이 반영된 시점 이후부터 logstash에 매핑되어 있던 index 정보들은 더이상 수집되지 않는 것을 확인할 수 있다.&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;font-family: 'Noto Serif KR';&quot;&gt;마지막으로 추가 어플리케이션을 추가하여 수집되는지 여부를 확인해 보도록 하자. 테스트 방식은 동일한 nginx deployment를 수집 제외 대상으로 정의한 kube-logging namespace 내에 배포하고, 다른 nginx deployment는 app-test라는 namespace에 배포해 보도록 하자.&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&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;font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; kube-logging namespace 내 nginx service&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1644176955482&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: v1
kind: Service
metadata:
  name: my-nginx
  namespace: kube-logging
  labels:
    run: my-nginx
spec:
  ports:
  - nodePort: 30080
    port: 80
    protocol: TCP
  type: NodePort
  selector:
    run: my-nginx&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; kube-logging namespace 내 nginx deployment&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1644177014169&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
  namespace: kube-logging
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx
        ports:
        - containerPort: 80&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; app-test namespace 내 nginx service&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1644177040649&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: v1
kind: Service
metadata:
  name: my-nginx
  namespace: app-test
  labels:
    run: my-nginx
spec:
  ports:
  - nodePort: 30280
    port: 80
    protocol: TCP
  type: NodePort
  selector:
    run: my-nginx&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; app-test namespace 내 nginx deployment&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1644177070666&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
  namespace: app-test
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx
        ports:
        - containerPort: 80&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;아래와 같이 pod 상태를 확인해 보자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1644177160281&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 app]# kubectl get pod --all-namespaces | grep my-nginx
app-test       my-nginx-5b56ccd65f-j79sb               1/1     Running   0          7m33s
app-test       my-nginx-5b56ccd65f-j8dmq               1/1     Running   0          7m33s
default        my-nginx-5b56ccd65f-8rzl4               1/1     Running   0          2d11h
default        my-nginx-5b56ccd65f-w78f9               1/1     Running   0          2d11h
kube-logging   my-nginx-5b56ccd65f-7fgmx               1/1     Running   0          10m
kube-logging   my-nginx-5b56ccd65f-shc9z               1/1     Running   0          10m
[root@ip-192-168-78-195 app]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;정상 Running 상태로 기동이 되었다면, 각각 페이지 정상 호출 여부를 확인하고, 아래와 같이 kibana index pattern을 확인해 보자.&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;1322&quot; data-origin-height=&quot;930&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ddgsBP/btrssvNuHu3/WkeEDQ8zRGOKw5Y51bCymK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ddgsBP/btrssvNuHu3/WkeEDQ8zRGOKw5Y51bCymK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ddgsBP/btrssvNuHu3/WkeEDQ8zRGOKw5Y51bCymK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FddgsBP%2FbtrssvNuHu3%2FWkeEDQ8zRGOKw5Y51bCymK%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;1322&quot; height=&quot;930&quot; data-origin-width=&quot;1322&quot; data-origin-height=&quot;930&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: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 기존 default namespace 내의 pod와 app-test에 추가된 nginx pod만 index pattern에 추가된 것을 확인할 수 있다. kube-logging에 추가된 nginx pod는 수집 대상에서 제외되었다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;결론&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;본 포스팅에서는 Fluentd를 활용하여 수집, 정제 방안에 대해 알아보았으며, ElasticSearch가 제공하는 ILM 정책(용량, 기간)에 따라 HOT, WARM, COLD, FROZEN 아카이브로 구분하여 관리하는 저장소 체계 설계 및 Kibana의 트래픽 모니터링, 구간별 이상징후 탐지 기능, 거래 추적 등에 대한 보다 시각화가 강조된 대시보드 생성과정 등에 대해서는&amp;nbsp;별도 포스팅에서 다뤄보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;지금까지 ElasticSearch를 활용한 Kubernetes 로깅 환경 구성 방안에 대해 알아보았다. ElasticSearch를 활용하여 데이터를 수집하고, 저장하고, 분석하는 과정은 마이크로서비스 환경에서 반드시 선행되어야 할 부분이다. 특히 로깅의 경우 개발 초기 단계부터 활용 가능한 Telemetry 요소이므로 환경 구성 초반에 반드시 구성하여 활용 가치를 높여 나가도록 하자.&lt;/span&gt;&lt;/p&gt;</description>
      <category>③ 클라우드/ⓜ MSA</category>
      <category>EFK</category>
      <category>elasticsearch</category>
      <category>elasticsearch kubernetes</category>
      <category>elk</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/762</guid>
      <comments>https://waspro.tistory.com/762#entry762comment</comments>
      <pubDate>Sun, 6 Feb 2022 14:50:19 +0900</pubDate>
    </item>
    <item>
      <title>2022년 waspro 활동</title>
      <link>https://waspro.tistory.com/notice/760</link>
      <description>&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;2021년 그리고 임인년&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;2021년은 정말 바쁜 한 해였습니다. A 은행 차세대 프로젝트에 착수하여 MSA PL로 프로젝트를 수행하며, 목표한 포스팅을 많이 작성하지 못했지만, 대규모 프로젝트에서 마이크로서비스 아키텍처를 적용하기 위해 지금도 바쁜 하루를 보내고 있습니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;2021년에는 총 30개의 포스팅 글을 작성하였습니다........ 클라우드 &amp;amp; MSA 관련 포스팅을 시작한 2018년 이후 가장 저조하게 작성한 포스팅 수이지만, 그만큼 아직 작성하지 못한 지식들이 머리속에 가득하다는 의미겠네요. 곧 하나씩 풀어 내도록 하겠습니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;2021년도 역시 클라우드와 MSA 관련 포스팅이 주를 이뤘었는데요.&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; font-family: 'Noto Serif KR';&quot;&gt;OSS 7&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;클라우드 6&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;MSA 10&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;CI/CD 7&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;의도하지 않게 골고루 작성을 했네요.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;최근 기술과 관리의 중간에서 많은 고민과 함께 임인년을 시작했습니다. 검은 호랑이의 해인 임인년에는 어떠한 활용을 할 것인지 목표를 잡고 또 다시 2022년을 시작해 보도록 하겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;[MSA &amp;amp; Cloud]&lt;/span&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;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;kubevirt&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;EFK 최적화&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;TDD 구현&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;EventSourcing 구현&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;s&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;ElasticSearch 구축 (https://waspro.tistory.com/762)&lt;/span&gt;&lt;/s&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Istio multi cluster mesh&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;s&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Cloud Native DR 설계하기 (&lt;a style=&quot;color: #dddddd;&quot; href=&quot;https://waspro.tistory.com/784&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://waspro.tistory.com/784&lt;/a&gt;)&lt;/span&gt;&lt;/s&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;[Kubernetes]&lt;/span&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;span style=&quot;font-family: 'Noto Serif KR'; color: #dddddd;&quot;&gt;&lt;s&gt;다중 클러스터 접근 구성 kubectl config use-context minikube (https://waspro.tistory.com/763)&lt;/s&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #dddddd;&quot;&gt;&lt;s&gt;CSI (https://waspro.tistory.com/771)&lt;/s&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #dddddd;&quot;&gt;&lt;s&gt;Kuberhealthy (https://waspro.tistory.com/772)&lt;/s&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;KubeInvaders&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Kubefed&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Metallb (ARP PROXY, ARP SPEAKER)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Terraform&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Velero&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;보안&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #dddddd;&quot;&gt;&lt;s&gt;Pod 생성 및 종료 관리 (Health Check &amp;amp; Graceful Shutdown) (https://waspro.tistory.com/764)&lt;/s&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;멀티클러스터 - Karmada(Kubernetes Armada)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #dddddd;&quot;&gt;&lt;s&gt;kubernetes kubectl plugin (https://waspro.tistory.com/765)&lt;/s&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;정책 관리 엔진 - Kyverno&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;리소스 및 구성 관련 모니터링 도구 - popeye&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;VPA &amp;amp; Goldilocks&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #dddddd;&quot;&gt;&lt;s&gt;polaris (https://waspro.tistory.com/766)&lt;/s&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #dddddd;&quot;&gt;&lt;s&gt;kubernetes 보안도구 (https://waspro.tistory.com/767)&lt;/s&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #dddddd;&quot;&gt;&lt;s&gt;NetworkPolicy (https://waspro.tistory.com/768)&lt;/s&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #dddddd;&quot;&gt;&lt;s&gt;k&lt;/s&gt;&lt;s&gt;ubectl 자동완성 (https://waspro.tistory.com/769)&lt;/s&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Admission Controller&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Kubernetes Event Export&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;kubectl kustomize&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;s&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Terraform으로 EC2 인스턴스 생성하기 (&lt;a style=&quot;color: #dddddd;&quot; href=&quot;https://waspro.tistory.com/773&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://waspro.tistory.com/773&lt;/a&gt;)&lt;/span&gt;&lt;/s&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;s&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Multi Container Design (&lt;a style=&quot;color: #dddddd;&quot; href=&quot;https://waspro.tistory.com/775&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://waspro.tistory.com/775&lt;/a&gt;)&lt;/span&gt;&lt;/s&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;s&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Kubernetes Node 가용성 검증 (&lt;a style=&quot;color: #dddddd;&quot; href=&quot;https://waspro.tistory.com/777&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://waspro.tistory.com/777&lt;/a&gt;)&lt;/span&gt;&lt;/s&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;[AWS]&lt;/span&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;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;랜딩존&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;AWS NETWORK 구조 설계&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;AWS Batch&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #dddddd;&quot;&gt;&lt;s&gt;AWS EKS에 MariaDB 설치하기 (&lt;a style=&quot;color: #dddddd;&quot; href=&quot;https://waspro.tistory.com/778&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://waspro.tistory.com/778&lt;/a&gt;)&lt;/s&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #dddddd;&quot;&gt;&lt;s&gt;AWS CodeSeriess 파이프라인 구성하기 (&lt;a style=&quot;color: #dddddd;&quot; href=&quot;https://waspro.tistory.com/780&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://waspro.tistory.com/780&lt;/a&gt;)&lt;/s&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;[CI/CD &amp;amp; Framework]&lt;/span&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;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Git sourcetree / Git gitkraken&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Eclipse Sub Project 구조&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Jenkins Pipeline&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;- NotifyFailed&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Jenkins Pipeline Pod Deployment Check Stage&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;GitlabCI&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Atlassian 시점 기반 Commit&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Git Cherry-Pick&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Telepresence&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;subtree&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Harbor Image Sign&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;- Harbor Image Sign CI/CD 체계 적용&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;git master&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;- git reset, revert&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;- git amend&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;- git rebase, merge&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Kanban&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;s&gt;&lt;/s&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #dddddd;&quot;&gt;&lt;s&gt;git ops &amp;amp; argocd (https://waspro.tistory.com/758)&lt;/s&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #dddddd;&quot;&gt;&lt;s&gt;&lt;/s&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #dddddd;&quot;&gt;&lt;s&gt;PMD (https://waspro.tistory.com/759)&lt;/s&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;span style=&quot;text-decoration: line-through;&quot;&gt;SI 프로젝트와 배포 전략 (&lt;a style=&quot;color: #dddddd;&quot; href=&quot;https://waspro.tistory.com/787&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://waspro.tistory.com/787&lt;/a&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;[OpenSource Software]&lt;/span&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;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Kafka&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;- Kafka NewTopic&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;- Kafka sample test 환경&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;- Kafka 순서보장&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Schema Registry&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Apache HTTPD&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;- SSLSESSIONCOOKIE&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Redis&amp;nbsp;Pub/Sub&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;[Spring Boot]&lt;/span&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;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;JACOCO&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Spring Batch&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;i&gt;&lt;u&gt;#앞으로 추가되는 내용은 계속 업데이트 예정&lt;/u&gt;&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;작년과 마찬가지로 여전히 코로나로 인해 어려운 한해를 보내고 있습니다. 임인년 검은 호랑이의 기운으로 코로나를 극복하고, 예전 모습으로 되돌아 갈 수 있는 날이 하루 빨리 돌아왔으면 좋겠습니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;올 해도 화이팅!&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;# 참조&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; Pod Topology Spread Constraints&lt;br /&gt;- kubectl get pods podsname -n namespaces -o yaml&lt;br /&gt;- kubectl get pods -w&lt;br /&gt;- kubectl get service --all-namespaces&lt;br /&gt;- kubectl get service -A&lt;br /&gt;- kubectl --kubeconfig=$HOME/.kube/config rollout restart deployment/test-deployment&lt;br /&gt;- kubectl create secrets tls / ingress yaml apply&lt;br /&gt;- docker exec -itu root contianer_name bash&lt;br /&gt;- watch -n interval &quot;command&quot;&lt;br /&gt;- fuser -ck /dev/sdb1 &amp;amp;&amp;amp; umount /dev/sdb1&lt;br /&gt;- curl -k (--insecure : https test)&lt;br /&gt;- curl -X POST \&lt;br /&gt;http://localhost:8080/servlet \&lt;br /&gt;-H 'Accept: application/json' \&lt;br /&gt;-H 'Cache-Control: no-cache' \&lt;br /&gt;-H 'Content-Type: multipart/mixed' \&lt;br /&gt;-H 'Postman-Token: 406bfbe4-94d3-0c70-1b0f-0d1fdb2a6f5b' \&lt;br /&gt;-H 'content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW' \&lt;br /&gt;-F 'uploadFile=@access_log.2021.01.06'&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;# 실행계획&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;# 디버깅&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;# Release Layup / BranchUp&lt;/span&gt;&lt;/p&gt;</description>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/notice/760</guid>
      <pubDate>Tue, 1 Feb 2022 22:05:37 +0900</pubDate>
    </item>
    <item>
      <title>정적분석도구 &amp;quot;PMD&amp;quot; 활용</title>
      <link>https://waspro.tistory.com/759</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;개요&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;큰 규모의 프로젝트에서는 개발자가이드나 코드리뷰 만으로 소스코드 내에 산재되어 있는 잠재적인 문제점을 모두 찾아내기 어렵다. 따라서 소스코드 전체를 일괄로 스캔하여 문제가 되는 패턴을 자동으로 찾아서 수정할 수 있는 도구의 도입은 반드시 필요하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;대표적인 정적분석 도구 중 하나인 PMD에 대해 알아보도록 하자. PMD, SpotBugs(FindBugs), SonarQube 등 정적분석도구는 소스코드에 대한 inspection을 강화하여 이후 발생가능한 이슈들을 개발단계에서 점검하는 도구이다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;STS(Spring-Tool-Suit) PMD Plugin 적용&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1) Help &amp;gt; Eclipse Marketplace&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;pmd1.png&quot; data-origin-width=&quot;1273&quot; data-origin-height=&quot;923&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lg4lf/btrr06gh9vG/hpxlBpSHg1iWHr7xM9RGgk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lg4lf/btrr06gh9vG/hpxlBpSHg1iWHr7xM9RGgk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lg4lf/btrr06gh9vG/hpxlBpSHg1iWHr7xM9RGgk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Flg4lf%2Fbtrr06gh9vG%2FhpxlBpSHg1iWHr7xM9RGgk%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;1273&quot; height=&quot;923&quot; data-filename=&quot;pmd1.png&quot; data-origin-width=&quot;1273&quot; data-origin-height=&quot;923&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: 'Noto Serif KR'; color: #000000;&quot;&gt;2) Search &amp;gt; PMD &amp;gt; PMD Install&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;pmd2.png&quot; data-origin-width=&quot;1274&quot; data-origin-height=&quot;923&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bNAOZA/btrr5Vw9Xhq/Jt20O0ZjE1wjkkeqE8u0mk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bNAOZA/btrr5Vw9Xhq/Jt20O0ZjE1wjkkeqE8u0mk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bNAOZA/btrr5Vw9Xhq/Jt20O0ZjE1wjkkeqE8u0mk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbNAOZA%2Fbtrr5Vw9Xhq%2FJt20O0ZjE1wjkkeqE8u0mk%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;1274&quot; height=&quot;923&quot; data-filename=&quot;pmd2.png&quot; data-origin-width=&quot;1274&quot; data-origin-height=&quot;923&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: 'Noto Serif KR'; color: #000000;&quot;&gt;한 차례 리스타트 후 pmd 정적분석 도구를 사용할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;PMD 활용&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1) PMD Ruleset 커스터마이징&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;1277&quot; data-origin-height=&quot;838&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/miE1H/btrr5VxLRkl/TiTgexo6thwSRUYtyuoWk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/miE1H/btrr5VxLRkl/TiTgexo6thwSRUYtyuoWk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/miE1H/btrr5VxLRkl/TiTgexo6thwSRUYtyuoWk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmiE1H%2Fbtrr5VxLRkl%2FTiTgexo6thwSRUYtyuoWk1%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;1277&quot; height=&quot;838&quot; data-origin-width=&quot;1277&quot; data-origin-height=&quot;838&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: 'Noto Serif KR'; color: #000000;&quot;&gt;window &amp;gt; Preferences &amp;gt; PMD &amp;gt; Rule Configuration 접속 시 위와 같이 Default Rule을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;RuleSet은 여러 형태로 커스터마이징이 가능하다. &amp;lt;no grouping&amp;gt;으로 되어 있는 콤보박스를 선택하여 정렬하며 RuleSet을 선택할 수 있다. Default로 등록되어 있는 Active Rule 448개 모두를 등록할 경우 개발자는 개발하기 이전에 inspection의 늪에 허덕여야 할 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;PMD는 총 5단계의 Inspection Level을 관리하고 있다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;Blocker : High Level의 Inspection으로 반드시 적용되어야 할 Rule (빨간색)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Critical : Medium High Level의 Inspection으로 컴파일 에러가 발생하는 Rule 등급 (하늘색)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Urgent : Medium Level의 Inspection으로 권고하는 Rule (초록색)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Important : Medium Low Level의 Inspection (보라색)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Warning : Low Level의 Inspection (파란색)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1277&quot; data-origin-height=&quot;838&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cXsyoW/btrr1h9Xp7N/btiEwqKp1OUIQuWgtnPKy1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cXsyoW/btrr1h9Xp7N/btiEwqKp1OUIQuWgtnPKy1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cXsyoW/btrr1h9Xp7N/btiEwqKp1OUIQuWgtnPKy1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcXsyoW%2Fbtrr1h9Xp7N%2FbtiEwqKp1OUIQuWgtnPKy1%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;1277&quot; height=&quot;838&quot; data-origin-width=&quot;1277&quot; data-origin-height=&quot;838&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: 'Noto Serif KR'; color: #000000;&quot;&gt;개인적으로 추천하는 RuleSet은 두가지 형태의 조합이다. 먼저, Priority 기준으로 Blocker와 Critical을 선택한다. 전체 448개 중 70개가 그 대상이다. (버전별 상이할 수 있음)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;다음으로 Rule Set을 선택하여, Best Practices와 Security 전체를 선택한다. 이때, Best Practices 전체 적용에 부담이 있을 경우에는 +로 Security만 포함하여 적용하도록 한다.&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;1276&quot; data-origin-height=&quot;838&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDtX58/btrr6AGKvgM/UjoY05uas7KJMV0NA8HD3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDtX58/btrr6AGKvgM/UjoY05uas7KJMV0NA8HD3k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDtX58/btrr6AGKvgM/UjoY05uas7KJMV0NA8HD3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDtX58%2Fbtrr6AGKvgM%2FUjoY05uas7KJMV0NA8HD3k%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;1276&quot; height=&quot;838&quot; data-origin-width=&quot;1276&quot; data-origin-height=&quot;838&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: 'Noto Serif KR'; color: #000000;&quot;&gt;이 경우 전체 448개 중 154개의 Ruleset이 등록된 상태가 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;등록이 완료되면, 코드 검사를 실행한다. PMD는 아래와 같은 기능 목록을 지원한다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;Clear Violation Reviews : Violation Review 초기화&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Find Suspect Cut And Paste Detector : 중복 코드 체크&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Clear Violations : Violation 초기화&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Check Code : 코드 Inspection&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1275&quot; data-origin-height=&quot;1005&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vq5M1/btrsaSgcNXx/3yir0Q3BpkfKrXoKn0smO1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vq5M1/btrsaSgcNXx/3yir0Q3BpkfKrXoKn0smO1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vq5M1/btrsaSgcNXx/3yir0Q3BpkfKrXoKn0smO1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fvq5M1%2FbtrsaSgcNXx%2F3yir0Q3BpkfKrXoKn0smO1%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;1275&quot; height=&quot;1005&quot; data-origin-width=&quot;1275&quot; data-origin-height=&quot;1005&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: 'Noto Serif KR'; color: #000000;&quot;&gt;2) Check Code&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;먼저 개발된 소스코드의 Inspection을 실행해 보도록 하자. src/main/java &amp;gt; 우클릭 &amp;gt; PMD &amp;gt; Check Code 클릭 시 선택된 소스 코드 하위를 포함하여 검증한다. 이로인해 대체로 src/main/java를 선택한 후 check를 수행한다.&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;1276&quot; data-origin-height=&quot;1006&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwzrj4/btrsc0ZlQua/Yz2kCMXfDs2GhQBbzCGKCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwzrj4/btrsc0ZlQua/Yz2kCMXfDs2GhQBbzCGKCk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwzrj4/btrsc0ZlQua/Yz2kCMXfDs2GhQBbzCGKCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbwzrj4%2Fbtrsc0ZlQua%2FYz2kCMXfDs2GhQBbzCGKCk%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;1276&quot; height=&quot;1006&quot; data-origin-width=&quot;1276&quot; data-origin-height=&quot;1006&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; font-family: 'Noto Serif KR';&quot;&gt;위와 같이 Violation에 걸린 항목들을 확인할 수 있다. &lt;span style=&quot;background-color: #ffffff;&quot;&gt;PMD 퍼스펙티브를 열거나 Violations Overview 뷰를 열면 간단한 통계를 볼 수 있다. 또한 색깔로 구분된 Violation Level을 기준으로 기본 선택되어 있는 화면에서 선택을 해제하여 위반 우선 순위별로 확인 가능하고 각 파일의 위반사항 갯수, 라인당 위반 수, 메소드당 위반 수를 볼 수 있다. &lt;/span&gt;가장 많이 걸리는 부분인 SystemPrintLn에 대한 예를 위와 같이 확인할 수 있다.&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;1275&quot; data-origin-height=&quot;1005&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cvBcUT/btrr2zbD5qT/C60KGqxQlNdG9mr1pte3ek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cvBcUT/btrr2zbD5qT/C60KGqxQlNdG9mr1pte3ek/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cvBcUT/btrr2zbD5qT/C60KGqxQlNdG9mr1pte3ek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcvBcUT%2Fbtrr2zbD5qT%2FC60KGqxQlNdG9mr1pte3ek%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;1275&quot; height=&quot;1005&quot; data-origin-width=&quot;1275&quot; data-origin-height=&quot;1005&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Violations Outline 뷰에서 Violation을 예외처리하는 Mark as reviewed를 선택할 수 있다. 이 경우 아래와 같이 주석이 달리며, // NOPMD가 포함되어 있는 라인은 PMD Violation에서 예외처리된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;// NOPMD by nrson on 22. 1. 31 오전 1:48&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;1276&quot; data-origin-height=&quot;1007&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xurqN/btrsaRO8Y91/ckR6q1n1oKRim6WR1V2PQK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xurqN/btrsaRO8Y91/ckR6q1n1oKRim6WR1V2PQK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xurqN/btrsaRO8Y91/ckR6q1n1oKRim6WR1V2PQK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxurqN%2FbtrsaRO8Y91%2FckR6q1n1oKRim6WR1V2PQK%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;1276&quot; height=&quot;1007&quot; data-origin-width=&quot;1276&quot; data-origin-height=&quot;1007&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;위와 같이 Marked 된 Violation은 주석과 함께 제외된 것을 확인할 수 있다. (DemoController가 Violations Overview에서 제거됨)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;반대로 Clear Violation Review를 통해 주석을 제거하고 다시 Violation 상태로 돌릴 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;3) Find Suspect Cut And Paste Detector&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;CPD는 PMD의 기능 중 하나인 중복코드 검사 기능이다. window &amp;gt; Preferences &amp;gt; PMD &amp;gt; CPD preference에서 기본 설정(&lt;span style=&quot;background-color: #ffffff;&quot;&gt;Minimum Tile Size)&lt;/span&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;1276&quot; data-origin-height=&quot;1007&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b1yojQ/btrr4xEcBW8/WkJfl3tO9CvjhPE9Vp0pVK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b1yojQ/btrr4xEcBW8/WkJfl3tO9CvjhPE9Vp0pVK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b1yojQ/btrr4xEcBW8/WkJfl3tO9CvjhPE9Vp0pVK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb1yojQ%2Fbtrr4xEcBW8%2FWkJfl3tO9CvjhPE9Vp0pVK%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;1276&quot; height=&quot;1007&quot; data-origin-width=&quot;1276&quot; data-origin-height=&quot;1007&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; font-family: 'Noto Serif KR';&quot;&gt;proejct 이름 &amp;gt; 우클릭 &amp;gt; PMD &amp;gt; Find Suspect Cut And Paste 클릭 시 하위 중복코드 여부를 검증한다.&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;1274&quot; data-origin-height=&quot;1007&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cu1ns2/btrr3naIkOC/pg589LVekMphfI9rDaWxvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cu1ns2/btrr3naIkOC/pg589LVekMphfI9rDaWxvK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cu1ns2/btrr3naIkOC/pg589LVekMphfI9rDaWxvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcu1ns2%2Fbtrr3naIkOC%2Fpg589LVekMphfI9rDaWxvK%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;1274&quot; height=&quot;1007&quot; data-origin-width=&quot;1274&quot; data-origin-height=&quot;1007&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: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;위와 같이 Minimum Tile-size를 지정하고 OK를 클릭하면,&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&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;1277&quot; data-origin-height=&quot;1008&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eauz1u/btrsc143iHC/ZHKmVHAls9JbKHNI1TIMw1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eauz1u/btrsc143iHC/ZHKmVHAls9JbKHNI1TIMw1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eauz1u/btrsc143iHC/ZHKmVHAls9JbKHNI1TIMw1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Feauz1u%2Fbtrsc143iHC%2FZHKmVHAls9JbKHNI1TIMw1%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;1277&quot; height=&quot;1008&quot; data-origin-width=&quot;1277&quot; data-origin-height=&quot;1008&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; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;CPD View 탭을 통해 대상 클래스 목록과 중복 코드를 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;4) Add rule&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;새로운 Rule을 추가하는 방법에 대해 알아보자. Rule은 Java Code를 직접 작성하여 추가하는 방법과 XPath를 사용하여 Rule을 추가하는 방법이 있다. 이번 포스팅에서는 XPath를 이용하여 추가하는 방법에 대해 알아보자.&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;추가할 Rule은 Best Practices에 default로 추가되어 있는 &lt;span style=&quot;color: #000000;&quot;&gt;SystemPrintln &lt;/span&gt;Rule을 커스터마이징하여 myManagedPrintln을 만들어보도록 하자. SystemPrintln은 System.out.print로 시작하는 구문 모두에 Critical Alert을 날리지만, 커스터마이징하여 생성한 &lt;span style=&quot;color: #000000;&quot;&gt;myManagedPrintln은 S&lt;span style=&quot;color: #000000;&quot;&gt;ystem.out.print는 허용하고, &lt;span style=&quot;color: #000000;&quot;&gt;S&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;ystem.out.println만 Critical Alert으로 날리는 룰이다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;먼저 Rule Designer를 실행하여 원하는 Rule이 정상 동작하는지 확인해 보도록 하자.&lt;/span&gt;&lt;/span&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;1276&quot; data-origin-height=&quot;891&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AXMsK/btrr9fpMFVo/ExfMliSKGryPCln6d7ZsD1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AXMsK/btrr9fpMFVo/ExfMliSKGryPCln6d7ZsD1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AXMsK/btrr9fpMFVo/ExfMliSKGryPCln6d7ZsD1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAXMsK%2Fbtrr9fpMFVo%2FExfMliSKGryPCln6d7ZsD1%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;1276&quot; height=&quot;891&quot; data-origin-width=&quot;1276&quot; data-origin-height=&quot;891&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; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Window &amp;gt; Preferences &amp;gt; PMD &amp;gt; Rule Configuration &amp;gt; 오른쪽 중간 쯤 Rule Designer를 클릭한다.&lt;/span&gt;&lt;/span&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;1281&quot; data-origin-height=&quot;803&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yOBm7/btrscOrnUjP/aund8SlF0BEabi9KnzoZHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yOBm7/btrscOrnUjP/aund8SlF0BEabi9KnzoZHK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yOBm7/btrscOrnUjP/aund8SlF0BEabi9KnzoZHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyOBm7%2FbtrscOrnUjP%2Faund8SlF0BEabi9KnzoZHK%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;1281&quot; height=&quot;803&quot; data-origin-width=&quot;1281&quot; data-origin-height=&quot;803&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; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;화면에는 아래 네가지 구성요소로 이루어져 있다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Source Code : 테스트를 진행할 샘플 소스코드를 작성한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;XPath Query : Violation을 정의하는 XPath식을 작성한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Abstract Syntax Tree / XPath / Symbol Table (Data Flow Analysis) : Source Code를 기준으로 AST 또는 Data Flow가 자동 작성된다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Result Window : Violation 결과가 출력된다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;위 샘플을 보면 System.out.print와 System.out.println이 사용되고 있으며, 이 중 &lt;span style=&quot;color: #000000;&quot;&gt;System.out.println이&lt;/span&gt; Violation에 걸려 Result Window에 하나의 결과가 출력되는 것을 확인할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;테스트가 완료되면, Rule을 등록한다.&lt;/span&gt;&lt;/span&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;1276&quot; data-origin-height=&quot;891&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b0ylXq/btrsfXn5SJ2/J5WSUK70P0bUtTbcARmakk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b0ylXq/btrsfXn5SJ2/J5WSUK70P0bUtTbcARmakk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b0ylXq/btrsfXn5SJ2/J5WSUK70P0bUtTbcARmakk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0ylXq%2FbtrsfXn5SJ2%2FJ5WSUK70P0bUtTbcARmakk%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;1276&quot; height=&quot;891&quot; data-origin-width=&quot;1276&quot; data-origin-height=&quot;891&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; font-family: 'Noto Serif KR';&quot;&gt;Window &amp;gt; Preferences &amp;gt; PMD &amp;gt; Rule Configuration &amp;gt; 오른쪽 상단의 Add rule을 클릭한다.&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;1280&quot; data-origin-height=&quot;896&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfp2fN/btrr2tvxkmo/2OOFQ0REtvqvFrK1tUzll0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfp2fN/btrr2tvxkmo/2OOFQ0REtvqvFrK1tUzll0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfp2fN/btrr2tvxkmo/2OOFQ0REtvqvFrK1tUzll0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbfp2fN%2Fbtrr2tvxkmo%2F2OOFQ0REtvqvFrK1tUzll0%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;896&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;896&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;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Rule name : Rule 이름 지정 (MyPrintlnRule)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;RuleSet : RuleSet 중 대상을 지정 (Best Practices)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Implemented by : 앞서 Rule 추가를 위한 두가지 방식(Java Class or XPath script) 중 하나를 선택 (XPath script)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Implementation class : XPath script의 경우 자동 매핑되며, Java Class의 경우 impl class 지정&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Target language : Language, min version, max version 지정 (Java)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Priority : 5가지 단계 중 지정 (Critical)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&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;896&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pdeSK/btrr5UT3juI/V95fq07vQt7eH9cMStdFS1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pdeSK/btrr5UT3juI/V95fq07vQt7eH9cMStdFS1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pdeSK/btrr5UT3juI/V95fq07vQt7eH9cMStdFS1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpdeSK%2Fbtrr5UT3juI%2FV95fq07vQt7eH9cMStdFS1%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;896&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;896&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;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Window : Description 작성&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Message : 참고 문구&lt;/span&gt;&lt;/li&gt;
&lt;/ul&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;896&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Z2NQm/btrsc0ZZrn0/bdQMKcnJKMMjS4DO1M34v1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Z2NQm/btrsc0ZZrn0/bdQMKcnJKMMjS4DO1M34v1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Z2NQm/btrsc0ZZrn0/bdQMKcnJKMMjS4DO1M34v1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZ2NQm%2Fbtrsc0ZZrn0%2FbdQMKcnJKMMjS4DO1M34v1%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;896&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;896&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;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Window : XPath 식 작성&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1643650255933&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//Name[
    starts-with(@Image, 'System.out.println')
    or
    starts-with(@Image, 'System.err.println')
    ]&lt;/code&gt;&lt;/pre&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;896&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lKsA8/btrr4xxYSFO/zIKrF6BR7h6ZjLVP3vRAQk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lKsA8/btrr4xxYSFO/zIKrF6BR7h6ZjLVP3vRAQk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lKsA8/btrr4xxYSFO/zIKrF6BR7h6ZjLVP3vRAQk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlKsA8%2Fbtrr4xxYSFO%2FzIKrF6BR7h6ZjLVP3vRAQk%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;896&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;896&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;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Window : Sample Code 작성&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1643650308389&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Foo{
    Logger log = Logger.getLogger(Foo.class.getName());
    public void testA () {
        System.out.println(&quot;Entering test&quot;);
        // Better use this
        log.fine(&quot;Entering test&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;Finish를 클릭하면, 아래와 같이 Rule이 추가된 것을 확인할 수 있다.&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;1280&quot; data-origin-height=&quot;896&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rZMLQ/btrr1H8T1QX/gQrZEKdrdMudjYXNnr3Abk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rZMLQ/btrr1H8T1QX/gQrZEKdrdMudjYXNnr3Abk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rZMLQ/btrr1H8T1QX/gQrZEKdrdMudjYXNnr3Abk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrZMLQ%2Fbtrr1H8T1QX%2FgQrZEKdrdMudjYXNnr3Abk%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;896&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;896&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; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;동작을 검증하기에 앞서 SystemPrintln Rule이 적용된 상태로 현재 소스코드의 Inspection을 실행해 보도록 하자.&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;1280&quot; data-origin-height=&quot;896&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWmhlM/btrsfXVXZIC/6AaR4bOxgokFf5oO13Nyp0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWmhlM/btrsfXVXZIC/6AaR4bOxgokFf5oO13Nyp0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWmhlM/btrsfXVXZIC/6AaR4bOxgokFf5oO13Nyp0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWmhlM%2FbtrsfXVXZIC%2F6AaR4bOxgokFf5oO13Nyp0%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;896&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;896&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; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;위와 같이 System.out.println, System.out.print 모두 Critical Inspection Alert이 나타나는 것을 확인할 수 있다. 그럼 이제 추가한 Rule을 Test하기 위해 SystemPrintln은 Deselect하고, 추가한 MyPrintlnRule을 Select한 후 Check Code를 실행해 보자.&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvkax5/btrseR9wTex/PO5auoTGowgMMF0bO1AKM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvkax5/btrseR9wTex/PO5auoTGowgMMF0bO1AKM1/img.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;896&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvkax5/btrseR9wTex/PO5auoTGowgMMF0bO1AKM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbvkax5%2FbtrseR9wTex%2FPO5auoTGowgMMF0bO1AKM1%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;896&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjurO2/btrr2tvxyXE/ehyEbxGujYyUvpLqRbyKZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjurO2/btrr2tvxyXE/ehyEbxGujYyUvpLqRbyKZ1/img.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;896&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjurO2/btrr2tvxyXE/ehyEbxGujYyUvpLqRbyKZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjurO2%2Fbtrr2tvxyXE%2FehyEbxGujYyUvpLqRbyKZ1%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;896&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;위와 같이 Println만 Inspection Alert이 나타나는 것을 확인할 수 있다. 이와 같이 룰을 &lt;span style=&quot;color: #000000;&quot;&gt;커스터마이징하여&lt;/span&gt;&amp;nbsp;나만의 룰셋을 등록관리할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;추가로 IPv4에 대한 하드코딩 제한 Rule - MyAvoidIPv4HardCodingRule, 주민번호에 대한 하드코딩 제한 Rule - MyAvoidR&lt;span style=&quot;background-color: #ffffff; color: #202020;&quot;&gt;RNumHardCodingRule을 생성하고 적용해 보자.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #202020;&quot;&gt;[&lt;span style=&quot;color: #000000;&quot;&gt;MyAvoidIPv4HardCodingRule&lt;/span&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1643650726977&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[XPath]
//PrimaryExpression/PrimaryPrefix/Literal
 [matches(@Image,
  '(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)'
 )]
 
 [Example]
 class DemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);
		String ip = &quot;192.168.1.120&quot;;
		System.out.println(ip);
		System.out.print(ip);
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #202020;&quot;&gt;[&lt;span style=&quot;color: #000000;&quot;&gt;MyAvoidR&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #202020;&quot;&gt;RNumHardCodingRule&lt;/span&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1643650647843&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[XPath]
//PrimaryExpression/PrimaryPrefix/Literal
 [matches(@Image,
  '(?:[0-9]{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[1,2][0-9]|3[0,1]))-[1-4][0-9]{6}'
 )]

[Example]
class DemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);
		String rrn = &quot;831021-1234567&quot;;
		System.out.println(rrn);
		System.out.print(rrn);
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: 0px;&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;1280&quot; data-origin-height=&quot;896&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQwln7/btrsfTsrDZt/0vfg6aecLtZRER5TZ6vzx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQwln7/btrsfTsrDZt/0vfg6aecLtZRER5TZ6vzx1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQwln7/btrsfTsrDZt/0vfg6aecLtZRER5TZ6vzx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQwln7%2FbtrsfTsrDZt%2F0vfg6aecLtZRER5TZ6vzx1%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;896&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;896&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; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;이와 같이 XPath 식을 추가하여 손쉽게 Rule을 생성할 수 있다. (&lt;a href=&quot;https://www.ing.iac.es//~docs/external/java/pmd/xpathruletutorial.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;XPath Rule&lt;/a&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;5) Import rule set / Export selected rules&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;이제 생성한 Ruleset을 다른 개발자나 다른 환경으로 이관하기 위해 Export / Import하는 과정에 대해 알아보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;먼저, Export Selected rules이다. Export는 앞에 체크되어 있는 Rule을 기준으로 추출하는 것이 아닌 선택되어진 Rule을 추출하는 것에 유의하여 Ruleset 파일을 생성한다.&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;1280&quot; data-origin-height=&quot;896&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MEwTd/btrr4wMCLXv/nYKhOw6hdzxlg4rFPymYD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MEwTd/btrr4wMCLXv/nYKhOw6hdzxlg4rFPymYD0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MEwTd/btrr4wMCLXv/nYKhOw6hdzxlg4rFPymYD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMEwTd%2Fbtrr4wMCLXv%2FnYKhOw6hdzxlg4rFPymYD0%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;896&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;896&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; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;참고 차 전체 Ruleset 파일을 업로드 해두도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1643642294857&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;ruleset xmlns=&quot;http://pmd.sourceforge.net/ruleset/2.0.0&quot;
         xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
         name=&quot;pmd-test-ruleset&quot;
         xsi:schemaLocation=&quot;http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd&quot;&amp;gt;
   &amp;lt;description&amp;gt;PMD Plugin preferences rule set&amp;lt;/description&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/AbstractClassWithoutAbstractMethod&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/AbstractClassWithoutAnyMethod&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/AbstractNaming&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/AccessorClassGeneration&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/AccessorMethodGeneration&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/performance.xml/AddEmptyString&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/bestpractices.xml/ApexAssertionsShouldIncludeMessage&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/security.xml/ApexBadCrypto&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/security.xml/ApexCRUDViolation&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/errorprone.xml/ApexCSRF&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/security.xml/ApexDangerousMethods&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/documentation.xml/ApexDoc&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/security.xml/ApexInsecureEndpoint&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/security.xml/ApexOpenRedirect&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/security.xml/ApexSOQLInjection&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/security.xml/ApexSharingViolations&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/security.xml/ApexSuggestUsingNamedCred&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/bestpractices.xml/ApexUnitTestClassShouldHaveAsserts&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/bestpractices.xml/ApexUnitTestMethodShouldHaveIsTestAnnotation&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/bestpractices.xml/ApexUnitTestShouldNotUseSeeAllDataTrue&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/security.xml/ApexXSSFromEscapeFalse&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/security.xml/ApexXSSFromURLParam&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/performance.xml/AppendCharacterWithChar&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/ArrayIsStoredDirectly&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/ecmascript/codestyle.xml/AssignmentInOperand&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/AssignmentInOperand&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/AssignmentToNonFinalStatic&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/AtLeastOneConstructor&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/AvoidAccessibilityAlteration&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/performance.xml/AvoidArrayLoops&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/AvoidAssertAsIdentifier&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/xsl/performance.xml/AvoidAxisNavigation&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/AvoidBranchingStatementAsLastInLoop&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/performance.xml/AvoidCalendarDateCreation&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/AvoidCallingFinalize&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/AvoidCatchingGenericException&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/AvoidCatchingNPE&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/AvoidCatchingThrowable&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/performance.xml/AvoidDebugStatements&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/AvoidDecimalLiteralsInBigDecimalConstructor&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/design.xml/AvoidDeeplyNestedIfStmts&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/AvoidDeeplyNestedIfStmts&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/vm/design.xml/AvoidDeeplyNestedIfStmts&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/errorprone.xml/AvoidDirectAccessTriggerMap&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/performance.xml/AvoidDmlStatementsInLoops&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/AvoidDollarSigns&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/AvoidDuplicateLiterals&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/AvoidEnumAsIdentifier&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/AvoidFieldNameMatchingMethodName&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/AvoidFieldNameMatchingTypeName&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/performance.xml/AvoidFileStream&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/AvoidFinalLocalVariable&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/bestpractices.xml/AvoidGlobalModifier&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/errorprone.xml/AvoidHardcodingId&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/AvoidInstanceofChecksInCatchClause&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/performance.xml/AvoidInstantiatingObjectsInLoops&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/AvoidLiteralsInIfCondition&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/bestpractices.xml/AvoidLogicInTrigger&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/AvoidLosingExceptionInformation&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/AvoidMessageDigestField&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/AvoidMultipleUnaryOperators&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/errorprone.xml/AvoidNonExistentAnnotations&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/AvoidPrefixingMethodParameters&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/AvoidPrintStackTrace&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/AvoidProtectedFieldInFinalClass&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/AvoidProtectedMethodInFinalClassNotExtending&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/AvoidReassigningCatchVariables&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/AvoidReassigningLoopVariables&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/AvoidReassigningParameters&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/vm/bestpractices.xml/AvoidReassigningParameters&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/AvoidRethrowingException&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/performance.xml/AvoidSoqlInLoops&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/performance.xml/AvoidSoslInLoops&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/AvoidStringBufferField&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/multithreading.xml/AvoidSynchronizedAtMethodLevel&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/plsql/codestyle.xml/AvoidTabCharacter&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/multithreading.xml/AvoidThreadGroup&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/AvoidThrowingNewInstanceOfSameException&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/AvoidThrowingNullPointerException&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/AvoidThrowingRawExceptionTypes&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/ecmascript/errorprone.xml/AvoidTrailingComma&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/AvoidUncheckedExceptionsInSignatures&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/AvoidUsingHardCodedIP&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/AvoidUsingNativeCode&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/AvoidUsingOctalValues&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/performance.xml/AvoidUsingShortType&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/multithreading.xml/AvoidUsingVolatile&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/ecmascript/bestpractices.xml/AvoidWithStatement&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/BeanMembersShouldSerialize&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/performance.xml/BigIntegerInstantiation&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/BooleanGetMethodName&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/performance.xml/BooleanInstantiation&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/BrokenNullCheck&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/performance.xml/ByteInstantiation&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/CallSuperFirst&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/CallSuperInConstructor&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/CallSuperLast&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/CheckResultSet&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/CheckSkipResult&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/ClassCastExceptionWithToArray&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/codestyle.xml/ClassNamingConventions&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/ClassNamingConventions&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/ClassWithOnlyPrivateConstructorsShouldBeFinal&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/CloneMethodMustBePublic&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/CloneMethodMustImplementCloneable&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/CloneMethodReturnTypeMustMatchClassName&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/CloneThrowsCloneNotSupportedException&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/CloseResource&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/plsql/codestyle.xml/CodeFormat&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/design.xml/CognitiveComplexity&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/CognitiveComplexity&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/CollapsibleIfStatements&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/vm/design.xml/CollapsibleIfStatements&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/documentation.xml/CommentContent&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/CommentDefaultAccessModifier&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/documentation.xml/CommentRequired&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/documentation.xml/CommentSize&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/CompareObjectsWithEquals&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/ComparisonWithNaN&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/ConfusingTernary&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/performance.xml/ConsecutiveAppendsShouldReuse&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/performance.xml/ConsecutiveLiteralAppends&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/ecmascript/bestpractices.xml/ConsistentReturn&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/ConstantsInInterface&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/ConstructorCallsOverridableMethod&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/ControlStatementBraces&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/CouplingBetweenObjects&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/design.xml/CyclomaticComplexity&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/CyclomaticComplexity&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/plsql/design.xml/CyclomaticComplexity&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/DataClass&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/DataflowAnomalyAnalysis&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/bestpractices.xml/DebugsShouldUseLoggingLevel&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/DefaultLabelNotLastInSwitchStmt&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/DefaultPackage&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/DetachedTestCase&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/DoNotCallGarbageCollectionExplicitly&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/DoNotExtendJavaLangError&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/DoNotExtendJavaLangThrowable&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/DoNotHardCodeSDCard&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/DoNotTerminateVM&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/DoNotThrowExceptionInFinally&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/multithreading.xml/DoNotUseThreads&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/multithreading.xml/DontCallThreadRun&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/DontImportJavaLang&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/DontImportSun&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/jsp/bestpractices.xml/DontNestJsfInJstlIteration&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/DontUseFloatTypeForLoopIndices&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/DoubleBraceInitialization&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/multithreading.xml/DoubleCheckedLocking&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/DuplicateImports&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/jsp/codestyle.xml/DuplicateJspImports&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/performance.xml/EagerlyLoadedDescribeSObjectResult&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/errorprone.xml/EmptyCatchBlock&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/EmptyCatchBlock&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/EmptyFinalizer&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/EmptyFinallyBlock&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/vm/errorprone.xml/EmptyForeachStmt&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/errorprone.xml/EmptyIfStmt&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/EmptyIfStmt&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/vm/errorprone.xml/EmptyIfStmt&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/EmptyInitializer&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/EmptyMethodInAbstractClassShouldBeAbstract&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/errorprone.xml/EmptyStatementBlock&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/EmptyStatementBlock&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/EmptyStatementNotInLoop&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/EmptySwitchStatements&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/EmptySynchronizedBlock&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/EmptyTryBlock&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/errorprone.xml/EmptyTryOrFinallyBlock&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/errorprone.xml/EmptyWhileStmt&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/EmptyWhileStmt&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/ecmascript/errorprone.xml/EqualComparison&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/EqualsNull&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/ExceptionAsFlowControl&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/design.xml/ExcessiveClassLength&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/ExcessiveClassLength&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/ExcessiveImports&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/ExcessiveMethodLength&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/plsql/design.xml/ExcessiveMethodLength&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/plsql/design.xml/ExcessiveObjectLength&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/plsql/design.xml/ExcessivePackageBodyLength&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/plsql/design.xml/ExcessivePackageSpecificationLength&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/design.xml/ExcessiveParameterList&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/ExcessiveParameterList&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/plsql/design.xml/ExcessiveParameterList&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/design.xml/ExcessivePublicCount&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/ExcessivePublicCount&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/vm/design.xml/ExcessiveTemplateLength&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/plsql/design.xml/ExcessiveTypeLength&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/ExtendsObject&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/codestyle.xml/FieldDeclarationsShouldBeAtStart&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/FieldDeclarationsShouldBeAtStartOfClass&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/codestyle.xml/FieldNamingConventions&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/FieldNamingConventions&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/FinalFieldCouldBeStatic&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/FinalParameterInAbstractMethod&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/FinalizeDoesNotCallSuperFinalize&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/FinalizeOnlyCallsSuperFinalize&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/FinalizeOverloaded&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/FinalizeShouldBeProtected&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/ForLoopCanBeForeach&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/plsql/codestyle.xml/ForLoopNaming&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/ForLoopShouldBeWhileLoop&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/ForLoopVariableCount&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/codestyle.xml/ForLoopsMustUseBraces&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/ecmascript/codestyle.xml/ForLoopsMustUseBraces&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/ForLoopsMustUseBraces&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/codestyle.xml/FormalParameterNamingConventions&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/FormalParameterNamingConventions&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/GenericsNaming&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/ecmascript/bestpractices.xml/GlobalVariable&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/GodClass&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/GuardLogStatement&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/security.xml/HardCodedCryptoKey&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/IdempotentOperations&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/IdenticalCatchBranches&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/codestyle.xml/IfElseStmtsMustUseBraces&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/ecmascript/codestyle.xml/IfElseStmtsMustUseBraces&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/IfElseStmtsMustUseBraces&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/codestyle.xml/IfStmtsMustUseBraces&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/ecmascript/codestyle.xml/IfStmtsMustUseBraces&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/IfStmtsMustUseBraces&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/jsp/security.xml/IframeMissingSrcAttribute&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/ImmutableField&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/ImplicitSwitchFallThrough&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/ImportFromSamePackage&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/errorprone.xml/InaccessibleAuraEnabledGetter&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/performance.xml/InefficientEmptyStringCheck&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/performance.xml/InefficientStringBuffering&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/ecmascript/errorprone.xml/InnaccurateNumericLiteral&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/security.xml/InsecureCryptoIv&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/InstantiationToGetClass&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/performance.xml/InsufficientStringBufferDeclaration&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/performance.xml/IntegerInstantiation&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/pom/errorprone.xml/InvalidDependencyTypes&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/InvalidLogMessageFormat&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/JUnit4SuitesShouldUseSuiteAnnotation&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/JUnit4TestShouldUseAfterAnnotation&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/JUnit4TestShouldUseBeforeAnnotation&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/JUnit4TestShouldUseTestAnnotation&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/JUnit5TestShouldBePackagePrivate&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/JUnitAssertionsShouldIncludeMessage&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/JUnitSpelling&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/JUnitStaticSuite&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/JUnitTestContainsTooManyAsserts&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/JUnitTestsShouldIncludeAssert&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/JUnitUseExpected&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/jsp/errorprone.xml/JspEncoding&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/JumbledIncrementer&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/LawOfDemeter&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/plsql/codestyle.xml/LineLength&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/LinguisticNaming&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/LiteralsFirstInComparisons&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/LocalHomeNamingConvention&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/LocalInterfaceSessionNamingConvention&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/LocalVariableCouldBeFinal&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/codestyle.xml/LocalVariableNamingConventions&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/LocalVariableNamingConventions&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/LoggerIsNotStaticFinal&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/LogicInversion&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/performance.xml/LongInstantiation&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/LongVariable&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/LooseCoupling&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/LoosePackageCoupling&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/MDBAndSessionBeanNamingConvention&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/MIsLeadingVariableName&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/MethodArgumentCouldBeFinal&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/codestyle.xml/MethodNamingConventions&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/MethodNamingConventions&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/MethodReturnsInternalArray&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/errorprone.xml/MethodWithSameNameAsEnclosingClass&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/MethodWithSameNameAsEnclosingClass&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/MisplacedNullCheck&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/plsql/codestyle.xml/MisplacedPragma&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/MissingOverride&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/MissingSerialVersionUID&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/MissingStaticMethodInNonInstantiatableClass&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/xml/errorprone.xml/MistypedCDATASection&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/ModifiedCyclomaticComplexity&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/MoreThanOneLogger&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/MutableStaticState&quot;/&amp;gt;
   &amp;lt;rule class=&quot;net.sourceforge.pmd.lang.rule.XPathRule&quot; deprecated=&quot;false&quot; dfa=&quot;false&quot;
         language=&quot;java&quot;
         message=&quot;Avoid System.out.println&quot;
         name=&quot;MyPrintlnRule&quot;
         typeResolution=&quot;true&quot;&amp;gt;
      &amp;lt;description&amp;gt;class Foo{&amp;amp;#xD;
    Logger log = Logger.getLogger(Foo.class.getName());&amp;amp;#xD;
    public void testA () {&amp;amp;#xD;
        System.out.print(&quot;Entering test&quot;);&amp;amp;#xD;
        System.out.println(&quot;Entering test&quot;);&amp;amp;#xD;
        // Better use this&amp;amp;#xD;
        log.fine(&quot;Entering test&quot;);&amp;amp;#xD;
    }&amp;amp;#xD;
}&amp;lt;/description&amp;gt;
      &amp;lt;priority&amp;gt;2&amp;lt;/priority&amp;gt;
      &amp;lt;properties&amp;gt;
         &amp;lt;property name=&quot;xpath&quot;&amp;gt;
            &amp;lt;value&amp;gt;//Name[&amp;amp;#xD;
    starts-with(@Image, 'System.out.println')&amp;amp;#xD;
    or&amp;amp;#xD;
    starts-with(@Image, 'System.err.println')&amp;amp;#xD;
    ]&amp;lt;/value&amp;gt;
         &amp;lt;/property&amp;gt;
      &amp;lt;/properties&amp;gt;
   &amp;lt;/rule&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/NPathComplexity&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/plsql/design.xml/NPathComplexity&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/design.xml/NcssConstructorCount&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/NcssConstructorCount&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/NcssCount&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/design.xml/NcssMethodCount&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/NcssMethodCount&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/plsql/design.xml/NcssMethodCount&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/plsql/design.xml/NcssObjectCount&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/design.xml/NcssTypeCount&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/NcssTypeCount&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/jsp/bestpractices.xml/NoClassAttribute&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/ecmascript/codestyle.xml/NoElseReturn&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/jsp/bestpractices.xml/NoHtmlComments&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/vm/design.xml/NoInlineJavaScript&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/jsp/design.xml/NoInlineScript&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/jsp/design.xml/NoInlineStyleInformation&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/vm/design.xml/NoInlineStyles&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/jsp/bestpractices.xml/NoJspForward&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/jsp/design.xml/NoLongScripts&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/NoPackage&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/jsp/design.xml/NoScriptlets&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/jsp/security.xml/NoUnsanitizedJSPExpression&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/NonCaseLabelInSwitchStatement&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/NonStaticInitializer&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/multithreading.xml/NonThreadSafeSingleton&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/NullAssignment&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/codestyle.xml/OneDeclarationPerLine&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/OneDeclarationPerLine&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/OnlyOneReturn&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/performance.xml/OperationWithLimitsInLoop&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/performance.xml/OptimizableToArrayCall&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/errorprone.xml/OverrideBothEqualsAndHashcode&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/OverrideBothEqualsAndHashcode&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/PackageCase&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/PositionLiteralsFirstInCaseInsensitiveComparisons&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/PositionLiteralsFirstInComparisons&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/PrematureDeclaration&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/PreserveStackTrace&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/PrimitiveWrapperInstantiation&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/pom/errorprone.xml/ProjectVersionAsDependencyVersion&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/ProperCloneImplementation&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/ProperLogger&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/codestyle.xml/PropertyNamingConventions&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/performance.xml/RedundantFieldInitializer&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/RemoteInterfaceNamingConvention&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/RemoteSessionInterfaceNamingConvention&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/ReplaceEnumerationWithIterator&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/ReplaceHashtableWithMap&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/ReplaceVectorWithList&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/ReturnEmptyArrayRatherThanNull&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/ReturnEmptyCollectionRatherThanNull&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/ReturnFromFinallyBlock&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/ecmascript/bestpractices.xml/ScopeForInVariable&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/ShortClassName&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/performance.xml/ShortInstantiation&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/ShortMethodName&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/ShortVariable&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/SignatureDeclareThrowsException&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/SimpleDateFormatNeedsLocale&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/SimplifiableTestAssertion&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/SimplifiedTernary&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/SimplifyBooleanAssertion&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/SimplifyBooleanExpressions&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/SimplifyBooleanReturns&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/SimplifyConditional&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/performance.xml/SimplifyStartsWith&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/SingleMethodSingleton&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/SingletonClassReturningNewInstance&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/SingularField&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/StaticEJBFieldShouldBeFinal&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/design.xml/StdCyclomaticComplexity&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/StdCyclomaticComplexity&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/StringBufferInstantiationWithChar&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/performance.xml/StringInstantiation&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/performance.xml/StringToString&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/SuspiciousConstantFieldName&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/SuspiciousEqualsMethodName&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/SuspiciousHashcodeMethodName&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/SuspiciousOctalEscape&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/SwitchDensity&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/SwitchStmtsShouldHaveDefault&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/SystemPrintln&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/plsql/errorprone.xml/TO_DATEWithoutDateFormat&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/plsql/errorprone.xml/TO_DATE_TO_CHAR&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/plsql/errorprone.xml/TO_TIMESTAMPWithoutDateFormat&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/TestClassWithoutTestCases&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/errorprone.xml/TestMethodsMustBeInTestClasses&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/plsql/bestpractices.xml/TomKytesDespair&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/performance.xml/TooFewBranchesForASwitchStatement&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/design.xml/TooManyFields&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/TooManyFields&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/plsql/design.xml/TooManyFields&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/TooManyMethods&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/plsql/design.xml/TooManyMethods&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/TooManyStaticImports&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/documentation.xml/UncommentedEmptyConstructor&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/documentation.xml/UncommentedEmptyMethodBody&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/UnconditionalIfStatement&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/UnnecessaryAnnotationValueElement&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/ecmascript/codestyle.xml/UnnecessaryBlock&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/UnnecessaryBooleanAssertion&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/UnnecessaryCaseChange&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/UnnecessaryCast&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/UnnecessaryConstructor&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/UnnecessaryConversionTemporary&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/UnnecessaryFullyQualifiedName&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/UnnecessaryImport&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/UnnecessaryLocalBeforeReturn&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/UnnecessaryModifier&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/ecmascript/codestyle.xml/UnnecessaryParentheses&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/UnnecessaryReturn&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/performance.xml/UnnecessaryWrapperObjectCreation&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/ecmascript/codestyle.xml/UnreachableCode&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/multithreading.xml/UnsynchronizedStaticDateFormatter&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/multithreading.xml/UnsynchronizedStaticFormatter&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/UnusedAssignment&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/UnusedFormalParameter&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/UnusedImports&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/bestpractices.xml/UnusedLocalVariable&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/UnusedLocalVariable&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/vm/bestpractices.xml/UnusedMacroParameter&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/UnusedNullCheckInEquals&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/UnusedPrivateField&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/UnusedPrivateMethod&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/performance.xml/UseArrayListInsteadOfVector&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/performance.xml/UseArraysAsList&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/UseAssertEqualsInsteadOfAssertTrue&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/UseAssertNullInsteadOfAssertTrue&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/UseAssertSameInsteadOfAssertTrue&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/UseAssertTrueInsteadOfAssertEquals&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/ecmascript/bestpractices.xml/UseBaseWithParseInt&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/UseCollectionIsEmpty&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/xsl/codestyle.xml/UseConcatOnce&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/multithreading.xml/UseConcurrentHashMap&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/UseCorrectExceptionLogging&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/UseDiamondOperator&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/UseEqualsToCompareStrings&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/performance.xml/UseIOStreamsWithApacheCommonsFileItem&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/performance.xml/UseIndexOfChar&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/UseLocaleWithCaseConversions&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/multithreading.xml/UseNotifyAllInsteadOfNotify&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/UseObjectForClearerAPI&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/UseProperClassLoader&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/UseShortArrayInitializer&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/UseStandardCharsets&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/performance.xml/UseStringBufferForStringAppends&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/performance.xml/UseStringBufferLength&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/UseTryWithResources&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/UseUnderscoresInNumericLiterals&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/UseUtilityClass&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/UseVarargs&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/errorprone.xml/UselessOperationOnImmutable&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/design.xml/UselessOverridingMethod&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/UselessParentheses&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/UselessQualifiedThis&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/performance.xml/UselessStringValueOf&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/codestyle.xml/VariableNamingConventions&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/VariableNamingConventions&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/vf/security.xml/VfCsrf&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/vf/security.xml/VfHtmlStyleTagXss&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/vf/security.xml/VfUnescapeEl&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/bestpractices.xml/WhileLoopWithLiteralBoolean&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/apex/codestyle.xml/WhileLoopsMustUseBraces&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/ecmascript/codestyle.xml/WhileLoopsMustUseBraces&quot;/&amp;gt;
   &amp;lt;rule ref=&quot;category/java/codestyle.xml/WhileLoopsMustUseBraces&quot;/&amp;gt;
&amp;lt;/ruleset&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;중간 부분에 추가한 MyPrintlnRule이 아래와 같이 등록되어 있는 것을 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1643642312959&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;rule class=&quot;net.sourceforge.pmd.lang.rule.XPathRule&quot; deprecated=&quot;false&quot; dfa=&quot;false&quot;
         language=&quot;java&quot;
         message=&quot;Avoid System.out.println&quot;
         name=&quot;MyPrintlnRule&quot;
         typeResolution=&quot;true&quot;&amp;gt;
      &amp;lt;description&amp;gt;class Foo{&amp;amp;#xD;
    Logger log = Logger.getLogger(Foo.class.getName());&amp;amp;#xD;
    public void testA () {&amp;amp;#xD;
        System.out.print(&quot;Entering test&quot;);&amp;amp;#xD;
        System.out.println(&quot;Entering test&quot;);&amp;amp;#xD;
        // Better use this&amp;amp;#xD;
        log.fine(&quot;Entering test&quot;);&amp;amp;#xD;
    }&amp;amp;#xD;
}&amp;lt;/description&amp;gt;
      &amp;lt;priority&amp;gt;2&amp;lt;/priority&amp;gt;
      &amp;lt;properties&amp;gt;
         &amp;lt;property name=&quot;xpath&quot;&amp;gt;
            &amp;lt;value&amp;gt;//Name[&amp;amp;#xD;
    starts-with(@Image, 'System.out.println')&amp;amp;#xD;
    or&amp;amp;#xD;
    starts-with(@Image, 'System.err.println')&amp;amp;#xD;
    ]&amp;lt;/value&amp;gt;
         &amp;lt;/property&amp;gt;
      &amp;lt;/properties&amp;gt;
   &amp;lt;/rule&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;Import는 반대로 추출한 Rule을 반영하는 과정이다. 대체로 현재 반영되어 있는 Rule과 중복을 방지하기 위해 전체 Rule을 삭제하고, 반영하는 것을 추천한다.&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;1280&quot; data-origin-height=&quot;896&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Cfmh7/btrseQJzhGD/JbE5CcMZP9KH3J2c0IcDoK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Cfmh7/btrseQJzhGD/JbE5CcMZP9KH3J2c0IcDoK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Cfmh7/btrseQJzhGD/JbE5CcMZP9KH3J2c0IcDoK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCfmh7%2FbtrseQJzhGD%2FJbE5CcMZP9KH3J2c0IcDoK%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;896&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;896&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; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;위와 같이 Export selected rules를 통해 추출한 ruleset 파일을 반영하고, import by copy를 선택한 후 OK를 클릭한다.&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;1280&quot; data-origin-height=&quot;896&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVm0yl/btrr9gI0B5j/8LKBCZz2JfhIWbQlqm6AW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVm0yl/btrr9gI0B5j/8LKBCZz2JfhIWbQlqm6AW1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVm0yl/btrr9gI0B5j/8LKBCZz2JfhIWbQlqm6AW1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVm0yl%2Fbtrr9gI0B5j%2F8LKBCZz2JfhIWbQlqm6AW1%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;896&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;896&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; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;위와 같이 MyPrintlnRule을 포함한 Ruleset이 적용된 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;결론&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;PMD는 소스코드를 분석하여 프로그램의 부적절한 부분을 찾아내고 성능을 높이도록 도와주는 정적분석 도구로, 사용하지 않는 변수, 불필요한 catch block, Object 생성 등을 찾아내며, 시스템 개발공정의 구현 및 테스트단계에서 정적분석에 활용할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;PMD와 같은 정적분석 도구의 적용은 코드의 품질을 높일 뿐 아니라, 이후 발생 가능한 Rework을 줄일 수 있는 방안 중 하나이다. 열심히 코딩하고, 재작업하는 일이 반복되면, 생산성도 떨어질 뿐 아니라, 개발자 별 코딩 스타일 차이에 따라 코드의 일관성이 떨어질 수도 있다. 이와 같은 문제들을 사전에 진단하고 대처하기 위한 정적분석도구의 도입은 반드시 이뤄져야 할 부분이다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>⑤ 개발, 데이터베이스/ⓒ CI CD</category>
      <category>CPD</category>
      <category>FindSecurityBugs</category>
      <category>PMD</category>
      <category>PMD Rule Export</category>
      <category>PMD Rule Import</category>
      <category>Rule Designer</category>
      <category>SonarQube</category>
      <category>SpotBugs</category>
      <category>정적분석</category>
      <category>정적분석도구</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/759</guid>
      <comments>https://waspro.tistory.com/759#entry759comment</comments>
      <pubDate>Sat, 29 Jan 2022 16:21:05 +0900</pubDate>
    </item>
    <item>
      <title>GitOps 프로세스 설계(feat. ArgoCD)</title>
      <link>https://waspro.tistory.com/758</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;개요&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;DevOps는 최근 가속화 되고 있는 추세이다. 특히 조직의 변화가 어려운 기업에서도 DevOps에 관심을 갖고 체계를 수립해 보고자 변화의 자세를 갖고 있다. 현재 프로젝트 중인 a은행에서도 DevOps에 대한 제언을 요청하고 있으며, 조직과 프로세스 그리고 도구 관점에서 제언할 수 있는 부분들을 지속적으로 검토하고 있다. 특히 Security 관점에서 DecSecOps에 대한 논의 역시 이루어지고 있다. 전체 프로세스에 대한 부분은 이후 다시한번 다뤄보도록 하고, 이번 포스팅에서는 Ops 관점에서 지속적인 배포 프로세스의 속도 개선을 위한 체계 개선 방안 중 하나인 GitOps에 대해 알아보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;DevOps를 위해 많은 도구들이 도입되고 활용되고 있지만, 그 중 대표적인이면서, 클라우드 환경에서 빠지지 않는 도구를 이야기 하자면, 단연 Git일 것이다. GitOps는 Git을 기반으로 Ops를 실현하는 방식을 의미하며, Human Error를&amp;nbsp;줄이고 배포 파이프라인의 안정성을 개선하여 복잡한 클라우드 환경 특히 마이크로서비스 환경에서 더 자주 배포하면서도 오류를 줄이고 배포에 대한 결과를 수집하여 개선할 수 있는 방안들을 마련할 수 있는 일종의 배포 설계 패턴이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;GitOps는 Git 자체만으로 구현되는 것이 아닌 Git를 활용하여 Ops를 구현하는 도구가 필요하다. 대표적인 도구로는 ArgoCD, Terraform, FluxCD 등이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;GitOps 장점&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;앞서 이야기한데로 GitOps는 Git을 사용하여 인프라를 구성하는 자동화된 Ops 패턴이다. GitOps를 적용하면 몇가지 유용한 장점을 얻을 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;먼저 GitOps는 자동화된 파이프라인 구성으로 Git 변경사항이 운영환경에 동시에 반영되어 별도 프로세스 없어 배포 속도를 높일 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;두번째로 변경사항을 비교하여 클러스터가 Git과 일치하지 않으면 일치하지 않는 코드를 식별하여 알려준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;세번째로 Kubernetes GitOps 에서는 Git이 Kubernetes 외부에서 수행된 모든 클러스터 변경 사항에 대한 로그를 제공하므로 문제를 추적하기 쉽다. 이 로그를 사용하여 변경 사항을 관리하고 어떤 개발자가 어떤 변경 사항을 푸시했는지, 언제, 어떤 클러스터가 변경되었는지 확인할 수 있다. 이 측면은 시스템의 안정성을 보장한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;네번째로 버그를 재현하거나 안정적인 롤백을 생성할 때 유용하다. GitOps를 통해 DevOps 엔지니어는 치명적인 오류가 발생한 후에도 시스템 전체를 이전 버전으로 신속하게 복구할 수 있는 신뢰할 수 있는 버전을 관리할 수 있다. 또한 단 몇 분 만에 복구가 가능하므로 데이터 손실을 최소화 할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;마지막으로 GitOps를 사용하면 자동화된 피드백을 통해 배포하는 평균 시간을 크게 단축하므로 생산성도 크게 향상된다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;ArgoCD 개요&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;ArgoCD는 전체 인프라를 빠르고 일관성 있게 롤백할 수 있는 지속적인 배포기능을 제공하여 GitOps 모범 사례를 활용할 수 있도록 지원한다. 특히 Kubernetes와 함께 전 과정을 자동화하고 'source of truth'인 Git Repository의 내용과 항상 일치하는지 지속적으로 점검하여 배포 속도를 높인다. ArgoCD를 통해 DevOps 전문가는 다음 작업을 수행할 수 있다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;버전 추적 수행&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;드리프트 감지에 대한 알림 수신&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;전체 인프라를 빠르게 로드&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Git 리포지토리 내에 기록된 모든 지점으로 롤백&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;또한 ArgoCD는 직관적인 UI, 내장된 웹 인터페이스 및 애플리케이션에 대한 통계를 실시간으로 제공하는 API 서버로 인해 시스템 모니터링을 더 쉽게 만든다. 또한 CI를 지원하는 CLI도 함께 제공된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;지금부터는 ArgoCD를 구축해 보고, 대시보드를 살펴보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;ArgoCD 설치&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1) namespace 생성&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1643385429900&quot; class=&quot;lsl&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 ~]# kubectl create namespace argocd
namespace/argocd created
[root@ip-192-168-78-195 ~]# kubectl get namespace argocd
NAME     STATUS   AGE
argocd   Active   8s
[root@ip-192-168-78-195 ~]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2) ArgoCD Manifest download 및 install&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1643385429900&quot; class=&quot;angelscript&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 ~]# kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
customresourcedefinition.apiextensions.k8s.io/applications.argoproj.io created
customresourcedefinition.apiextensions.k8s.io/appprojects.argoproj.io created
serviceaccount/argocd-application-controller created
serviceaccount/argocd-dex-server created
serviceaccount/argocd-redis created
serviceaccount/argocd-server created
role.rbac.authorization.k8s.io/argocd-application-controller created
role.rbac.authorization.k8s.io/argocd-dex-server created
role.rbac.authorization.k8s.io/argocd-server created
clusterrole.rbac.authorization.k8s.io/argocd-application-controller created
clusterrole.rbac.authorization.k8s.io/argocd-server created
rolebinding.rbac.authorization.k8s.io/argocd-application-controller created
rolebinding.rbac.authorization.k8s.io/argocd-dex-server created
rolebinding.rbac.authorization.k8s.io/argocd-redis created
rolebinding.rbac.authorization.k8s.io/argocd-server created
clusterrolebinding.rbac.authorization.k8s.io/argocd-application-controller created
clusterrolebinding.rbac.authorization.k8s.io/argocd-server created
configmap/argocd-cm created
configmap/argocd-cmd-params-cm created
configmap/argocd-gpg-keys-cm created
configmap/argocd-rbac-cm created
configmap/argocd-ssh-known-hosts-cm created
configmap/argocd-tls-certs-cm created
secret/argocd-secret created
service/argocd-dex-server created
service/argocd-metrics created
service/argocd-redis created
service/argocd-repo-server created
service/argocd-server created
service/argocd-server-metrics created
deployment.apps/argocd-dex-server created
deployment.apps/argocd-redis created
deployment.apps/argocd-repo-server created
deployment.apps/argocd-server created
statefulset.apps/argocd-application-controller created
networkpolicy.networking.k8s.io/argocd-application-controller-network-policy created
networkpolicy.networking.k8s.io/argocd-dex-server-network-policy created
networkpolicy.networking.k8s.io/argocd-redis-network-policy created
networkpolicy.networking.k8s.io/argocd-repo-server-network-policy created
networkpolicy.networking.k8s.io/argocd-server-network-policy created
[root@ip-192-168-78-195 ~]# kubectl get all -n argocd
NAME                                      READY   STATUS    RESTARTS   AGE
pod/argocd-application-controller-0       1/1     Running   0          42s
pod/argocd-dex-server-66f865ffb4-2jrrd    1/1     Running   0          43s
pod/argocd-redis-5b6967fdfc-xw8pn         1/1     Running   0          43s
pod/argocd-repo-server-656c76778f-8999w   1/1     Running   0          43s
pod/argocd-server-cd68f46f8-rzs2t         1/1     Running   0          43s

NAME                            TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE
service/argocd-dex-server       ClusterIP   10.100.24.138    &amp;lt;none&amp;gt;        5556/TCP,5557/TCP,5558/TCP   43s
service/argocd-metrics          ClusterIP   10.100.133.53    &amp;lt;none&amp;gt;        8082/TCP                     43s
service/argocd-redis            ClusterIP   10.100.27.165    &amp;lt;none&amp;gt;        6379/TCP                     43s
service/argocd-repo-server      ClusterIP   10.100.42.130    &amp;lt;none&amp;gt;        8081/TCP,8084/TCP            43s
service/argocd-server           ClusterIP   10.100.183.103   &amp;lt;none&amp;gt;        80/TCP,443/TCP               43s
service/argocd-server-metrics   ClusterIP   10.100.53.55     &amp;lt;none&amp;gt;        8083/TCP                     43s

NAME                                 READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/argocd-dex-server    1/1     1            1           43s
deployment.apps/argocd-redis         1/1     1            1           43s
deployment.apps/argocd-repo-server   1/1     1            1           43s
deployment.apps/argocd-server        1/1     1            1           43s

NAME                                            DESIRED   CURRENT   READY   AGE
replicaset.apps/argocd-dex-server-66f865ffb4    1         1         1       43s
replicaset.apps/argocd-redis-5b6967fdfc         1         1         1       43s
replicaset.apps/argocd-repo-server-656c76778f   1         1         1       43s
replicaset.apps/argocd-server-cd68f46f8         1         1         1       43s

NAME                                             READY   AGE
statefulset.apps/argocd-application-controller   1/1     43s
[root@ip-192-168-78-195 ~]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;3) ArgoCD CLI Download&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1643385429901&quot; class=&quot;angelscript&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 ~]# curl -sSL -o /usr/local/bin/argocd https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64
[root@ip-192-168-78-195 ~]# chmod +x /usr/local/bin/argocd
[root@ip-192-168-78-195 ~]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;4) NodePort 설정&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1643385429901&quot; class=&quot;yaml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 ~]# kubectl edit service argocd-server -n argocd
...
...
spec:
  clusterIP: 10.100.183.103
  clusterIPs:
  - 10.100.183.103
  ipFamilies:
  - IPv4
  ipFamilyPolicy: SingleStack
  ports:
  - nodePort: 31000
    name: http
    port: 80
    protocol: TCP
    targetPort: 8080
  - nodePort: 31443
    name: https
    port: 443
    protocol: TCP
    targetPort: 8080
  selector:
    app.kubernetes.io/name: argocd-server
  sessionAffinity: None
  type: NodePort
...
...
[root@ip-192-168-78-195 ~]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;# AWS Worker Node가 사용하는 보안그룹에 Local IP와 Workstation EC2 Node에서 사용하는 보안그룹에서 31000 노드 포트가 접근할 수 있도록 인바운드 규칙 추가&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;5) 대시보드 접속&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;1600&quot; data-origin-height=&quot;791&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cVNEqt/btrr2Af8EMp/24mC8XATiIl7kIOvH41wok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cVNEqt/btrr2Af8EMp/24mC8XATiIl7kIOvH41wok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cVNEqt/btrr2Af8EMp/24mC8XATiIl7kIOvH41wok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcVNEqt%2Fbtrr2Af8EMp%2F24mC8XATiIl7kIOvH41wok%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;1600&quot; height=&quot;791&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;791&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;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Host : http://external_ip:31000&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Username : admin&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Password : kubectl&amp;nbsp;-n&amp;nbsp;argocd&amp;nbsp;get&amp;nbsp;secret&amp;nbsp;argocd-initial-admin-secret&amp;nbsp;-o&amp;nbsp;jsonpath=&quot;{.data.password}&quot;&amp;nbsp;|&amp;nbsp;base64&amp;nbsp;-d;&amp;nbsp;echo&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;6) Password 변경 (login &amp;gt; account update-password)&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1643385429901&quot; class=&quot;asciidoc&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 ~]# argocd login 192.168.89.241:31000
WARNING: server certificate had error: x509: cannot validate certificate for 192.168.89.241 because it doesn't contain any IP SANs. Proceed insecurely (y/n)? y
Username: admin
Password: 
'admin:login' logged in successfully
Context '192.168.89.241:31000' updated
[root@ip-192-168-78-195 ~]# argocd account update-password
*** Enter password of currently logged in user (admin): 
*** Enter new password for user admin: 
*** Confirm new password for user admin: 
Password updated
Context '192.168.89.241:31000' updated
[root@ip-192-168-78-195 ~]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;7) 대시보드 로그인&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;1602&quot; data-origin-height=&quot;792&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GO49N/btrr2XoEg4x/CifkAOJ040En5ZaG7IENz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GO49N/btrr2XoEg4x/CifkAOJ040En5ZaG7IENz0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GO49N/btrr2XoEg4x/CifkAOJ040En5ZaG7IENz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGO49N%2Fbtrr2XoEg4x%2FCifkAOJ040En5ZaG7IENz0%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;1602&quot; height=&quot;792&quot; data-origin-width=&quot;1602&quot; data-origin-height=&quot;792&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: 'Noto Serif KR'; color: #000000;&quot;&gt;8) GitLab 구성&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;1894&quot; data-origin-height=&quot;802&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Kq1yL/btrr3m9xSNl/pMSASOEa71XNlIwBBJnwP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Kq1yL/btrr3m9xSNl/pMSASOEa71XNlIwBBJnwP1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Kq1yL/btrr3m9xSNl/pMSASOEa71XNlIwBBJnwP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKq1yL%2Fbtrr3m9xSNl%2FpMSASOEa71XNlIwBBJnwP1%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;1894&quot; height=&quot;802&quot; data-origin-width=&quot;1894&quot; data-origin-height=&quot;802&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: 'Noto Serif KR'; color: #000000;&quot;&gt;root path에 deployment.yaml 파일과 service.yaml 파일을 생성한다. 물론 이후 관리는 IDE를 통해 하는 것을 권장하며, 운영자 관점에서 권한 분리를 통해 반영 가능한 MAINTAINER의 역할에 따라 프로젝트가 관리될 수 있도록 한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1643391970636&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[deployment.yaml]
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx
        ports:
        - containerPort: 80&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1643391992570&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[service.yaml]
apiVersion: v1
kind: Service
metadata:
  name: my-nginx
  labels:
    run: my-nginx
spec:
  type: NodePort
  ports:
  - nodePort: 32000
    port: 80
    protocol: TCP
  selector:
    run: my-nginx&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;9) New App Add&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;[GENERAL]&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;1603&quot; data-origin-height=&quot;727&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uSSwk/btrr1miEOHG/0Q7vvTXlFtm5pk6SedvBVK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uSSwk/btrr1miEOHG/0Q7vvTXlFtm5pk6SedvBVK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uSSwk/btrr1miEOHG/0Q7vvTXlFtm5pk6SedvBVK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuSSwk%2Fbtrr1miEOHG%2F0Q7vvTXlFtm5pk6SedvBVK%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;1603&quot; height=&quot;727&quot; data-origin-width=&quot;1603&quot; data-origin-height=&quot;727&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;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Application Name : 배포할 어플리케이션 이름 (sample-argocd-test)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Project : ArgoCD 내 어플리케이션 그룹 (default)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;SYNC POLICY : (Manual, Automatic) Git 변동사항을 자동으로 반영할 것인지, 수동으로 반영할 것인지 선택 (Manual)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;# 자주 발생하는 Error&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1643385429902&quot; class=&quot;markdown&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Unable to create application: Application.argoproj.io &quot;ArgoCDSample&quot; is invalid: metadata.name: Invalid value: &quot;ArgoCDSample&quot;: a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character (e.g. 'example.com', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*')
해결방안
&amp;gt; Applicaton Name은 소문자, 숫자, ., -만 허용함. 대문자나, 허용되지 않은 특수문자가 포함될 경우 위 에러 발생&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;[SOURCE]&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;1603&quot; data-origin-height=&quot;484&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dJhu7B/btrr4yaPR4t/B7IeZnGhc0cnxCZXddrFxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dJhu7B/btrr4yaPR4t/B7IeZnGhc0cnxCZXddrFxk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dJhu7B/btrr4yaPR4t/B7IeZnGhc0cnxCZXddrFxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdJhu7B%2Fbtrr4yaPR4t%2FB7IeZnGhc0cnxCZXddrFxk%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;1603&quot; height=&quot;484&quot; data-origin-width=&quot;1603&quot; data-origin-height=&quot;484&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;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Repository URL : Git 저장소 URL (git 또는 helm) (http://192.168.84.159:8090/root/myargocdproject.git)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Revision : Git의 어떤 Revision을 바라 볼 것인지 지정 (HEAD, main, tag 등) (main)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Path : Repository 내 변경사항을 관리할 파일이 위치한 경로 지정 (. 일 경우 root) (.)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;# 자주 발생하는 Error&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1643385429902&quot; class=&quot;sql&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Unable to create application: application spec for sample-argocd-test is invalid: InvalidSpecError: repository not accessible: rpc error: code = Unknown desc = error testing repository connectivity: Get &quot;http://192.168.84.159:8090/root/myargocdproject.git/info/refs?service=git-upload-pack&quot;: context deadline exceeded (Client.Timeout exceeded while awaiting headers)
해결방안
&amp;gt; gitlab 서버와의 통신 문제로 gitlab이 설치된 E2C 인스턴스가 사용하는 보안그룹의 인바운드 규칙에 GitLab이 사용중인 Port(8090)를 Worker Node가 사용하는 보안그룹 허용&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;[DESTINATION &amp;amp; DIRECTORY]&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;1602&quot; data-origin-height=&quot;851&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xjVz2/btrr4xJLxi1/k68zt8XKrtXAgETvRpGZE0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xjVz2/btrr4xJLxi1/k68zt8XKrtXAgETvRpGZE0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xjVz2/btrr4xJLxi1/k68zt8XKrtXAgETvRpGZE0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxjVz2%2Fbtrr4xJLxi1%2Fk68zt8XKrtXAgETvRpGZE0%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;1602&quot; height=&quot;851&quot; data-origin-width=&quot;1602&quot; data-origin-height=&quot;851&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;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Cluster URL : 배포 대상 Kubernetes Cluster 지정 (https://kubernetes.default.svc)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Namespace : 배포 할 Kubernetes Cluster 내 Namespace 지정 (default)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;DIRECTORY RECURSE : Path 하위 경로 디렉토리의 변동사항 체크 확인 여부&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 입력 후 CREATE 버튼을 클릭한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;10) SYNC APPS&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;1601&quot; data-origin-height=&quot;835&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k6zNS/btrr1nV8pa0/1QoVE4u5T2AN1xS4Si1Kf0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k6zNS/btrr1nV8pa0/1QoVE4u5T2AN1xS4Si1Kf0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k6zNS/btrr1nV8pa0/1QoVE4u5T2AN1xS4Si1Kf0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk6zNS%2Fbtrr1nV8pa0%2F1QoVE4u5T2AN1xS4Si1Kf0%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;1601&quot; height=&quot;835&quot; data-origin-width=&quot;1601&quot; data-origin-height=&quot;835&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: 'Noto Serif KR'; color: #000000;&quot;&gt;초기 NEW APP으로 추가된 APPS는 SYNC를 수행하기 전 상태로 OutOfSync 상태의 App으로 기동된다. 하단의 SYNC 버튼을 클릭한다.&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;1601&quot; data-origin-height=&quot;836&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xhQiY/btrr3n8spqK/m9iGjVx2b3d5ZAARtD8KgK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xhQiY/btrr3n8spqK/m9iGjVx2b3d5ZAARtD8KgK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xhQiY/btrr3n8spqK/m9iGjVx2b3d5ZAARtD8KgK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxhQiY%2Fbtrr3n8spqK%2Fm9iGjVx2b3d5ZAARtD8KgK%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;1601&quot; height=&quot;836&quot; data-origin-width=&quot;1601&quot; data-origin-height=&quot;836&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;span style=&quot;color: #000000;&quot;&gt;SYNCHRONIZE RESOURCES : Git Repository로 부터 동기화 된 Resource로 반영할 대상 선택&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;# 자주 발생하는 Error&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;1602&quot; data-origin-height=&quot;834&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bz6yeL/btrr3h8cu7N/01uXdkFP5bfkFg7y6kKVVK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bz6yeL/btrr3h8cu7N/01uXdkFP5bfkFg7y6kKVVK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bz6yeL/btrr3h8cu7N/01uXdkFP5bfkFg7y6kKVVK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbz6yeL%2Fbtrr3h8cu7N%2F01uXdkFP5bfkFg7y6kKVVK%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;1602&quot; height=&quot;834&quot; data-origin-width=&quot;1602&quot; data-origin-height=&quot;834&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; font-family: 'Noto Serif KR';&quot;&gt;문제발생 : Sync Failed 발생&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;장애진단 : argocd cli 활용&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1643389912261&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 ~]# argocd app get sample-argocd-test 
Name:               sample-argocd-test
Project:            default
Server:             https://kubernetes.default.svc
Namespace:          default
URL:                https://192.168.89.241:31000/applications/sample-argocd-test
Repo:               http://192.168.84.159:8090/root/myargocdproject.git
Target:             main
Path:               .
SyncWindow:         Sync Allowed
Sync Policy:        &amp;lt;none&amp;gt;
Sync Status:        OutOfSync from main (c7ac08f)
Health Status:      Missing

GROUP  KIND        NAMESPACE  NAME      STATUS     HEALTH   HOOK  MESSAGE
       Service     default    my-nginx  OutOfSync  Missing        error validating data: ValidationError(Service.spec.ports[0]): unknown field &quot;nodePotr&quot; in io.k8s.api.core.v1.ServicePort
apps   Deployment  default    my-nginx  OutOfSync  Missing        
[root@ip-192-168-78-195 ~]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;argocd app get [Application Name]으로 현재 app의 상태를 확인 (MESSAGE 부분). 대부분의 경우 &quot;error validating data: ValidationError(Service.spec.ports[0]): unknown field &quot;nodePotr&quot; in io.k8s.api.core.v1.ServicePort&quot;와 같이 yaml 파일 수정 시 오타로 인한 field 식별 오류 또는 yaml Syntax 오류 등으로 인해 OutOfSync 상태가 유지되며, Sync Failed가 발생한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;현재는 nodePort가 nodePotr로 오기입된 상태이므로 kubernetes에 반영하기전 validation에서 오류가 발생한 상태이다. 이 경우 Git Repository의 yaml 파일을 반영한 후 재 시도를 한다.&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&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;1600&quot; data-origin-height=&quot;836&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/beBCqF/btrr025NgHr/jrIwHb94L8BLhpyt1Wz3G0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/beBCqF/btrr025NgHr/jrIwHb94L8BLhpyt1Wz3G0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/beBCqF/btrr025NgHr/jrIwHb94L8BLhpyt1Wz3G0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbeBCqF%2Fbtrr025NgHr%2FjrIwHb94L8BLhpyt1Wz3G0%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;1600&quot; height=&quot;836&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;836&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: 'Noto Serif KR'; color: #000000;&quot;&gt;11) Application 배포 확인&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;1801&quot; data-origin-height=&quot;833&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ssnBA/btrr1OlGaEF/K2Auh6K6EznvlUQBCIUtX1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ssnBA/btrr1OlGaEF/K2Auh6K6EznvlUQBCIUtX1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ssnBA/btrr1OlGaEF/K2Auh6K6EznvlUQBCIUtX1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FssnBA%2Fbtrr1OlGaEF%2FK2Auh6K6EznvlUQBCIUtX1%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;1801&quot; height=&quot;833&quot; data-origin-width=&quot;1801&quot; data-origin-height=&quot;833&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: 'Noto Serif KR'; color: #000000;&quot;&gt;Sync가 완료된 Application을 클릭하면 위와 같이 상세 상태를 확인할 수 있다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;sample-argocd-test : New App으로 배포한 argocd application&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;svc (my-nginx) : kubernetes service&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;ep (my-nginx) : kubernetes enpoint&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;endpointslice (my-ngnix-xxxxx) : kubernetes endpoint tracer&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;deploy (my-nginx) : kubernetest deployment&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;rs (my-nginx-xxxxxxxxxx) : kubernetes replicaset&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;pod (my-nginx-rsname-xxxxx) : kubernetes pod (현재 2개 pod 기동 중)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1802&quot; data-origin-height=&quot;836&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/19R4F/btrr3nACMkR/baCdlVpNWtPFSsf32t4amK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/19R4F/btrr3nACMkR/baCdlVpNWtPFSsf32t4amK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/19R4F/btrr3nACMkR/baCdlVpNWtPFSsf32t4amK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F19R4F%2Fbtrr3nACMkR%2FbaCdlVpNWtPFSsf32t4amK%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;1802&quot; height=&quot;836&quot; data-origin-width=&quot;1802&quot; data-origin-height=&quot;836&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: 'Noto Serif KR'; color: #000000;&quot;&gt;왼쪽 상단의 APP DETAILS를 클릭하여 sample-argocd-test application의 전체 정보를 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;특히 SUMMARY TAB의 EDIT를 통해 Configuration을 수정하거나, STATUS Field를 통해 현재 반영되어 있는 Commit SHA 정보를 확인할 수 있다. &lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;ENABLE AUTO-SYNC 설정으로 변경하여 자동 반영 설정을 적용할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;12) GitLab 수정 후 반영&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;1797&quot; data-origin-height=&quot;829&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nj0if/btrr2S1SYOT/dgdip3PKRzgkidyBvCVpH1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nj0if/btrr2S1SYOT/dgdip3PKRzgkidyBvCVpH1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nj0if/btrr2S1SYOT/dgdip3PKRzgkidyBvCVpH1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fnj0if%2Fbtrr2S1SYOT%2Fdgdip3PKRzgkidyBvCVpH1%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;1797&quot; height=&quot;829&quot; data-origin-width=&quot;1797&quot; data-origin-height=&quot;829&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: 'Noto Serif KR'; color: #000000;&quot;&gt;GitLab에 반영되어 있는 deployment.yaml 파일의 replicas를 2에서 1로 수정 후 SYNC 버튼을 클릭하면 위와 같이 Pod하나가 중지되는 것을 확인할 수 있다.&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;1800&quot; data-origin-height=&quot;831&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQ0GpB/btrr052tSD1/DLeWsQckCQzwhkcUL0YSs1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQ0GpB/btrr052tSD1/DLeWsQckCQzwhkcUL0YSs1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQ0GpB/btrr052tSD1/DLeWsQckCQzwhkcUL0YSs1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQ0GpB%2Fbtrr052tSD1%2FDLeWsQckCQzwhkcUL0YSs1%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;1800&quot; height=&quot;831&quot; data-origin-width=&quot;1800&quot; data-origin-height=&quot;831&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: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 반영된 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1643392136459&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 ~]# kubectl get all
NAME                            READY   STATUS    RESTARTS   AGE
pod/my-nginx-5b56ccd65f-n2bdb   1/1     Running   0          32m

NAME                 TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
service/kubernetes   ClusterIP   10.100.0.1       &amp;lt;none&amp;gt;        443/TCP        3h15m
service/my-nginx     NodePort    10.100.128.191   &amp;lt;none&amp;gt;        80:32000/TCP   32m

NAME                       READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/my-nginx   1/1     1            1           32m

NAME                                  DESIRED   CURRENT   READY   AGE
replicaset.apps/my-nginx-5b56ccd65f   1         1         1       32m
[root@ip-192-168-78-195 ~]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;kubernetes 상에서도 위와 같이 반영된 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;13) 롤백 처리&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&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;1801&quot; data-origin-height=&quot;835&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lyfrM/btrr2yo511I/jvCK17QLoK9bFWJKv6OrOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lyfrM/btrr2yo511I/jvCK17QLoK9bFWJKv6OrOk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lyfrM/btrr2yo511I/jvCK17QLoK9bFWJKv6OrOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlyfrM%2Fbtrr2yo511I%2FjvCK17QLoK9bFWJKv6OrOk%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;1801&quot; height=&quot;835&quot; data-origin-width=&quot;1801&quot; data-origin-height=&quot;835&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: 'Noto Serif KR'; color: #000000;&quot;&gt;이 경우 몇번의 클릭만으로 이전 revision으로 되 돌릴 수 있다.&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;1797&quot; data-origin-height=&quot;834&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqSCMz/btrr2WXzB91/h8xbKGmjyZX3RMT6R1s8G1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqSCMz/btrr2WXzB91/h8xbKGmjyZX3RMT6R1s8G1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqSCMz/btrr2WXzB91/h8xbKGmjyZX3RMT6R1s8G1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqSCMz%2Fbtrr2WXzB91%2Fh8xbKGmjyZX3RMT6R1s8G1%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;1797&quot; height=&quot;834&quot; data-origin-width=&quot;1797&quot; data-origin-height=&quot;834&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: 'Noto Serif KR'; color: #000000;&quot;&gt;상단의 HISTORY AND ROLLBACK 클릭 후 &amp;gt; 원하는 Revision 확인 후 &amp;gt; 오른쪽 Rollback 클릭&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;1801&quot; data-origin-height=&quot;835&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cE1F3s/btrr03Kj2Dk/tJN7eGXaS1L7SLLmUnmlP0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cE1F3s/btrr03Kj2Dk/tJN7eGXaS1L7SLLmUnmlP0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cE1F3s/btrr03Kj2Dk/tJN7eGXaS1L7SLLmUnmlP0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcE1F3s%2Fbtrr03Kj2Dk%2FtJN7eGXaS1L7SLLmUnmlP0%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;1801&quot; height=&quot;835&quot; data-origin-width=&quot;1801&quot; data-origin-height=&quot;835&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: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 몇번의 클릭만으로 pod가 2개로 복원된 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;14) 추가 기능&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;그 밖에 유용한 기능 몇가지 더 소개하고 포스팅을 마치도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; DIFF 기능&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;1800&quot; data-origin-height=&quot;835&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pdOwX/btrr0QR4VtM/eozZYukr0fOHsDyQWlt0pK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pdOwX/btrr0QR4VtM/eozZYukr0fOHsDyQWlt0pK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pdOwX/btrr0QR4VtM/eozZYukr0fOHsDyQWlt0pK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpdOwX%2Fbtrr0QR4VtM%2FeozZYukr0fOHsDyQWlt0pK%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;1800&quot; height=&quot;835&quot; data-origin-width=&quot;1800&quot; data-origin-height=&quot;835&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: 'Noto Serif KR'; color: #000000;&quot;&gt;변경된 Application Revision에 대해 Diff 기능을 통해 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; LOGS&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;1800&quot; data-origin-height=&quot;833&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MqTAJ/btrr1i1z2vf/zKUlJJxVzjX8cIU9BraRvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MqTAJ/btrr1i1z2vf/zKUlJJxVzjX8cIU9BraRvK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MqTAJ/btrr1i1z2vf/zKUlJJxVzjX8cIU9BraRvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMqTAJ%2Fbtrr1i1z2vf%2FzKUlJJxVzjX8cIU9BraRvK%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;1800&quot; height=&quot;833&quot; data-origin-width=&quot;1800&quot; data-origin-height=&quot;833&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: 'Noto Serif KR'; color: #000000;&quot;&gt;Pod 로그를 대시보드에서 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; FILTER&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bz3gJ3/btrr0QxLdfH/obokkCEO9VPickcSl9Monk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bz3gJ3/btrr0QxLdfH/obokkCEO9VPickcSl9Monk/img.png&quot; data-origin-width=&quot;988&quot; data-origin-height=&quot;833&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.2442%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bz3gJ3/btrr0QxLdfH/obokkCEO9VPickcSl9Monk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbz3gJ3%2Fbtrr0QxLdfH%2FobokkCEO9VPickcSl9Monk%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;988&quot; height=&quot;833&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cmutlc/btrr4yaQbon/EwRN8RaAPBsHSiskkxkQn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cmutlc/btrr4yaQbon/EwRN8RaAPBsHSiskkxkQn0/img.png&quot; data-origin-width=&quot;995&quot; data-origin-height=&quot;833&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.5931%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cmutlc/btrr4yaQbon/EwRN8RaAPBsHSiskkxkQn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcmutlc%2Fbtrr4yaQbon%2FEwRN8RaAPBsHSiskkxkQn0%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;995&quot; height=&quot;833&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;FILTER를 통해 그룹핑하여 대량의 서비스가 배포되는 환경에서 빠르게 원하는 조건의 어플리케이션을 찾아 갈 수 있도록 도와준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; Settings (Repository, Cluster, Project)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDqBqY/btrr2zVRnFs/geVbnmDK1TKfkPzkaKFSz1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDqBqY/btrr2zVRnFs/geVbnmDK1TKfkPzkaKFSz1/img.png&quot; data-origin-width=&quot;1801&quot; data-origin-height=&quot;834&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4302%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDqBqY/btrr2zVRnFs/geVbnmDK1TKfkPzkaKFSz1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDqBqY%2Fbtrr2zVRnFs%2FgeVbnmDK1TKfkPzkaKFSz1%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;1801&quot; height=&quot;834&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqWZ9t/btrr1nBSmzU/tpuWvKkK8dpKEWaDI18S30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqWZ9t/btrr1nBSmzU/tpuWvKkK8dpKEWaDI18S30/img.png&quot; data-origin-width=&quot;1798&quot; data-origin-height=&quot;833&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4071%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqWZ9t/btrr1nBSmzU/tpuWvKkK8dpKEWaDI18S30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqWZ9t%2Fbtrr1nBSmzU%2FtpuWvKkK8dpKEWaDI18S30%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;1798&quot; height=&quot;833&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/caz57k/btrr2yJonvN/NHdgSfoD2alpwiilDd95gK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/caz57k/btrr2yJonvN/NHdgSfoD2alpwiilDd95gK/img.png&quot; data-origin-width=&quot;1800&quot; data-origin-height=&quot;833&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4049%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/caz57k/btrr2yJonvN/NHdgSfoD2alpwiilDd95gK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcaz57k%2Fbtrr2yJonvN%2FNHdgSfoD2alpwiilDd95gK%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;1800&quot; height=&quot;833&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YgxLR/btrr2yvVS5b/iJIMm5EGAGZn9j0KHhPG40/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YgxLR/btrr2yvVS5b/iJIMm5EGAGZn9j0KHhPG40/img.png&quot; data-origin-width=&quot;1801&quot; data-origin-height=&quot;833&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4323%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YgxLR/btrr2yvVS5b/iJIMm5EGAGZn9j0KHhPG40/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYgxLR%2Fbtrr2yvVS5b%2FiJIMm5EGAGZn9j0KHhPG40%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;1801&quot; height=&quot;833&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 사전에 Repository, Cluster, Project를 등록하여 관리할 수 있다. 이는 상태를 점검하는 측면에서 활용되거나, 여러 구성에서 해당 항목을 손쉽게 등록할 수 있도록 도와주는 역할을 하는 기능이다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;결론&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;GitOps는 자동배포와 인프라 관리를 위해 다양한 정보를 모니터링하고 추적할 수 있는 도구와 연계되어야 한다.&lt;br /&gt;이와 같은 측면에서 볼때 ArgoCD는 Git 및 Kubernetes에 최적화된 도구로 손쉬운 구성과 대시보드 제공, 높은 추적성과 안정성을 보장하는 GitOps 프로세스와 체계를 설계하는 단계의 프로젝트에 적용하기 적합한 도구라 할 수 있을 것이다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>⑤ 개발, 데이터베이스/ⓒ CI CD</category>
      <category>ArgoCD</category>
      <category>argocd cli</category>
      <category>argocd login</category>
      <category>git</category>
      <category>GitLab</category>
      <category>GitOps</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/758</guid>
      <comments>https://waspro.tistory.com/758#entry758comment</comments>
      <pubDate>Sat, 29 Jan 2022 03:04:05 +0900</pubDate>
    </item>
    <item>
      <title>Swagger UI &amp;amp; Mock Server (Prism)</title>
      <link>https://waspro.tistory.com/755</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;개요&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;마이크로서비스는 서비스간 호출 검증을 위해 Component / Contract Test를 시나리오를 정의하고, 파이프라인 또는 3rd Party 솔루션을 통해 자동 검증할 수 있도록 구성하는 것이 일반적이다. Component Test는 테스트를 수행하는 서비스를 기준으로 테스트 케이스를 정의하고, Contract Test는 서비스에서 제공하는 api를 호출하는 client 기준으로 테스트 케이스를 정의한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이와 같은 상호간의 인터페이스를 테스트하기 위해서는 각 서비스가 기동되어 있어야 하지만, 개발부서가 분리되어 있거나, client 입장에서 Contract를 테스트하기 위해서는 보다 번거로운 절차를 통해 테스트를 진행해야 한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&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;1099&quot; data-origin-height=&quot;685&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ExaGa/btrqnjO9oNe/TnkxMzXifIsrbZOITI9kuk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ExaGa/btrqnjO9oNe/TnkxMzXifIsrbZOITI9kuk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ExaGa/btrqnjO9oNe/TnkxMzXifIsrbZOITI9kuk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FExaGa%2FbtrqnjO9oNe%2FTnkxMzXifIsrbZOITI9kuk%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;1099&quot; height=&quot;685&quot; data-origin-width=&quot;1099&quot; data-origin-height=&quot;685&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; font-family: 'Noto Serif KR';&quot;&gt;위와 같이 MicroService B가 특정 이유(서비스가 중지되었거나, 서비스 개발팀이 휴가를 갔거나, 네트워크가 차단되었거나 등 수많은 이유)로 인해 접속이 불가능한 경우 MicroService A와 C는 서비스 테스트가 불가능하고, 테스트 자동화 구성이 되어 있는 환경에서는 타 서비스가 기동될 때까지 CI 실패가 발생할 수도 있다.&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;1099&quot; data-origin-height=&quot;806&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bH1oA4/btrqt01SjKJ/T2iNlQrcH2d272FJhtAwlK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bH1oA4/btrqt01SjKJ/T2iNlQrcH2d272FJhtAwlK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bH1oA4/btrqt01SjKJ/T2iNlQrcH2d272FJhtAwlK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbH1oA4%2Fbtrqt01SjKJ%2FT2iNlQrcH2d272FJhtAwlK%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;1099&quot; height=&quot;806&quot; data-origin-width=&quot;1099&quot; data-origin-height=&quot;806&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1099&quot; data-origin-height=&quot;650&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blM89y/btrqnkHidec/1jebNM15wrnNJA9EtJ7LJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blM89y/btrqnkHidec/1jebNM15wrnNJA9EtJ7LJ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blM89y/btrqnkHidec/1jebNM15wrnNJA9EtJ7LJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblM89y%2FbtrqnkHidec%2F1jebNM15wrnNJA9EtJ7LJ1%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;1099&quot; height=&quot;650&quot; data-origin-width=&quot;1099&quot; data-origin-height=&quot;650&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; font-family: 'Noto Serif KR';&quot;&gt;이를 해소하기 위해 위와 같이 MockServer를 구성하여 각 로컬 서비스 내에 테스트가 가능하도록 구현해 두는 것을 권고한다. 각 서비스에서 제공하는 api를 가상의 서버인 MockServer에 정의하고, 가상의 데이터를 리턴해 주는 형태로 구성한다. 이때 MockServer는 API 규격에 맞는 데이터를 리턴타입에 맞게 임시 데이터를 생성하고 리턴한다. 이를 통해 서비스간 API 규격을 공유할 수 있는 환경만 명확하게 제공된다면, 서비스 간 Component/Contract 테스트는 로컬 서비스 내에서 수행할 수 있도록 구성할 수 있다. MockServer는 단일 또는 서비스별로 구분하여 구성할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;이번 포스팅에서는 OpenSource MockServer인 Prism에 대해 알아보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;# 참고 URL :&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://stoplight.io/open-source/prism/&quot;&gt;https://stoplight.io/open-source/prism/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Prism 설치&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Prism은 Node 기반으로 설치된다. nvm &amp;gt; node &amp;gt; npm 순으로 설치를 진행한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1) nvm 설치&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1641738621604&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-84-159 ~]# curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 13226  100 13226    0     0  99443      0 --:--:-- --:--:-- --:--:-- 99443
=&amp;gt; Downloading nvm from git to '/root/.nvm'
=&amp;gt; Cloning into '/root/.nvm'...
remote: Enumerating objects: 278, done.
remote: Counting objects: 100% (278/278), done.
remote: Compressing objects: 100% (245/245), done.
remote: Total 278 (delta 31), reused 101 (delta 20), pack-reused 0
Receiving objects: 100% (278/278), 142.25 KiB | 813.00 KiB/s, done.
Resolving deltas: 100% (31/31), done.
=&amp;gt; Compressing and cleaning up git repository

=&amp;gt; Appending nvm source string to /root/.bashrc
=&amp;gt; Appending bash_completion source string to /root/.bashrc
=&amp;gt; Close and reopen your terminal to start using nvm or run the following to use it now:

export NVM_DIR=&quot;$HOME/.nvm&quot;
[ -s &quot;$NVM_DIR/nvm.sh&quot; ] &amp;amp;&amp;amp; \. &quot;$NVM_DIR/nvm.sh&quot;  # This loads nvm
[ -s &quot;$NVM_DIR/bash_completion&quot; ] &amp;amp;&amp;amp; \. &quot;$NVM_DIR/bash_completion&quot;  # This loads nvm bash_completion
[root@ip-192-168-84-159 ~]# . ~/.nvm/nvm.sh&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2) node 설치&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1641910532597&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-84-159 ~]# nvm install node
Downloading and installing node v17.3.0...
Downloading https://nodejs.org/dist/v17.3.0/node-v17.3.0-linux-x64.tar.xz...
##################################################################################################################################################################################################################################### 100.0%
Computing checksum with sha256sum
Checksums matched!
Now using node v17.3.0 (npm v8.3.0)
Creating default alias: default -&amp;gt; node (-&amp;gt; v17.3.0 *)
[root@ip-192-168-84-159 ~]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;3) prism 설치&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1641738702179&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-84-159 ~]# npm install -g @stoplight/prism-cli
npm WARN deprecated uuid@3.4.0: Please upgrade  to version 7 or higher.  Older versions may use Math.random() in certain circumstances, which is known to be problematic.  See https://v8.dev/blog/math-random for details.
npm WARN deprecated har-validator@5.1.5: this library is no longer supported
npm WARN deprecated request@2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142

added 239 packages, and audited 240 packages in 22s

11 packages are looking for funding
  run `npm fund` for details

11 moderate severity vulnerabilities

To address all issues (including breaking changes), run:
  npm audit fix --force

Run `npm audit` for details.
[root@ip-192-168-84-159 ~]#&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Prism 적용&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;api contract로 등록할 대상 서비스에 대해 다음과 같은 절차를 진행한다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;swagger api document 다운로드&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;mock server(prism) 기동&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;api test&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;mock server 로그 및 리턴 결과 확인&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;1) swagger api doc download&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;http://[IP]:[PORT]/[CONTEXT]/v2/api-docs&lt;span style=&quot;color: #000000;&quot;&gt;로 접근할 경우 api doc을 확인할 수 있다. 이를 아래와 같이 저장하여 mock server에 적용한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;[root@ip-192-168-84-159&amp;nbsp;~]#&amp;nbsp;cat&amp;nbsp;swagger-prism.json&amp;nbsp; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;{ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;swagger&quot;:&quot;2.0&quot;, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;info&quot;:{ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;description&quot;:&quot;Api&amp;nbsp;Documentation&quot;, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;version&quot;:&quot;1.0&quot;, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;title&quot;:&quot;Api&amp;nbsp;Documentation&quot;, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;termsOfService&quot;:&quot;urn:tos&quot;, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;contact&quot;:{ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;license&quot;:{ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;name&quot;:&quot;Apache&amp;nbsp;2.0&quot;, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;url&quot;:&quot;&lt;a style=&quot;color: #000000;&quot; href=&quot;http://www.apache.org/licenses/LICENSE-2.0&amp;quot;&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;http://www.apache.org/licenses/LICENSE-2.0&quot;&lt;/a&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;} &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;host&quot;:&quot;localhost:8075&quot;, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;basePath&quot;:&quot;/prism/account&quot;, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;tags&quot;:[ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;name&quot;:&quot;account-controller&quot;, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;description&quot;:&quot;Account&amp;nbsp;Controller&quot; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;} &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;], &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;paths&quot;:{ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;/prism/rest/v0.8/{acntNo}&quot;:{ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;get&quot;:{ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;tags&quot;:[ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;account-controller&quot; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;], &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;operationId&quot;:&quot;retrieveAccountNoUsingGET&quot;, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;consumes&quot;:[ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;application/json&quot;, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;application/xml&quot;, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;text/xml&quot;, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;text/html&quot; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;], &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;produces&quot;:[ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;application/json&quot;, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;application/xml&quot;, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;text/xml&quot;, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;text/html&quot; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;], &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;parameters&quot;:[ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;{ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&amp;nbsp;&quot;name&quot;:&quot;acntNo&quot;, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&amp;nbsp;&quot;in&quot;:&quot;path&quot;, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&amp;nbsp;&quot;description&quot;:&quot;acntNo&quot;, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&amp;nbsp;&quot;required&quot;:true, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&amp;nbsp;&quot;type&quot;:&quot;string&quot; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;} &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;], &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;responses&quot;:{ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;200&quot;:{ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&amp;nbsp;&quot;description&quot;:&quot;OK&quot;, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&amp;nbsp;&quot;schema&quot;:{ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;type&quot;:&quot;integer&quot;, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;format&quot;:&quot;int64&quot; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&amp;nbsp;} &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;}, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;401&quot;:{ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&amp;nbsp;&quot;description&quot;:&quot;Unauthorized&quot; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;}, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;403&quot;:{ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&amp;nbsp;&quot;description&quot;:&quot;Forbidden&quot; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;}, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;404&quot;:{ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&amp;nbsp;&quot;description&quot;:&quot;Not&amp;nbsp;Found&quot; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;} &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;} &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;} &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;/prism/rest/v1.8/{acntNo}&quot;:{ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;get&quot;:{ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;tags&quot;:[ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;account-controller&quot; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;], &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;operationId&quot;:&quot;retrieveTransactionAccountNoUsingGET&quot;, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;consumes&quot;:[ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;application/json&quot;, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;application/xml&quot;, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;text/xml&quot;, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;text/html&quot; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;], &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;produces&quot;:[ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;application/json&quot;, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;application/xml&quot;, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;text/xml&quot;, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;text/html&quot; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;], &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;parameters&quot;:[ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;{ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&amp;nbsp;&quot;name&quot;:&quot;acntNo&quot;, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&amp;nbsp;&quot;in&quot;:&quot;path&quot;, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&amp;nbsp;&quot;description&quot;:&quot;acntNo&quot;, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&amp;nbsp;&quot;required&quot;:true, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&amp;nbsp;&quot;type&quot;:&quot;string&quot; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;} &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;], &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;responses&quot;:{ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;200&quot;:{ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&amp;nbsp;&quot;description&quot;:&quot;OK&quot;, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&amp;nbsp;&quot;schema&quot;:{ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;type&quot;:&quot;array&quot;, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;items&quot;:{ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;$ref&quot;:&quot;#/definitions/TransactionHistory&quot; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;} &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&amp;nbsp;} &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;}, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;401&quot;:{ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&amp;nbsp;&quot;description&quot;:&quot;Unauthorized&quot; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;}, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;403&quot;:{ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&amp;nbsp;&quot;description&quot;:&quot;Forbidden&quot; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;}, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;404&quot;:{ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&amp;nbsp;&quot;description&quot;:&quot;Not&amp;nbsp;Found&quot; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;} &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;} &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;} &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;} &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;definitions&quot;:{ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;TransactionHistory&quot;:{ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;type&quot;:&quot;object&quot;, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;properties&quot;:{ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;acntBlnc&quot;:{ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;type&quot;:&quot;integer&quot;, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;format&quot;:&quot;int64&quot; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;}, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;acntNo&quot;:{ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;type&quot;:&quot;string&quot; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;}, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;divCd&quot;:{ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;type&quot;:&quot;string&quot; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;}, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;seq&quot;:{ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;type&quot;:&quot;integer&quot;, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;format&quot;:&quot;int32&quot; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;}, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;stsCd&quot;:{ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;type&quot;:&quot;string&quot; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;}, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;trnsAmt&quot;:{ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;type&quot;:&quot;integer&quot;, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;format&quot;:&quot;int64&quot; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;}, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;trnsBrnch&quot;:{ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;type&quot;:&quot;string&quot; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;}, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;trnsDtm&quot;:{ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;type&quot;:&quot;string&quot; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;} &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;} &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;} &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;} &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;} &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;[root@ip-192-168-84-159&amp;nbsp;~]#&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;2) &lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;prism 기동 (prism mock --host [IP] -p [PORT] -d [api-doc.json]&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1641738874715&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-84-159 ~]# prism mock --host 0.0.0.0 -p 15002 -d swagger-prism.json
[2:29:03 PM] [39m [CLI]  [39m awaiting  Starting Prism
[2:29:04 PM] [39m [CLI]  [39m info      GET        http://0.0.0.0:15002/prism/rest/v0.8/architecto
[2:29:04 PM] [39m [CLI]  [39m info      GET        http://0.0.0.0:15002/prism/rest/v1.8/eligendi
[2:29:04 PM] [39m [CLI]  [39m start     Prism is listening on http://0.0.0.0:15002&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;3) API 단위 테스트&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dSiSy4/btrqtTV9Uka/LXKVNIYs0VWFCdntX3YVOK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dSiSy4/btrqtTV9Uka/LXKVNIYs0VWFCdntX3YVOK/img.png&quot; data-origin-width=&quot;1063&quot; data-origin-height=&quot;893&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dSiSy4/btrqtTV9Uka/LXKVNIYs0VWFCdntX3YVOK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdSiSy4%2FbtrqtTV9Uka%2FLXKVNIYs0VWFCdntX3YVOK%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;1063&quot; height=&quot;893&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ao1Yp/btrqnjBA8O6/5rttkECdPHIsPvKwO6ftwk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ao1Yp/btrqnjBA8O6/5rttkECdPHIsPvKwO6ftwk/img.png&quot; data-origin-width=&quot;1063&quot; data-origin-height=&quot;893&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ao1Yp/btrqnjBA8O6/5rttkECdPHIsPvKwO6ftwk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAo1Yp%2FbtrqnjBA8O6%2F5rttkECdPHIsPvKwO6ftwk%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;1063&quot; height=&quot;893&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;4) prism 로그 확인&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1641911597350&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-84-159 ~]# prism mock --host 0.0.0.0 -p 15002 -d swagger-prism.json
[2:29:03 PM] [39m [CLI]  [39m awaiting  Starting Prism
[2:29:04 PM] [39m [CLI]  [39m info      GET        http://0.0.0.0:15002/prism/rest/v0.8/architecto
[2:29:04 PM] [39m [CLI]  [39m info      GET        http://0.0.0.0:15002/prism/rest/v1.8/eligendi
[2:29:04 PM] [39m [CLI]  [39m start     Prism is listening on http://0.0.0.0:15002
[2:30:48 PM] [39m [HTTP SERVER] get /prism/rest/v0.8/architecto  [39m info      Request received
[2:30:48 PM] [39m     [NEGOTIATOR]  [39m info      Request contains an accept header: */*
[2:30:48 PM] [39m     [VALIDATOR]  [39m success   The request passed the validation rules. Looking for the best response
[2:30:48 PM] [39m     [NEGOTIATOR]  [39m success   Found a compatible content for */*
[2:30:48 PM] [39m     [NEGOTIATOR]  [39m success   Responding with the requested status code 200
[2:31:39 PM] [39m [HTTP SERVER] get /prism/rest/v1.8/eligendi  [39m info      Request received
[2:31:39 PM] [39m     [NEGOTIATOR]  [39m info      Request contains an accept header: */*
[2:31:39 PM] [39m     [VALIDATOR]  [39m success   The request passed the validation rules. Looking for the best response
[2:31:39 PM] [39m     [NEGOTIATOR]  [39m success   Found a compatible content for */*
[2:31:39 PM] [39m     [NEGOTIATOR]  [39m success   Responding with the requested status code 200&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;# 트러블슈팅 &lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;CASE 1 : &lt;a style=&quot;color: #000000;&quot; href=&quot;https://stoplight.io/prism/errors#NO_COMPLEX_OBJECT_TEXT&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;Cannot&quot;&gt;NO_COMPLEX_OBJECT_TEXT (500 Error)&lt;/a&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;1063&quot; data-origin-height=&quot;893&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dxrj5c/btrqt1fsj2q/K1BwY4PxyvqIG8mb46ZyzK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dxrj5c/btrqt1fsj2q/K1BwY4PxyvqIG8mb46ZyzK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dxrj5c/btrqt1fsj2q/K1BwY4PxyvqIG8mb46ZyzK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdxrj5c%2Fbtrqt1fsj2q%2FK1BwY4PxyvqIG8mb46ZyzK%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;1063&quot; height=&quot;893&quot; data-origin-width=&quot;1063&quot; data-origin-height=&quot;893&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: 'Noto Serif KR'; color: #000000;&quot;&gt;아래와 같이 produces를 정의한다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;letter-spacing: 0px; border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;[swagger-prism.json]&lt;/span&gt;&lt;br /&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;consumes&quot;:[&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;application/json&quot;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;],&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;&quot;produces&quot;:[&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #ee2323;&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;&quot;application/json&quot;,&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #ee2323;&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;&quot;application/xml&quot;,&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #ee2323;&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;&quot;text/xml&quot;,&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #ee2323;&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;&quot;text/html&quot;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;],&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;...&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&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;1063&quot; data-origin-height=&quot;893&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FCigg/btrqu1svTzG/FhJtahZoZU5o4743CYsWn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FCigg/btrqu1svTzG/FhJtahZoZU5o4743CYsWn0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FCigg/btrqu1svTzG/FhJtahZoZU5o4743CYsWn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFCigg%2Fbtrqu1svTzG%2FFhJtahZoZU5o4743CYsWn0%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;1063&quot; height=&quot;893&quot; data-origin-width=&quot;1063&quot; data-origin-height=&quot;893&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: 'Noto Serif KR'; color: #000000;&quot;&gt;CASE 2 &lt;a style=&quot;color: #000000;&quot; href=&quot;https://stoplight.io/prism/errors#NO_PATH_MATCHED_ERROR&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;Route&quot;&gt;NO_PATH_MATCHED_ERROR (404 Client Error)&lt;/a&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;1063&quot; data-origin-height=&quot;893&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGfOkD/btrqmNQqxXt/np1iiNNiLSytq8j6upnIok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGfOkD/btrqmNQqxXt/np1iiNNiLSytq8j6upnIok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGfOkD/btrqmNQqxXt/np1iiNNiLSytq8j6upnIok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGfOkD%2FbtrqmNQqxXt%2Fnp1iiNNiLSytq8j6upnIok%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;1063&quot; height=&quot;893&quot; data-origin-width=&quot;1063&quot; data-origin-height=&quot;893&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: 'Noto Serif KR'; color: #000000;&quot;&gt;Contex 정보 및 도메인 정보 입력 실패&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;[root@ip-192-168-84-159&amp;nbsp;~]#&amp;nbsp;prism&amp;nbsp;mock&amp;nbsp;--host&amp;nbsp;0.0.0.0&amp;nbsp;-p&amp;nbsp;15002&amp;nbsp;-d&amp;nbsp;swagger-prism.json &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;[2:56:13&amp;nbsp;PM]&amp;nbsp;[39m&amp;nbsp;[CLI]&amp;nbsp; [39m&amp;nbsp;awaiting&amp;nbsp;&amp;nbsp;Starting&amp;nbsp;Prism&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;[2:56:13&amp;nbsp;PM]&amp;nbsp;[39m&amp;nbsp;[CLI]&amp;nbsp; [39m&amp;nbsp;info&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;GET&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;http://0.0.0.0:15002/prism/rest/v0.8/sapiente &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;[2:56:13&amp;nbsp;PM]&amp;nbsp;[39m&amp;nbsp;[CLI]&amp;nbsp; [39m&amp;nbsp;info&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;GET&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;http://0.0.0.0:15002/prism/rest/v1.8/voluptatum &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;[2:56:13&amp;nbsp;PM]&amp;nbsp;[39m&amp;nbsp;[CLI]&amp;nbsp; [39m&amp;nbsp;start&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Prism&amp;nbsp;is&amp;nbsp;listening&amp;nbsp;on&amp;nbsp;http://0.0.0.0:15002 &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;[2:56:17&amp;nbsp;PM]&amp;nbsp;[39m&amp;nbsp;[HTTP&amp;nbsp;SERVER]&amp;nbsp;get&amp;nbsp;/hellomynameis/prism/rest/v1.8/architecto&amp;nbsp; [39m&amp;nbsp;info&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Request&amp;nbsp;received &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;[2:56:17&amp;nbsp;PM]&amp;nbsp;[39m&amp;nbsp;[HTTP&amp;nbsp;SERVER]&amp;nbsp;get&amp;nbsp;/hellomynameis/prism/rest/v1.8/architecto&amp;nbsp; [39m&amp;nbsp;error&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Request&amp;nbsp;terminated&amp;nbsp;with&amp;nbsp;error:&amp;nbsp;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://stoplight.io/prism/errors#NO_PATH_MATCHED_ERROR:&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://stoplight.io/prism/errors#NO_PATH_MATCHED_ERROR:&lt;/a&gt;&amp;nbsp;Route&amp;nbsp;not&amp;nbsp;resolved,&amp;nbsp;no&amp;nbsp;path&amp;nbsp;matched&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;기동 시 호출 URL 정보 확인 후 호출을 진행한다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;결론&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이와 같이 Prism을 활용하면, 분산 서비스 환경에서 상호간 Contract를 관리하는 mockserver로써의 역할 수행할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;그 밖에 Prism은 로드된 문서의 변경 사항을 자동으로 감지하여 서버를 다시 시작시켜 변경 사항을 반영한다.&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span&gt; 즉 수정된 api document를 특정 위치에 업로드만 하면, 손쉽게 prism 서버에 반영할 수 있다는 의미이다. 이를 활용하면, 자동화 체계를 설계할 수 있다. 예를 들어 api portal을 통해 api가 추가될 경우 이와 동시에 swagger json을 prism 서버에 업로드 하는 기능을 만든다고 할때, 손쉽게 MockServer 환경을 관리할 수 있을 것이다.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span&gt;또한, Proxy 서버의 역할로도 활용할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span&gt;Prism은 누구나 손쉽게 구성이 가능한 Mockserver로 각 개발환경에 적용해 보고 API Portal과 함께 활용 방안에 대해 프로젝트 별로 고민해 보도록 하자.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>⑦ Open Source Software</category>
      <category>mock</category>
      <category>MOCKSERVER</category>
      <category>NO_COMPLEX_OBJECT_TEXT</category>
      <category>NO_PATH_MATCHED_ERROR</category>
      <category>prism</category>
      <category>SWAGGER MOCK</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/755</guid>
      <comments>https://waspro.tistory.com/755#entry755comment</comments>
      <pubDate>Wed, 22 Dec 2021 01:33:00 +0900</pubDate>
    </item>
    <item>
      <title>마이크로서비스로의 점진적 전환 시 고려사항</title>
      <link>https://waspro.tistory.com/751</link>
      <description>&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;개요&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;마이크로서비스 아키텍처는 고객의 경험을 높이고 서비스의 민첩성, 성능, 안정성 등을 향상시키는 개방형 아키텍처이다. 마이크로서비스로의 전환은 분산 서비스 환경에서 발생 가능한 트랜잭션에 따른 영향도, 분산 DB 구축에 따른 데이터 처리 또는 더 세분화 하여 서비스 간 동기/비동기 식별부터 DevSecOps 체계를 위한 조직, 문화, 기술의 변화까지 당면 과제들을 맞닥뜨리며 해결과정을 아키텍처에 반영하여, 프로젝트에 적합한 설계 방향을 잡아간다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;여러 당면 과제들이 생겨 나겠지만 프로젝트에서는 오픈 방식에 대해서도 심도있게 고려해야 한다. 전통적인 SI 프로젝트 특성상 빅뱅 방식을 선호하여, 점진적 이행을 추구하는 MSA와 다르게 진행되는 경우가 많다. SI를 통해 프로젝트가 진행되는 경우 대부분 지속적으로 MSA를 유지보수해 나갈 인력의 부족으로 인해 빅뱅 방식으로 오픈하고, 이후 모놀리스 개발 방식으로 회귀되는 경우가 많다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;이와 같은 일이 반복되지 않도록 전환 방식에 따른 영역별 대응 방안을 수립하고, 점진적 이행에 대응할 수 있도록 기술력을 내재화해 나가는 것이 무엇보다 중요할 것이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;점진적 이행은 마이크로서비스를 한 번에 하나씩 분리하면서&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;오히려 더 빠르게&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;대규모 배포를 기다릴 필요 없이 마이크로서비스가 제공하는 가치를 점진적으로 얻을 수 있다. &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;지금부터는 점진적 확대 방식으로 마이크로서비스를 설계하고 개발할 때 고려해야 할 문제점들에 대해 살펴보고 현재 우리 회사의 도달 수준과 대처방안에 대해 알아보도록 하자.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;권한 관리&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;마이크로서비스로 모놀리스 어플리케이션이 세분화되면서, 관리해야 할 대상이 증가하고 있다. 특히, 관리 대상 간의 자원 소유권을 정의하는 것은 역할의 구분이라는 측면에서 민감하고, 중요하다. &lt;/span&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;분산DB 분리에 따른 데이터 소유자, 소스코드 관리자, 공통 모듈 개발자, API Composition 대상 서비스&lt;/span&gt; 등 상호간 중복되는 영역에 대해 역할을 사전에 정의한 후 프로젝트를 진행할 필요가 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1) 데이터 소유자&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;마이크로서비스 별 데이터의 소유 즉 테이블의 owner를 결정하는 것은 마이크로서비스의 성공 여부를 결정할 정도로 중요하다. 데이터의 소유자가 잘못 결정되어 불필요한 데이터 호출이 발생할 경우 서비스의 성능은 물론 정합성에 문제를 발생 시킬 수 있다. 따라서 서비스간 공유해야 할 데이터에 대한 소유자 관리는 데이터모델링을 통해 영향도를 파악하여 결정하는 것이 바람직하다.&lt;br /&gt;CUD를 발생시키는 주체와 그 데이터를 사용하는 주체간에서 데이터 효율성을 재고해야하며, &lt;/span&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;대체로 공유서비스를 호출하는 빈도와 주고받아야 하는 데이터량을 기준으로 데이터 소유자를 결정하게 된다. 데이터의 소유자는 결국 데이터베이스의 테이블 소유자이며, 이를 기준으로 데이터베이스 분리를 진행한다. 또한, Join 테이블에 따라 결합도를 분석하고, 상호간 복제 또는 CQRS와 같은 ReadOnly DB를 활용하는 방법도 고려해 볼 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;2) 공통 모듈 개발자&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;공통 모듈의 경우 마이크로서비스의 규모와 비즈니스에 따라 공통 서비스를 개발하는 별도의 팀을 구성하는 경우와 모든 팀이 개별로 개발하여 배포하는 경우를 예로 들 수 있다. 공통 서비스도 하나의 서비스로 구분하여 단일 팀이 개발하는 경우에는 타 팀의 개발이 시작되기 전 선행적으로 먼저 개발하는 것이 추후 리웍을 줄이는 방안이며, 모든 서비스 간 테스트 방안을 수립해 두는 것이 중요하다.&lt;span&gt; 또한, 각 팀에서 개발한 소스 코드를 머지하기 위한 정책과 배포 시 포함시키는 방안 그리고 무엇보다 개발한 공통 모듈에 대한 검증을 수행하는 단계에 대해 고려되어야 한다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;3) API Composition&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;데이터에 직접 접근하지 못하는 경우 데이터를 조회하기 위한 API를 개발해야 한다. 이로 인해 팀단위 프로젝트의 경우 상호간 협업이 증가하게 된다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;API Composition의 경우 Client/Server/3rd Party 솔루션/DB 등 다양한 위치에서 &lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;API를 조회하고 &lt;/span&gt;조합할 수 있다. Client Side도 msa 형태로 개발이 진행된다면, 가능한 Client Side에서 조합하되, 데이터의 양에 따라 CQRS 또는 데이터 복제를 통해 Join을 허용하는 것이 효과적일 수 있다. 물론 Server Side에서도 Composition을 처리할 수 있지만, Client의 결합도를 높일 수 있어 완전한 MSA 환경으로 데이터를 조회하기 위해서는 서버 사이드 Composition은 지양하는 것이 바람직하다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;4) 소스코드 관리&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;소스코드 관리의 경우 owner, maintainer, developer 등으로 구분하는 역할 기반 롤 배정 방식과 Commit, Merge, Branch 정책 등을 세분화하여 설계하는 정책 기반 롤 배정 방식이 있다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;역할기반 롤 배정 방식은 각 역할 별 특정 권한을 부여하는 방식이다. 예를 들어 maintainer까지 모든 프로젝트에 대한 merge 승인권한을 부여하거나, developer까지 feature branch push 권한을 부여하는 것과 같은 역할을 기준으로 소스코드에 대한 권한을 분리하여 관리할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;정책기반 롤 배정 방식은 프로세스를 기준으로 수립한다. developer는 MR을 요청하고, maintainer 1명 이상 코드리뷰를 거쳐 머지 승인을 처리하는 프로세스, feature branch는 developer 이상 dev/stg/prd branch 등 main branch는 maintainer 이상의 승인이 있을 경우 merge한다는 프로세스 등을 프로젝트 내에 정의할 수 있다. 이와 같은 정책 기준으로 각 담당자에게 권한을 배정할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;추가로 고려되어야 할 부분은 마이크로서비스로와 관리 조직 규모에 따른 권한 부여이다. 몇개의 팀 내에서 수개의 마이크로서비스를 운영하는 경우에는 각 마이크로서비스를 개발하는 DevOpS 조직 내에서 모두 동일한 권한을 갖고, 타 DevOpS 조직에서 관리하는 마이크로서비스에 접근하고자 할 경우 권한을 제어하여 관리할 수 있다. 또는 내가 속한 DevOps 조직에서도 역할을 세분화하여 이슈과 MR을 통해 권한을 분리하여 관리할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;대체로 마이크로서비스가 증가함에 따라 개발팀이 세분화되고, 개발자가 늘어나면서 점점 공유되는 리소스에 대한 소유권 문제가 증가하게 된다. 소유권은 굉장히 민감한 문제로 발생시점에 해소하지 않을 경우 문제는 점점 더 심화될 가능성이 높다. 또한, 분리에 대한 해소 없이 데이터나 리소스에 대한 접근 권한을 여러 팀이나 여러 개발자에게 중복적으로 제공할 경우 모놀리스 어플리케이션화 된 마이크로서비스 형태가 될 수 있으며, 이는 마이크로서비스의 장점도 감소시킬 뿐더러 협업 체계를 악화 시키는 결과를 초래할 것이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;무엇보다 데이터의 소유권이 명확하지 않을 경우 마이크로서비스를 개발하는 팀 간에 마찰이 빈번하게 발생할 소지가 있다. 이를 해소하기 위해 &lt;/span&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;개발자 수가 증가하거나 개발 팀 단위의 역할이 분산될수록 인터페이스에 대한 체계를 만들고, 서비스 공통 데이터에 대한 처리 프로세스를 수립하여 이를 명확히 따르는 협업체계를 구축할 필요가 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;서비스간 Contract 관리&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;마이크로서비스는 전체 시스템의 일부로써 동작하며, 개별 서비스로의 역할과 함께 타 서비스와의 인터페이스로 서비스간 통신한다. 서비스는 그 자체의 서비스를 수행하거나, 타 서비스를 호출하거나 반대로 타 서비스로부터의 요청을 처리하는 역할을 담당한다. 이때 서비스간 인터페이스를 정의하는 Contract 관리는 무엇보다 중요하다. 특히 대규모 시스템을 개편/구축하는 프로젝트에서 Contact를 정의하고, 개발하는 것은 테스트 시간의 단축과 운영 장애 발생을 감소시키는 중요한 포인트이다. Contract를 관리해 주는 다양한 도구들이 존재하지만, 이번 포스팅에서는 도구 보다는 이론적인 내용에 맞게 접근해 보도록 하자.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;서비스가 증가하고, 서비스간 호출이 복잡해짐에따라, 모든 서비스를 개발하는 담당 파트와 협업하는 것은 때로 시간적인 문제와 효율성 측면에서 고려되어야 한다. 예를 들어 판매 데이터를 조회하기 위해 판매 서비스를 제공하는 팀의 리더와 미팅을 잡고, 조회 시 필요한 데이터를 협의하고, 이를 통해 조회 결과를 테스트하고, 결과에 따라 이 과정을 반복하는 경우 개발 생산성을 저해할 수 있다. 물론 복잡한 비즈니스를 처리하는 경우 반드시 대면 협의가 필요할 수도 있지만, 신속한 서비스 출시라는 측면에서 가능한 간소화 할 필요성이 있다.&lt;/span&gt;&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;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1) 개발자 포털 활용&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;마이크로서비스를 개발하는 프로젝트에서는 서비스간 인터페이스를 정의하는 Swagger와 같은 개발자포털을 커스터마이징하여 개발해야 한다. 개발자포털은 개발자간 API를 처리하기 위한 기본 Contract를 정의하여, 협의전 원하는 데이터를 조회하고 얻어 올 수 있는지 테스트해 볼 수 있는 포털이다. 개발자 포털을 통해 mock을 생성하고, Contract Test 전 api 규격을 확인하여 사전 테스트를 수행하여 원하는 데이터를 가져올 경우 반복적인 협의를 줄일 수 있을 것이다. 이를 위해 개발자 포털은 &lt;span style=&quot;color: #006dd7;&quot;&gt;api 규격, api 테스트&lt;/span&gt;는 물론 상호간 협의할 수 있는 &lt;span style=&quot;color: #006dd7;&quot;&gt;게시판, 알림 기능&lt;/span&gt; 등을 함께 포함하여 구현하는 것이 바람직하다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2) 현행 API 유지 전략&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;신규 서비스가 출시되면, 신규 API가 개발되고, 이전 API를 호출하는 Client와 Contract를 통해 이전 API 운영방식을 공유하는 서비스 규칙을 제공해야 한다. 그렇지 않으면 현행 API를 운영하는 타 서비스에 영향을 끼치게 된다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;이와 같은 문제를 해소하는 방법은 두가지로 생각해 볼 수 있다. 먼저 &lt;span style=&quot;color: #006dd7;&quot;&gt;1) 신규 API가 생성될 경우 이전 API를 호환할 수 있는 API를 생성하는 방법&lt;/span&gt;이다. 이는 AS-IS, TO-BE 모두 하나의 API로 커버할 수 있다는 장점이 있지만, 불필요한 데이터를 주고 받아야 할 수도 있다. 두번째로 &lt;span style=&quot;background-color: #fdfdfd; color: #006dd7;&quot;&gt;2)&lt;/span&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #006dd7;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;이전 API를 유지하고, 신규 URI를 통해 API를 배포하는 방식&lt;/span&gt;이다. 물론 이때 이전 API를 무한정 유지하기보다는 일정 기간 유지하되, 이와 같은 규칙은 사전에 개발자포털을 통해 공지하는 것이 바람직하다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;아래는 고객서비스와 이체서비스간 Contract의 관리를 위한 위 두가지 방식에 대한 처리 흐름을 정리한 이미지이다.&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;1010&quot; data-origin-height=&quot;372&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yY1EZ/btrmY4fR1j2/WbpFXjRr8tExKJRi4rpAtk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yY1EZ/btrmY4fR1j2/WbpFXjRr8tExKJRi4rpAtk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yY1EZ/btrmY4fR1j2/WbpFXjRr8tExKJRi4rpAtk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyY1EZ%2FbtrmY4fR1j2%2FWbpFXjRr8tExKJRi4rpAtk%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;1010&quot; height=&quot;372&quot; data-origin-width=&quot;1010&quot; data-origin-height=&quot;372&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 이체서비스가 제공하던 기존 API (A)에 이체 은행 코드가 추가된 신규 API (B)가 추가되었다. 이때 기존 제공하던 API 서비스를 제공하기 위한 방법에 대해 알아보도록 하자.&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;1223&quot; data-origin-height=&quot;372&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ba7u6h/btrmYE9Sufh/kD6qyfh0foyD98016fauqK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ba7u6h/btrmYE9Sufh/kD6qyfh0foyD98016fauqK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ba7u6h/btrmYE9Sufh/kD6qyfh0foyD98016fauqK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fba7u6h%2FbtrmYE9Sufh%2FkD6qyfh0foyD98016fauqK%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;1223&quot; height=&quot;372&quot; data-origin-width=&quot;1223&quot; data-origin-height=&quot;372&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위 이미지는 현행 API (A) - Service (A) / 신규 API (B) - Service (B)로 각 API 별로 독립적인 Service를 구성하고, 일정 병행 유지 기간이 종료될 경우 현행 API와 Service를 종료하는 방식으로 처리한다. 이는 독립적인 서비스로 운영하기 때문에 안정적으로 운영이 가능하지만, 인프라 관점의 보다 많은 리소스가 필요하고, 필요시 각 API 버전 간 데이터 호환성을 유지할 필요가 있다. 따라서 이와 같은 운영 방식은 단기 병행 운영이 필요할 경우 적합한 방식이라 할 수 있다.&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;1223&quot; data-origin-height=&quot;372&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cN2Qzd/btrmYEoyNrn/kpbQwlyPkLgGYQTtC9k2V0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cN2Qzd/btrmYEoyNrn/kpbQwlyPkLgGYQTtC9k2V0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cN2Qzd/btrmYEoyNrn/kpbQwlyPkLgGYQTtC9k2V0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcN2Qzd%2FbtrmYEoyNrn%2FkpbQwlyPkLgGYQTtC9k2V0%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;1223&quot; height=&quot;372&quot; data-origin-width=&quot;1223&quot; data-origin-height=&quot;372&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;두번째 이미지는 현행 API (A)와 신규 API (B) 모두 신규로 개발된 Service (B)로 연결되는 방식이다. 다만, Service (B)는 API (A)를 호환하도록 개발한다. 이는 마이크로서비스의 복잡도가 증가한다는 문제는 있지만, 현행 API 보존에 대한 문제는 완전히 해소할 수 있다. 이는 장기 병행 운영이 필요한 경우 적합한 운영 방식이라 할 수 있다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위 두가지 방식은 API를 호출하는 호출자입장에서 새로운 API에 대응할 수 있는 시간을 마련할 수 있다는 측면에서 의미가 있다. &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fdfdfd; font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이와 같이 문제점을 해소하면서 최대한 Contract를 유지하고자 노력하더라도 기존 서비스와의 호환성이 깨져 운영 중단되는 경우가 종종 발생할 수 있다. 이러한 문제는 &lt;span style=&quot;color: #006dd7;&quot;&gt;빠른 롤백 메커니즘&lt;/span&gt;이 없는 경우 치명적일 수 있다. 항상 배포에 대한 충분한 테스트가 있었더라도 반드시 롤백을 빠르게 수행할 수 있는 매커니즘을 마련해 두어야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;데이터 분할&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&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: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;마이크로서비스 분산DB 설계 (분산DB 조회 설계) : &lt;/span&gt;&lt;a href=&quot;https://waspro.tistory.com/724&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://waspro.tistory.com/724&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;마이크로서비스 아키텍처를 통해 우리는 이 모놀리식 스키마를 분해하여 데이터 독립성을 유지하는 반면, 데이터 전반에 걸친 대규모 조인 작업과 관련되어 데이터를 제공하기 위한 ReadOnly 복제본을 제공하기도 한다. 그럼에도 불구하고 단일 DB를 사용하던 과거와 다르게 데이터가 논리적으로 격리된 여러 스키마에 분산되어 있으므로 이를 구현하는 것은 굉장히 어려운 일이다. &lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;대표적으로 분산 데이터를 통합하여 조회하는 경우의 예를 들자면, 배치/리포팅을 들 수 있다. &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;배치/리포팅의 경우 여러 데이터베이스에 분리되어 있는 데이터를 조합해야 할 필요가 있다. 아래는 &lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;독립적으로 서비스하는 각 서비스 별 소유권을 갖는 DB와 배치/리포트를 처리하는 DB에 각각 Pooling하며, 서로 다른 비즈니스를 처리하는 방식이다. 이를 통해 배치/리포트 사용자의 특정 요구 사항을 염두에 두고 데이터베이스를 변경할 수 있다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;div id=&quot;idm46387401009080&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1293&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVQWop/btrm2nTi1vz/9rtYuO5T98cI9wFRO7RVUK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVQWop/btrm2nTi1vz/9rtYuO5T98cI9wFRO7RVUK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVQWop/btrm2nTi1vz/9rtYuO5T98cI9wFRO7RVUK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVQWop%2Fbtrm2nTi1vz%2F9rtYuO5T98cI9wFRO7RVUK%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;1293&quot; height=&quot;720&quot; data-origin-width=&quot;1293&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;먼저 직접 Pooling 하는 방식은 가장 Simple하게 구성이 가능하지만, 서비스간 결합도가 배치/리포팅 DB를 통해 상승할 수 있다는 문제가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1293&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dTMyxu/btrmXv6FHSI/rXj7tBSG3mIMWdZLjCb5w1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dTMyxu/btrmXv6FHSI/rXj7tBSG3mIMWdZLjCb5w1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dTMyxu/btrmXv6FHSI/rXj7tBSG3mIMWdZLjCb5w1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdTMyxu%2FbtrmXv6FHSI%2FrXj7tBSG3mIMWdZLjCb5w1%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;1293&quot; height=&quot;720&quot; data-origin-width=&quot;1293&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;두번째 Kafka를 통해 구성하는 방식은 비동기로 복제가 가능하지만, 일부 개발자 역할의 증가 및 데이터 복제에 대한 보장을 솔루션과 응용에서 수행해야 한다는 문제가 있다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1293&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XvpM3/btrm3OXqShr/KPfkLkxhpxvI0gmHxRCAD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XvpM3/btrm3OXqShr/KPfkLkxhpxvI0gmHxRCAD0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XvpM3/btrm3OXqShr/KPfkLkxhpxvI0gmHxRCAD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXvpM3%2Fbtrm3OXqShr%2FKPfkLkxhpxvI0gmHxRCAD0%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;1293&quot; height=&quot;720&quot; data-origin-width=&quot;1293&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;마지막 세번째 CDC 도구를 사용하는 방식은 데이터의 정합성을 보장하여 복제하지만, 이기종 DB 간 복제나 비용적인 문제가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;데이터 분할에 따른 조회 성능을 높이기 위한 여러 방안들은 앞서 제시한 포스팅을 참고하기 바란다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Telemetry 확대 구축 및 장애 대응&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;마이크로서비스 아키텍처로 분할되며, 관리 대상 서버가 증가하고, 복잡한 호출관계에 따라 추적이 복잡해진다. 이로 인해 장애 대응을 위한 Telemetry 환경을 구성하는 것은 필수이다. Telemetry 환경이 구성된 경우 장애에 대해 대응하기 위한 기준을 정의해야 하는데, 이는 각 프로젝트 마다 상이하게 결정할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;예를 들어 마이크로서비스는 클라우드 기반으로 구성되는 것이 기본이며, Kubernetes와 같은 Container 기반 어플리케이션을 구성할 경우 그 단위 하나하나가 굉장이 세분화된다. 또한 각 서비스는 Replica를 기준으로 복제되고 Resilience가 높아 가용성과 성능을 보장하는 방식으로 구성된다. 이때, 특정 Container 한대가 다운되었을 경우 어떻게 대처해야 할까?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;또 다른 예로 모놀리스 어플리케이션에서 CPU가 오랫동안 100%에 머무른다면 큰 문제가 될 것이다. 수십 또는 수백 개의 프로세스가 있는 마이크로서비스 아키텍처에서 특정 한 프로세스만 CPU 100%를 유지할 경우 장애조치는 즉각적으로 이루어져야 할까?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;마이크로 서비스 아키텍처가 성장함에 따라 문제 해결을 위한 대응 방식도 변화해야 한다. &lt;/span&gt;위와 같은 경우 대응방안을 판단하기 위해 많은 경험과 기술력이 필요하며, 특히 비즈니스에 대한 명확한 이해가 있어야 한다. 이로 인해 기존 모놀리식 어플리케이션 운영관리와 다르게 MSA를 위한 SRE는 변화되어 관리되고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;div id=&quot;idm46387400982360&quot;&gt;
&lt;div id=&quot;idm46387400977112&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1) Logging&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;수 많은 서비스로 분할 된 마이크로서비스 환경에서 각 머신들에 대한 로그를 일일이 확인하여 상태를 진단하는 것은 사실상 불가능한 일이다. 특히 마이크로서비스 아키텍처는 각 서비스의 수명이 짧아 서비스 장애시 로그를 유실할 수도 있다. 이를 위해 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;통합로그시스템을 구축하고 모든 로그를 공용 공간에 저장하며, 검색, 색인, 추적 관리할 수 있도록 구성해야 한다. 대표적인 도구로 ELK 스택&lt;span style=&quot;color: #000000;&quot;&gt;(Elastic search, Logstash/FluentD 및&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Kibana&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;), Splunk 등&lt;/span&gt;이 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;로그 수집은 구현하기 가장 간단한 메커니즘 중 하나이며 초기부터 구축되어야 한다. 로그의 수집은 초기 문제를 진단하는데 매우 유용하게 사용된다. 단순히 어플리케이션 로그 뿐만 아니라, 해당 프로젝트에서 사용하는 다양한 로그를 수집할 수 있다. 때로는 저널 로그, 인프라 로그를 함께 수집하여 각 서비스 환경에 일일이 접근하지 않고도 쉽게 로그를 확인할 수 있도록 구축해 두는 것은 확장되어 가는 마이크로서비스 점진적 이행 환경에 반드시 선행되어야 할 부분이라는 점을 인지해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;또한, 로그 수집과 함께 병행되어야 할 부분은 바로 로그를 남기는 방안에 대한 고려이다. 마이크로서비스 간 때로는 레가시 시스템과의 인터페이스가 발생할 경우, 비동기 이슈에 대한 추적 등을 어떻게 효과적으로 커버할 수 있을까 고민해 본다면 그 최적의 방안이 바로 로그이기 때문이다. 시스템간의 추적에 로그를 활용하기 위해서는 각 채널 별 공동으로 정의하는 로그 필드를 프로젝트 차원에서 정의/생성하고, 해당 필드를 Elastic search와 Kibana를 통해 추적관리하는 방식으로 구성할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;idm46387400968520&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2) Tracing&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;마이크로서비스 간의 호출이 실패한 위치 또는 지연 시간이 급증한 서비스를 찾아내는 것은 쉽지 않은 과정이다&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;. &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;앞서 살펴본 로깅 시스템과 같이 추적을 위한 시스템을 구축하기 위해서는 추적대상 시스템에 공통으로 정의하는 추적 ID를 생성해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이체 서비스가 요청을 받으면 최초 받은 요청을 받은 서비스에서 추적 ID를 생성한다. 계좌 서비스를 호출할때 생성한 추적 ID를 함께 전달한다. 이는 HTTP 헤더, 메시지 페이로드의 필드 또는 기타 메커니즘을 통해 수행될 수 있다. 일반적으로 초기 첫 마이크로서비스가 호출될 때 생성되는 추적 ID는 서비스 자체적으로 판단하여 생성할 수도 있지만, API 게이트웨이 또는 서비스 메시를 통해 생성되는 것이 일반적이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;계좌 서비스는 요청을 처리할 때 동일한 추적 ID와 함께 로그를 기록할 수 있으므로 로그 수집 시스템을 사용하여 주어진 추적 ID와 연결된 모든 로그를 조회할 수 있다. 물론 saga와 같이 추적 ID를 사용하여 다른 작업을 수행할 수도 있다.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;737&quot; data-origin-height=&quot;460&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/167hK/btrmYk4GAyA/jjILVGacQA8gw7h9BrkqE1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/167hK/btrmYk4GAyA/jjILVGacQA8gw7h9BrkqE1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/167hK/btrmYk4GAyA/jjILVGacQA8gw7h9BrkqE1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F167hK%2FbtrmYk4GAyA%2FjjILVGacQA8gw7h9BrkqE1%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;737&quot; height=&quot;460&quot; data-origin-width=&quot;737&quot; data-origin-height=&quot;460&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&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: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;이와 같은 추적 시스템은 오픈 소스 Zipkine, Jaeger와 같은 분산 추적 시스템을 활용하여 Visualize하여 관리할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;3) Monitoring&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;기존의 모니터링 및 알림 프로세스에서는 무엇이 잘못될 수 있는지 판단하고, 언제 문제가 발생하는지 정보를 수집하여 알림을 발생시키는데 사용되었다. 대체로 디스크 공간 부족, 서비스 인스턴스 미응답 또는 지연 시간 급증과 같은 알려진 문제의 원인을 처리하기 위해 모니터링 시스템을 구축하여 운영한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;마이크로서비스로 변화하면서 시스템이 더 복잡해짐에 따라, 문제점을 사전에 예측하는 것은 점점 더 어려워지고 있다. 따라서 문제 발생 시 조기에 인지하고, 시스템이 지속적으로 동작할 수 있도록 돕는 동시에 향후 문제를 해결하기 위해 충분한 정보를 수집할 수 있도록 하는 것이 모니터링 시스템의 역할로 변모하였다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;이를 위해 모니터링 시스템은 서비스가 무엇을 하고 있는지에 대해 최대한 많은 정보를 수집할 수 있어야 한다. 장애 발생 초기에는 연속성에 포커싱을 맞추었다면, 문제가 해소된 이후에는 기존의 모니터링 시스템과 같이 장애를 진단하기 위해 모놀리식 어플리케이션 보다 더 많은 메트릭이 수집되어야 함은 당연한 사실이다.&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;idm46387400949448&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;4) Testing&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;테스트는 마이크로서비스로 변화하며, CI/CD 파이프라인 내의 기능으로 자동화 되도록 구현하는 것이 중요하다. 특히 배포 전에 어플리케이션의 품질을 검증하는 것이 중요하며, 운영환경에도 기능을 검증할 수 있도록 준비되어야 한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;물론 그 수준의 문제는 있으며, 운영 환경의 신속 배포를 유지하기 위해 테스트 케이스나 종류를 제한하는 것이 일반적이다. 따라서 운영환경에서는 기존의 엔드 투 엔드 테스트 사례를 가져와 적용하는 것도 한가지 방법이 될 수 있다.&lt;/span&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;또한 CDC(Consumer-Driven Contract) 적용을 고려해 볼 수 있다. 서비스간 테스트는 &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Mock을 활용하는 테스트 전략이 일반적이다. 다만, 테스트 케이스의 정합성에 따라 테스트가 통과하더라도 실제 서비스에서 실패 할 수 있음을 인지해야 한다. 이를 보완하기 위해 Spring Cloud Contract 적용을 고려해 볼 수 있다.&lt;/span&gt;&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;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;복잡한 분산 환경에서 정확히 언제 문제가 생길지 예측하는 것은 굉장히 어려운 일이다. 특히 개발자와 테스터들이 운영하기 전 많은 테스트 케이스를 가지고 사전 검증을 수행하지만, 그럼에도 불구하고 어떤 부분에서 문제가 발생했는지 알아내는 것은 어려울 수 있다. 이와 같은 문제들을 해소하기 위해 반드시 Telemetry 환경을 구축하고, 진단을 위한 자동화 체계가 구성되어야 한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;&lt;/div&gt;
&lt;div id=&quot;idm46387400943752&quot;&gt;
&lt;div id=&quot;idm46387400943496&quot;&gt;
&lt;div id=&quot;idm46387400912776&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: -1px;&quot;&gt;관리 플랫폼&lt;/span&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;idm46387400903336&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;점진적 마이크로 서비스 전환이 이루어짐에 따라 관리대상 인프라는 점점 증가하게 된다. 단일 애플리케이션을 관리하기 위한 기존 기술은 변화하는 환경에 대응하기 어렵고, 유연한 확장관리를 지원하지 않는다. &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;이로 인해 문제 해결에 소요되는 시간이 점점 더 증가할 수 있으며, 수동 작업에 의존할 경우 반복적인 실수가 발생할 수 있다. &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;이로인해 유지 보수를 위한 더 많은 인력을 요하거나, 서비스를 제공하는 팀이 문제를 해결하는데 더 많은 시간을 할애해야 한다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;이를 해소하기 위해서는 높은 수준의 자동화를 지원하고, 개발자가 배포 환경을 이상적으로 셀프 서비스할 수 있으며, 원하는 자동 상태 관리를 처리할 수 있는 도구가 필요하다. &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;마이크로서비스의 경우 쿠버네티스가 이 분야의 강자로써 떠올랐다. Kubernetes를 사용하면 경량화된 컨테이너 환경을 지원하며, 여러 시스템에 걸쳐 서비스 인스턴스를 배포하여 회복력을 개선하고 유동적인 부하를 처리할 수 있도록 자동확장 기능을 적용할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;Kubernetes는 오픈소스로 Original Version인 바닐라 쿠버네티스만으로는 개발자/운영자에게 친화적인 환경을 지원하지 않는다. Kubernetes 장점의 이면에는 높은 러닝커브가 발생할 수 있다는 문제가 있어 즉시 활용에는 제약이 있는 상황이다. 이에 CSP 사인 AWS EKS, Azure AKS, GCP GKE 나, Private Cloud의 RedHat의 OpenShift, VMWare의 Tanzu, 국내에는 나무기술의 &lt;span style=&quot;background-color: #ffffff; color: #222222;&quot;&gt;Cocktail Cloud, 맨텍의 &lt;span style=&quot;background-color: #ffffff; color: #222222;&quot;&gt;Aaccordion, 티맥스클라우드의 HyperCloud&lt;/span&gt;&lt;/span&gt;와 같은 Kubernetes 패키지 버전을 채택하는 경우가 있다. 이 패키지는 Kubernetes를 Enterprise 환경 내에서 보다 쉽게 활용할 수 있는 도구를 함께 제공한다. 예를 들어, CI/CD를 위한 Tekton, S2I Builder 등을 함께 패키징하여 손쉽게 배포 프로세스를 제공하거나, Telemetry 모듈인 Grafana, Zipkin 등을 포함하여 손쉬운 추적관리 시스템을 구축할 수 있도록 제공하고 있다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;물론, Kubernetes와 같은 플랫폼은 여러 프로세스를 관리하는데 탁월하지만, 높은 러닝커브로 인해 반드시 시스템을 운영하는 부서에서 기술 내재화를 거쳐 구축/운영하는 과정이 필요하다. 따라서 빅뱅방식의 전환이 아닌 점진적 이행과 플랫폼 전환, MiniService 전환 등을 거쳐 MicroService로 전환해 가는 것이 바람직하다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;&lt;/div&gt;
&lt;div id=&quot;idm46387400908600&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div id=&quot;idm46387400716136&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;결론&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;이번 포스팅에서는 점진적 마이크로서비스 전환에 따른 영향도에 대해 살펴보았다. &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;기존 모놀리식 시스템을 분해하기로 결정했다면 점진적으로 진행하며, 빅뱅방식으로의 전환은 지양하는것이 좋다. 점진적인 접근 방식을 진행하면서 마이크로서비스에 대해 이해도를 높여가며 기술 내재화를 진행하고, 또한 방향성이 잘못된 서비스를 바로 잡아가며 전환하는 것이 바람직할 것이다.&lt;br /&gt;모놀리식 시스템을 마이크로서비스 아키텍처로 옮기는 비용이 클 수 있고, 모든 것을 한 번에 수행하는 경우 매몰비용이 크게 작용할 수도 있다. 따라서 단위를 작게 세분화하여 요구사항에 맞는 서비스부터 점진적으로 전환해 나가는 것이 성공 가능성을 높일 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;최초 마이크로서비스를 전환하는데 걸리는 시간은 다소 오래 걸리 수 있다. 기반 인프라 구축 부터 프로세스 정립, 조직 변화 체계 수립 등 준비 과정이 필요하기 때문이다. 다만, 두번째, 세번째 점진적 전환을 시도할 경우 보다 빠르게 접근할 수 있다. 앞선 경험으로부터 이번 전환이 얻을 수 있는 이점을 판단해 볼 수 있고, 다음 단계를 더 쉽게 만들고 추진력을 얻을 수 있기 때문이다.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>③ 클라우드/ⓜ MSA</category>
      <category>MSA</category>
      <category>msa 권한 분리</category>
      <category>마이크로서비스</category>
      <category>마이크로서비스 아키텍처</category>
      <category>점진적이행</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/751</guid>
      <comments>https://waspro.tistory.com/751#entry751comment</comments>
      <pubDate>Sat, 4 Dec 2021 01:08:52 +0900</pubDate>
    </item>
    <item>
      <title>마이크로서비스 분산 트랜잭션 관리 (Saga Pattern)</title>
      <link>https://waspro.tistory.com/735</link>
      <description>&lt;div id=&quot;ch05-sagas&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;개요&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;앞선 포스팅에서 마이크로서비스 분산DB 환경에서 고려되어야 할 사항에 대해 살펴보았다. 자세한 내용은 아래 포스팅을 참고하기 바란다.&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: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;마이크로서비스&amp;nbsp;분산&amp;nbsp;트랜잭션&amp;nbsp;관리&amp;nbsp;(2Phase&amp;nbsp;Commit)&amp;nbsp;:&amp;nbsp;&lt;a href=&quot;https://waspro.tistory.com/734&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://waspro.tistory.com/734&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;마이크로서비스&amp;nbsp;Schema&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;a href=&quot;https://waspro.tistory.com/730&quot;&gt;https://waspro.tistory.com/730&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;마이크로서비스&amp;nbsp;데이터베이스&amp;nbsp;분리&amp;nbsp;설계&amp;nbsp;:&amp;nbsp;&lt;a href=&quot;https://waspro.tistory.com/729&quot;&gt;https://waspro.tistory.com/729&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;마이크로서비스&amp;nbsp;분산DB&amp;nbsp;설계&amp;nbsp;(분산DB&amp;nbsp;데이터&amp;nbsp;분할,&amp;nbsp;동기화&amp;nbsp;설계)&amp;nbsp;:&amp;nbsp;&lt;a href=&quot;https://waspro.tistory.com/726&quot;&gt;https://waspro.tistory.com/726&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;마이크로서비스&amp;nbsp;분산DB&amp;nbsp;설계&amp;nbsp;(분산DB&amp;nbsp;조회&amp;nbsp;설계)&amp;nbsp;:&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://waspro.tistory.com/724&quot;&gt;https://waspro.tistory.com/724&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;마이크로서비스 아키텍처의 기준과 DB 분리 :&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://waspro.tistory.com/718&quot;&gt;https://waspro.tistory.com/718&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이번 포스팅에서는 분산트랜잭션 환경에서 데이터 원자성을 유지하기 위한 Saga Pattern에 대해 알아보자. &lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;Saga는 서비스 독립적으로 실행할 수 있도록 모델링되어&lt;/span&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt; 2PC와 같이 장기간 자원에 Lock을 잡을 필요가 없다.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;지금부터 이 Saga를 모델링하는 과정에 대해 알아보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;div id=&quot;ch05-transactions&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Saga Pattern&lt;/span&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Saga는 단일 데이터베이스에서 장시간 동작하는 트랜잭션에 대해 서포트하는 메커니즘으로 계획되었지만, 여러 서비스에 걸친 트랜잭션을 관리하는 데에도 적합하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&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: 'Noto Serif KR'; color: #000000;&quot;&gt;계좌이체 시작&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;고객서비스를 통해 먼저 타행 이체 서비스를 위한 대상 고객 정보를 조회한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;계좌서비스를 통해 타행 이체를 위한 잔액을 조회한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이체서비스를 통해 타행으로 계좌이체를 요청한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;타행서비스를 통해 타행에 금액을 이체하고 결과를 이체서비스에 전달한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;계좌서비스를 통해 이체가 성공했을 경우 잔액을 반영한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;계좌이체 종료&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;여기서 계좌이체 요청은 단일 사가(Saga)로 표현되며, 이 흐름의 각 단계는 서로 다른 서비스가 수행할 수 있는 작업을 나타낸다. 각 서비스 내에서 모든 상태 변경은 로컬 ACID 트랜잭션 내에서 처리될 수 있다. 예를 들어, 이체서비스를 사용하여 이체한 금액에 대해 내부적으로 기록하하고 실패 시 롤백 처리할 수 있다. (물론 이체서비스의 경우 타행이체를 위한 또 다른 서비스와 연관되어 있어 이를 처리하는 로직이 필요하지만, 이에 대해서는 아래 보상트랜잭션 설계에서 자세히 알아보도록 하자.) 또한, 계좌서비스의 잔액반영 시에도 잔액 반영에 실패할 경우 로컬 데이터베이스 내에서 트랜잭션을 관리할 수 있다. 결국 각 서비스에 대한 정상 처리가 수행될 경우 로컬 트랜잭션 별로 ACID를 관리하는 것은 전혀 문제가 되지 않는다.&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div id=&quot;ch04-order-process-overview&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1264&quot; data-origin-height=&quot;649&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dqmVYf/btrmidyium1/hoIHGPyHzqtLDNk6lK7sk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dqmVYf/btrmidyium1/hoIHGPyHzqtLDNk6lK7sk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dqmVYf/btrmidyium1/hoIHGPyHzqtLDNk6lK7sk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdqmVYf%2Fbtrmidyium1%2FhoIHGPyHzqtLDNk6lK7sk1%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;1264&quot; height=&quot;649&quot; data-origin-width=&quot;1264&quot; data-origin-height=&quot;649&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;div id=&quot;idm46387401273592&quot;&gt;&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Saga 실패 시 처리 방안&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;마이크로서비스는 개별 트랜잭션으로 분할되면서 트랜잭션 실패가 발생했을 때 복구하는 방법을 고려해야 한다. Saga에서 설명하는 복구 방법으로는 &lt;span style=&quot;background-color: #ffffff;&quot;&gt;backward/forward recovery 두가지&lt;/span&gt;가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;먼저 &lt;span style=&quot;background-color: #ffffff;&quot;&gt;backward recovery&lt;/span&gt;는 트랜잭션 실패시 롤백을 처리하는 방식이다. 따라서 이전에 커밋된 트랜잭션을 취소할 수 있는 보상 트랜잭션을 정의해야 한다. &lt;span style=&quot;background-color: #ffffff;&quot;&gt;forward recovery&lt;/span&gt;는 장애가 발생한 지점에서 중지하지 않고 계속 처리하는 방식이다. 따라서 트랜잭션을 재시도할 수 있도록 충분한 정보를 유지하고 있어야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;비즈니스 프로세스의 특성에 따라 &lt;span&gt;모델링되는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;모든 실패 상황에는 &lt;span style=&quot;background-color: #ffffff;&quot;&gt;backward/forward recovery&lt;/span&gt; 또는 이 둘의 혼합을 통해 적절한 처리 방식을 선택해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Saga B&lt;span style=&quot;background-color: #ffffff;&quot;&gt;ackward Recovery&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;단일 데이터베이스 내 ACID 트랜잭션을 사용하면 실패 발생 시 커밋 전에 롤백이 발생한다. 그러나 마이크로서비스 환경에서는 여러 트랜잭션이 관련되어 있어 서비스간 독립적인 트랜잭션이 발생할 때 실패 발생 전 커밋된 데이터에 대한 복원 정책을 마련해야 한다. 지금부터는 이러한 상황에서 어떻게 이전 데이터로 롤백을 처리할 것인지에 대해 알아보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1264&quot; data-origin-height=&quot;649&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mJyiE/btrmlYUu3Uh/BOjsxc8RKn6V9ORrv3ggd0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mJyiE/btrmlYUu3Uh/BOjsxc8RKn6V9ORrv3ggd0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mJyiE/btrmlYUu3Uh/BOjsxc8RKn6V9ORrv3ggd0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmJyiE%2FbtrmlYUu3Uh%2FBOjsxc8RKn6V9ORrv3ggd0%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;1264&quot; height=&quot;649&quot; data-origin-width=&quot;1264&quot; data-origin-height=&quot;649&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&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: 'Noto Serif KR'; color: #000000;&quot;&gt;계좌이체 시작&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;고객서비스를 통해 먼저 타행 이체 서비스를 위한 대상 고객 정보를 조회한다. (성공)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;계좌서비스를 통해 타행 이체를 위한 잔액을 조회한다.&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(성공)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이체서비스를 통해 타행으로 계좌이체를 요청한다.&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(성공)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;타행서비스를 통해 타행에 금액을 이체하고 결과를 이체서비스에 전달한다.&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(성공)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;계좌서비스를 통해 이체가 성공했을 경우 잔액을 반영한다.&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;(실패)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;타행서비스 반영이 정상적으로 완료된 후 계좌서비스에서 잔액을 반영하고자 하였으나, 타행이체가 처리되는 동안 카드 값이 자동이체되어 잔액이 마이너스가 되는 상황을 가정해 보자.(물론, 금융권에서 이렇게 방어코드 없이 개발하지는 않겠지만, 시나리오 가정임을 이해해 주시기를..) 이때 앞서 반영한 타행서비스의 이체결과와 이체서비스의 계좌이체 성공이력을 롤백해야 하는 상황이 발생한다. 이미 타행서비스를 통해 계좌 이체가 처리 되어 +@ 만큼 통장 잔액이 증가했을 텐데 이에 대해 롤백 처리를 어떻게 구현해야 할지 알아 보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;이 모든 단계가 단일 데이터베이스 트랜잭션에서 수행된 경우 간단한 롤백으로 정리할 수 있었을 것이다. 그러나 이체서비스, 타행서비스, 계좌서비스 서로 다른 세 서비스에서 상호간의 호출에 의해 처리 되었기 때문에 일괄 롤백으로 처리할 수는 없다. &lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;대신 롤백을 구현하려면 보상 트랜잭션을 구현해야 한다. (보상 트랜잭션은 이전에 커밋 된 트랜잭션을 취소하는 작업)&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1747&quot; data-origin-height=&quot;649&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/W67Qe/btrmjb7Qdtx/Rj2IIGX06K7lfrUU9w3Fk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/W67Qe/btrmjb7Qdtx/Rj2IIGX06K7lfrUU9w3Fk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/W67Qe/btrmjb7Qdtx/Rj2IIGX06K7lfrUU9w3Fk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FW67Qe%2Fbtrmjb7Qdtx%2FRj2IIGX06K7lfrUU9w3Fk0%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;1747&quot; height=&quot;649&quot; data-origin-width=&quot;1747&quot; data-origin-height=&quot;649&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;위는 보상트랜잭션을 적용한 서비스 흐름을 재정리한 내용이다.&lt;/span&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: 'Noto Serif KR'; color: #000000;&quot;&gt;계좌이체 시작&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;고객서비스를 통해 먼저 타행 이체 서비스를 위한 대상 고객 정보를 조회한다. (성공)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;계좌서비스를 통해 타행 이체를 위한 잔액을 조회한다.&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(성공)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이체서비스를 통해 타행으로 계좌이체를 요청한다.&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(성공)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;타행서비스를 통해 타행에 금액을 이체하고 결과를 이체서비스에 전달한다.&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(성공)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;계좌서비스를 통해 이체가 성공했을 경우 잔액을 반영한다.&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;(실패)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #ee2323;&quot;&gt;1) 타행이체취소 보상트랜잭션 요청&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #ee2323;&quot;&gt;2) 이체성공 &amp;gt; 이체실패처리 요청&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;계좌이체 종료&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이러한 보상 트랜잭션은 커밋 후에 롤백을 정의하므로 완전히 처음과 동일한 상태로 돌아기지 못하는 경우도 발생한다. 이와 같은 이유로 보상거래를 의미론적 롤백이라고도 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;또한, 롤백을 구현하며 기존 비즈니스를 개선하여 처리할 수도 있다. 계좌이체 트랜잭션의 마지막 단계에서 성공적으로 완료되었을 경우 Push로 정상 이체가 완료되었다는 알림을 보내는 형태가 존재한다고 가정하자. 만약 우리가 그것을 롤백하기로 결정한다면, 거래에 문제가 발생하여 이체가 취소되었음을 알리는 Push 알림을 고객에게 보낼 수도 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Saga Forward &lt;span style=&quot;background-color: #ffffff;&quot;&gt;Recovery&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;idm46387401278024&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;때때로 &lt;/span&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;장애가 발생한 지점에서 중지하지 않고 계속 처리해야 하는 경우가 발생할 수 있다. 실패가 발생한 시점에 즉시 복구가 중요하지 않은 서비스이거나, 실패한 내용이 성공한 부분보다 굉장히 사소한 부분일 경우, 또는 트랜잭션을 다시 시작할 경우 부하가중이 심각할 경우, 또는 보상트랜잭션을 구성하지 않고도 실패에 대해 알림을 주고, 그 경우가 클라이언트 입장에서 허용될 수 있을 경우 등에 Forward Recovery를 적용할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; letter-spacing: 0px;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;예를 들어, 물건을 구매하는 비즈니스를 예를 들어보자. 고객으로부터 돈을 받아 물건을 포장한 후 주문 처리까지 완료된 이후 배송을 처리하다 실패가 발생하였다. 배송에서 어떤 이유로 실패가 발생하였다고 해서 앞서 성공한 구매, 포장 프로세스까지 롤백 처리하는 것은 비즈니스 상 적절하지 않은 방안이라 할 수 있다. 이를 해소하기 위해 배송에 실패한 원인에 대해 분석하고 이를 재시도 함으로써 실패를 처리할 수 있다. 이때 실패에 대한 분석 작업, 클라이언트에게 배송간 문제가 발생했다는 알림 전송 등을 사람이 직접 개입하여 처리해야 하는 경우도 발생할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div id=&quot;idm46387401271832&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;비즈니스 프로세스 개선&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;비즈니스 순서를 변경하면 롤백 시나리오를 보다 간단하게 만들 수 있다. 아래와 같이 잔액반영과 계좌이체의 순서를 변경하여 타행 서비스가 수행되기 전 계좌서비스 내 처리를 한번에 수행되도록 묶고, 타행서비스와 같이 외부 인터페이스로의 호출을 가장 뒤로 배치하였다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1747&quot; data-origin-height=&quot;650&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ciozT3/btrmmc5PiZM/e6eYNuZQN69AVcGb3pSfDk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ciozT3/btrmmc5PiZM/e6eYNuZQN69AVcGb3pSfDk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ciozT3/btrmmc5PiZM/e6eYNuZQN69AVcGb3pSfDk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FciozT3%2Fbtrmmc5PiZM%2Fe6eYNuZQN69AVcGb3pSfDk%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;1747&quot; height=&quot;650&quot; data-origin-width=&quot;1747&quot; data-origin-height=&quot;650&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;이렇게 하면 앞서 실패가 발생한 원인이었던 타행이체가 진행되는 도중 카드값이체로 인한 잔액 부족 현상은 발생하지 않을 것이다. 또한, 타행서비스와 묶여있는 서비스를 단일화하여(이체서비스) 직접 트랜잭션을 관리할 수 없는 서비스에 대한 영향도를 최소한으로 줄일 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;u&gt;&lt;i&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;&quot;때로는 프로세스가 수행되는 방법을 조정하는 것만으로 롤백 작업을 간소화할 수 있다. 실패할 가능성이 가장 높은 단계를 앞당기거나, 여러 서비스를 번갈아가면서 처리하기보다는 단일 트랜잭션 내에서 처리 가능한 프로세스를 하나로 묶어 주는 것이 보상트랜잭션을 줄이는 방법이라 할 수 있다. &lt;/span&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;이러한 변화들이 수용될 수 있다면, 몇몇 단계들에 대한 보상적인 거래들을 만들 필요가 없기 때문에 보다 쉽게 분산트랜잭션을 설계하고 개발할 수 있다. 이는 보상거래를 구현하기 어려운 경우에 특히 중요할 수 있다.&quot;&lt;/span&gt;&lt;/span&gt;&lt;/i&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;idm46387401241496&quot;&gt;
&lt;div id=&quot;idm46387401241496&quot;&gt;&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Saga 구현&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;지금부터는 saga를 구현하는 방법에 대해 알아보자. saga는 대체로 두 가지 스타일로 구현한다. 먼저 &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Orchestrated saga&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;는 &lt;/span&gt;주로 중앙에서 관리하는 프레임워크 또는 미들웨어를 통해 통제되는 방식이다. 보상트랜잭션을 관리하는 중앙집중식 방식으로 개발 부담을 덜 수 있지만, 결합도가 올라간다. 두번째로 Choreographed saga는 느슨하게 결합된 모델을 선호하는 경우 적용할 수 있지만, 비즈니스를 이해하고 적용할 수 있도록 높은 개발 난이도를 요구하며, saga의 진행 과정을 더 복잡하게 만들 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div id=&quot;idm46387401231992&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Orchestrated Saga&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Orchestrated Saga는 실행 순서를 정의하고 필요한 보상 작업을 트리거하기 위해 중앙 오케스트레이터를 사용한다. 중앙 오케스트레이터는 어떤 일이 언제 발생하는지 제어하며, 이를 통해 주어진 saga에서 어떤 일이 일어나고 있는지에 대한 가시성을 확보할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1275&quot; data-origin-height=&quot;732&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbk2Tt/btrmifiOxGr/i1EbPzbLZ8PchN5SC5Infk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbk2Tt/btrmifiOxGr/i1EbPzbLZ8PchN5SC5Infk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbk2Tt/btrmifiOxGr/i1EbPzbLZ8PchN5SC5Infk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbbk2Tt%2FbtrmifiOxGr%2Fi1EbPzbLZ8PchN5SC5Infk%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;1275&quot; height=&quot;732&quot; data-origin-width=&quot;1275&quot; data-origin-height=&quot;732&quot;/&gt;&lt;/span&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: 'Noto Serif KR'; color: #000000;&quot;&gt;계좌이체 시작&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Transfer Orchestrator는 계좌서비스에 잔액반영을 요청한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Transfer Orchestrator는 이체서비스에 계좌이체를 요청한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Transfer Orchestrator는 타행서비스에 타행이체를 요청한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;계좌서비스는 잔액이 충분하여 잔액반영 후 서비스응답처리 채널을 통해 Transfer Orchestrator에 결과를 알린다.&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(성공)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;이체서비스는 계좌이체 대상의 계좌 정보 확인 후 서비스응답처리 채널을 통해 Transfer Orchestrator에 결과를 알린다. (성공)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #ee2323;&quot;&gt;1) 타행서비스는 타행이체 시 타행의 점검 시간과 겹쳐 이체에&amp;nbsp; 실패하였고 이를 서비스응답처리 채널을 통해 Transfer Orchestrator에 결과를 알린다.&amp;nbsp;(실패)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #ee2323;&quot;&gt;2) Transfer Orchestrator는 성공한 서비스인 계좌서비스와 이체서비스에 롤백을 수행하기 위해 보상 처리를 위한 정보를 제공하고, 보상 트랜잭션을 요청한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #ee2323;&quot;&gt;3) 계좌서비스와 이체서비스를 보상 트랜잭션을 처리하기 위해 각각 잔액롤백처리와 계좌이체실패처리에 대한 이벤트를 수신하고, 롤백(의미론적 롤백)을 처리한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;계좌이체 종료&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;&lt;span&gt;오케스트레이터의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;역할을 &lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;하는 Transfer Orchestrator가 프로세스를 조정한다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;서비스 처리는 물론 보상을 처리하기 위해 어떤 서비스가 필요한지 알고 있으며, 언제 해당 서비스를 요청해야 할지 결정한다. 만약 요청이 실패한다면, 그에 따르는 보상처리를 위해&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt; 무엇을 해야 할지 결정할 수 있다. 이러한 &lt;span&gt;오케스트레이션된&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;프로세서는 서비스 간 요청/응답 호출을 많이 사용하는 경향이 있다. Transfer Orchestrator는 서비스(예: 계좌, 이체, 타행서비스)에 요청을 보내고 요청이 성공했는지 여부를 알려주고 요청 결과를 제공하는 응답을 기다린다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;Transfer Orchestrator 내부에서 비즈니스 프로세스를 명시적으로 모델링하는 것은 매우 유용하다. 요청과 보상을 처리하는 지점을 단일화하여 동작 방식을 쉽게 이해할 수 있도록 도와주며, 새로운 서비스가 더해질때 보다 쉽게 서비스 프로세스를 정의할 수 있다. 반면에&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;&amp;nbsp;Orchestrated&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt; Saga는 오케스트레이터를 기반으로 &lt;/span&gt;결합된 방식이다. Transfer Orchestrator는 모든 관련 서비스에 대해 알아야 하므로 도메인 커플링이 높아질 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div id=&quot;idm46387401241496&quot;&gt;
&lt;div id=&quot;idm46387401233016&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Choreographed Saga&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;Crchestrated S&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;aga가&lt;/span&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt; 중앙 오케스트레이터에 의한 제어 방식이라면,&amp;nbsp;&lt;/span&gt;&lt;span&gt;Choreographed Saga&lt;/span&gt;는 운영에 대한 책임을 마이크로서비스에 분산시키는 방식이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1081&quot; data-origin-height=&quot;777&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9LQAj/btrmlXuKg1n/GtnYKNgnKQc2Gr3klhQk41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9LQAj/btrmlXuKg1n/GtnYKNgnKQc2Gr3klhQk41/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9LQAj/btrmlXuKg1n/GtnYKNgnKQc2Gr3klhQk41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9LQAj%2FbtrmlXuKg1n%2FGtnYKNgnKQc2Gr3klhQk41%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;1081&quot; height=&quot;777&quot; data-origin-width=&quot;1081&quot; data-origin-height=&quot;777&quot;/&gt;&lt;/span&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: 'Noto Serif KR'; color: #000000;&quot;&gt;0. 이체 요청 및 이체금액, 이체대상 은행, 고객명 등에 대한 이벤트를 생성한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #ee2323;&quot;&gt;1~2. 계좌서비스는 이체금액에 대한 이벤트를 수신하여 잔액이 충분할 경우 잔액을 반영 후 이벤트를 생성하고, 잔액이 부족할 경우 잔액부족을 알리고 트랜잭션을 종료한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #ee2323;&quot;&gt;3~4. 이체서비스는 계좌이체 대상 은행, 고객명 등에 대한 이벤트를 수신하고, 계좌이체 대상이 확인되었으면, 이벤트를 생성, 계좌이체 대상이 확인되지 않을 경우 계좌서비스에 보상트랜잭션을 요청한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #ee2323;&quot;&gt;5~6. 타행서비스는 타행이체 대상 은행, 고객명, 이체 금액 등에 대한 이벤트를 수신하고, 타행으로부터 이체 결과를 기다린다. 이체 결과가 성공일 경우 이체 요청자에게 Push 알림을 전송하고, 실패할 경우 이체서비스, 계좌서비스에 보상트랜잭션을 요청한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;계좌서비스는 잔액이 충분하여 잔액반영 후 서비스응답처리 채널을 통해 Transfer Orchestrator에 결과를 알린다.&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(성공)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;위와 같이 서비스가 보상트랜잭션을 결정하고 처리하는 방식이 바로 Choreographed 방식이라 할 수 있다. 이러한 서비스들은 수신되는 이벤트에 반응하고 있다. 이벤트는 요청자 또는 서비스로부터 송신되며, 이를 구독하는 또 다른 서비스가 수신하는 방식이다. 즉 이벤트를 서비스에 직접 보내는 것이 아니라 이벤트에 관심 있는 서비스가 이벤트를 수신하고 그에 따라 조치를 취하는 방식이다. 이 예시에서 계좌서비스는 첫 번째 이체요청-잔액확인 이벤트를 받을 때 통장 잔액을 확인하고 잔액이 충분할 경우 잔액을 반영하고 이벤트를 생성하지만, 잔액이 부족할 경우 해당 시점에서 이체요청이 중단될 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;이와 같은 방식에 적합한 적용 방식이 바로 Kafka와 같은 MQ 서비스를 적용하는 것이다. &lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;여러 서비스가 동일한 이벤트에 반응할 수 있다. &lt;/span&gt;&lt;/span&gt;특정 유형의 이벤트에 관심이 있는 서비스는 이러한 이벤트가 어디에서 왔는지 고민할 필요 없이 특정 주제를 구독하고 브로커는 Topic의 내구성 관리 및 해당 이벤트가 구독자에게 성공적으로 전달되도록 보장한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;Orchestrated Saga와 다르게 Choreographed Saga의 장점은 Publishing 한 서비스가 누구인지 알 필요 없이 특정 이벤트가 수신되었을 때 무엇을 해야 하는지만 알면된다는 점이다. 본질적으로, 이것은 Loosly Coupled 아키텍처를 만든다. &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;반면에 단점으로는 서비스 간 결합도가 낮아짐에 따라 &lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;추적이 점점 더 어려워질 수 있다는 것이다. 오케스트레이터의 명시적인 모델링과 다르게 간단한 비즈니스 프로세스도 각 서비스의 동작을 개별적으로 살펴보고 비즈니스를 재구성해야 한다.&lt;/span&gt;&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;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;특히 Choreographed Saga의 경우 이벤트에 대한 처리 상태를 저장할 수 있는 별도의 공간이 부재하다는 문제가 있다. 오케스트레이터가 담당하던 역할 역시 Choreographed Saga에서도 보상 처리를 위해 필수적으로 필요하며, 이를 간단히 구현하는 방법에 대해 알아보자.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;u&gt;&lt;i&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&quot;이벤트를 소비할 때 Saga의 상태를 저장하는 방법을 사용한다. Saga에 대한 Unique ID를 생성하고 송/수신되는 모든 이벤트에 이를 포함한다. 이 ID를 기반으로 보상트랜잭션을 위한 Event 정보를 관리하거나 각 서비스의 상태 정보를 확인할 수 있다.&quot;&lt;/span&gt;&lt;/i&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;&lt;/div&gt;
&lt;div id=&quot;idm46387401180120&quot;&gt;
&lt;div id=&quot;idm46387401305064&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;결론&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;지금까지 마이크로서비스의 분산 트랜잭션 처리 방식과 Saga Patten에 대해 알아 보았다. Saga Pattern은 분산 트랜잭션 환경에서 서비스 간 결합도를 낮추고 보상 처리를 설계하는 패턴 중 하나이다. Saga는 비즈니스에 적합한 적용 방식에 따라 서비스 to 서비스 간 비즈니스 흐름을 개선하여 보상 트랜잭션을 최소화 하는 것이 바람직하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;물론 그럼에도 불구하고 보상 트랜잭션을 설계해야 한다면, 프로젝트의 규모에 따라 Choreographed Saga와 Orchestrated Saga를 선택하는 것이 좋다. &lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;선택기준으로 명확히 제시된 것은 없지만, 일반적으로 프로젝트의 규모에 따라 선택기준을 분리해 볼 수 있다. 단순하게 Loosley Coupled 지향의 Choreographed Saga는 대규모 프로젝트에서 각 팀간의 결합도를 낮추고 개발에 영향을 최소화 하기 위해 선택하기 용이하다. 반면에 Orchestrated Saga는 단일 팀 내에서 개발 가능한 경우 중앙 관리 방식으로 개발하는 것이 효과적일 것이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>③ 클라우드/ⓜ MSA</category>
      <category>choreography</category>
      <category>msa saga</category>
      <category>Orchestrator</category>
      <category>SAGA</category>
      <category>saga pattern</category>
      <category>마이크로서비스 saga</category>
      <category>사가</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/735</guid>
      <comments>https://waspro.tistory.com/735#entry735comment</comments>
      <pubDate>Tue, 23 Nov 2021 14:45:06 +0900</pubDate>
    </item>
    <item>
      <title>마이크로서비스 분산 트랜잭션 관리 (2Phase Commit)</title>
      <link>https://waspro.tistory.com/734</link>
      <description>&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;개요&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;앞선 포스팅에서 마이크로서비스 분산DB 환경에서 고려되어야 할 사항에 대해 살펴보았다. 자세한 내용은 아래 포스팅을 참고하기 바란다.&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; font-family: 'Noto Serif KR';&quot;&gt;마이크로서비스 Schema 분리 설계 (테이블 분리, 외래키 참조관계, 조인, 데이터 정합성 보장) : &lt;a href=&quot;https://waspro.tistory.com/730&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://waspro.tistory.com/730&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;마이크로서비스 데이터베이스 분리 설계 : &lt;a href=&quot;https://waspro.tistory.com/729&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://waspro.tistory.com/729&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;마이크로서비스 분산DB 설계 (분산DB 데이터 분할, 동기화 설계) : &lt;a href=&quot;https://waspro.tistory.com/726&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://waspro.tistory.com/726&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;마이크로서비스 분산DB 설계 (분산DB 조회 설계) : &lt;/span&gt;&lt;a href=&quot;https://waspro.tistory.com/724&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://waspro.tistory.com/724&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;마이크로서비스 아키텍처의 기준과 DB 분리 : &lt;/span&gt;&lt;a href=&quot;https://waspro.tistory.com/718&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://waspro.tistory.com/718&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;이번 포스팅에서는 분산 환경에서의 트랜잭션 관리 방법에 대해 알아보자.&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt; 단일 DB 환경에서는 데이터의 안전성과 일관성을 보장하는 데이터베이스에 의존하여 개발과 성능 보장에 포커싱을 맞춰 접근할 수 있다. 그러나 데이터베이스 간에 데이터를 분할할 경우 데이터베이스 트랜잭션을 사용하여 상태 변화를 ACID 원칙에 따라 보장할 수 없어 그 이점이 사라진다. 이를 해결하기 위한 방안에 대해 살펴보도록 하자.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;먼저 이 문제를 해결하는 방법에 대해 살펴보기 전 데이터베이스 트랜잭션이 제공하는 내용을 간략하게 살펴보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;div id=&quot;ch05-transactions&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;ACID Transaction&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;일반적으로 데이터베이스 트랜잭션에 대해 이야기할 때 ACID 트랜잭션에 대해 이야기한다. ACID는 데이터 저장소의 내구성과 일관성을 보장하기 위해 신뢰할 수 있는 시스템으로 이어지는 데이터베이스 트랜잭션의 주요 속성을 설명하는 약어이다. ACID 는 원자성(Atomicity), 일관성(Consistency), 격리(Isolation) 및 내구성( Durability)을 나타내며 이러한 속성이 제공하는 것은 다음과 같다.&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;원자성(Atomicity) &lt;/span&gt;: 트랜잭션 내에서 완료된 모든 작업이 모두 완료되거나 모두 실패하도록 한다. 어떤 이유로 인해 변경하려는 변경 사항이 실패하면 전체 작업이 중단되고 변경 사항이 전혀 적용되지 않은 것처럼 동작한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;일관성(Consistency) &lt;/span&gt;: 데이터베이스가 변경되면 유효하고 일관된 상태로 유지되도록 보장한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;격리(Isolation) &lt;/span&gt;: &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;여러 트랜잭션이 간섭 없이 동시에 작동할 수 있다. 이것은 한 트랜잭션 동안 이루어진 모든 중간 상태 변경이 다른 트랜잭션에 표시되지 않도록 함으로써 달성된다.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;내구성(Durability) &lt;/span&gt;: &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;거래가 완료되면 시스템 오류가 발생하더라도 데이터가 손실되지 않도록 보장한다.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이 ACID 속성 중 트랜잭션 경계를 나눌 때 가장 먼저 부딪히는 문제가 원자성이다. 지금부터 이에 대해 자세히 살펴보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;div id=&quot;idm46387401350952&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;마이크로서비스 그리고 분산 트랜잭션&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;데이터베이스를 분리할 때 ACID 스타일 트랜잭션을 계속 사용할 수 있지만 이러한 트랜잭션의 범위와 유용성이 감소한다는 점을 기억하자. &lt;/span&gt;&lt;/p&gt;
&lt;div id=&quot;ch04-acid-one-transaction&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;848&quot; data-origin-height=&quot;500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cVIVZI/btrlT0rqeZg/gx2XoTOQZGR2zzkow0T5y0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cVIVZI/btrlT0rqeZg/gx2XoTOQZGR2zzkow0T5y0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cVIVZI/btrlT0rqeZg/gx2XoTOQZGR2zzkow0T5y0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcVIVZI%2FbtrlT0rqeZg%2Fgx2XoTOQZGR2zzkow0T5y0%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;500&quot; data-origin-width=&quot;848&quot; data-origin-height=&quot;500&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;고객서비스에 CUSTID 0001인 고객이 은행 계좌를 탈퇴하려고 한다. 이때 고객 서비스의 CUST 테이블에 해당 CUSTID를 갖는 Row를 삭제한 후 이체 서비스에 UserID가 0001인 사용자의 정보를 모두 삭제해야 한다고 가정해 보자. 단일 데이터베이스에서는 단일 ACID 데이터베이스 트랜잭션 범위 내에서 이 작업이 수행된다. 이는 두 테이블의 Row가 모두 반영되거나 반영되지 않는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위 동작은 정확히 같은 변경을 하고 있지만, 이제 각 변경은 다른 데이터베이스에서 이루어지고 이것은 고려해야 할 두 개의 트랜잭션이 있음을 의미하며, 각각은 서로 독립적으로 작동하거나 실패할 수 있다는 의미이다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;물론 두 서비스에서 동작하는 CUD 동작을 하나의 트랜잭션으로 묶어 처리할 수 있지만, 궁극적으로 결합도를 낮추는 마이크로서비스를 구현하는 방식과는 맞지 않으며, 이렇게 구현할 경우 굳이 서비스를 구분하지 않고 하나의 서비스로 구성하는 것이 더 낫다고 볼 수 있다. 또한, 어플리케이션 레벨에서 여러 트랜잭션을 묶어 처리하기 때문에 성능 저하 현상이 발생할 수 있다. 오히려 이와 같은 경우 비즈니스 처리 순서를 재정렬하는 것도 하나의 방식이 될 것이다. 그러나 근본적으로 이 작업을 두 개의 개별 데이터베이스 트랜잭션으로 분해함으로써 전체 작업의 보장된 원자성을 상실했다는 사실을 기억해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이러한 원자성 부족은 특히 이전에 이 속성에 의존했던 시스템을 마이그레이션하는 경우 심각한 문제를 일으킬 수 있다. 이 시점에서 사람들은 한 번에 여러 서비스에 대한 변경 사항을 관리할 수 있는 솔루션 또는 개발 방식에 대해 고려하기 시작한다. 이때 고려되는 분산 트랜잭션 관리 방안으로 대표적인 방식인 2Phase Commit과 Saga Pattern에 대해 알아보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;&lt;/div&gt;
&lt;div id=&quot;idm46387401339432&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2Phase Commit&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2Phase Commit 알고리즘(이하 2PC)은 분산 시스템에서 트랜잭션을 변경할 수 있는 기능을 제공하는 방식이다. 이때 2PC제한 사항이 존재한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;2PC는 투표 단계와 커밋 단계라는 두 단계로 나뉜다. 투표 단계에서는 Coordinator가 거래의 일부가 될 모든 대상 서비스에 직접 연결하여 상태 변경이 가능한지 확인 요청한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;[투표 단계]&lt;/span&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: 'Noto Serif KR'; color: #000000;&quot;&gt;1. Coordinator는 고객서비스의 CUSTID 0001 삭제 요청과 이체서비스의 UserID가 0001인 행 삭제 요청을 보낸다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2. 고객서비스와 이체서비스에서 상태 변경이 가능여부에 대해 투표하고 해당 Row에 lock을 잡는다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2-1. 투표 결과 모두 가능하다고 하면 각 서비스에서 상태를 변경하고 다음 단계로 넘어간다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2-2. 하나라도 상태 변경이 불가능하다고 투표하면 트랜잭션은 중단된다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;848&quot; data-origin-height=&quot;615&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kymJb/btrlXCxtnoB/fs17VOX37Fj9X7JTqQY1K0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kymJb/btrlXCxtnoB/fs17VOX37Fj9X7JTqQY1K0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kymJb/btrlXCxtnoB/fs17VOX37Fj9X7JTqQY1K0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkymJb%2FbtrlXCxtnoB%2Ffs17VOX37Fj9X7JTqQY1K0%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;615&quot; data-origin-width=&quot;848&quot; data-origin-height=&quot;615&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;이때 각 서비스가 변경 가능 여부에 대해 투표한 즉시 변경사항이 적용되지 않는다는 점을 기억하자. 투표에 동의한 서비스의 변경이 나중에 이루어질 수 있도록 하기 위해 반영 결과에 대해 Lock을 걸어둔다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;만약 이체 서비스가 투표에 동의하지 않았을 경우, 고객 서비스에 롤백 메시지를 보내야 한다. 모든 서비스가 투표에 동의하면 다음과 같이 Commit 단계로 이동한다. 여기서 변경사항이 실제로 적용되고 관련 Lock이 해제된다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;[Commit 단계]&lt;/span&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: 'Noto Serif KR'; color: #000000;&quot;&gt;1. Coordinator는 Commit 메시지를 각 서비스로 전달한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2. 고객서비스는 CUSTID 0001인 Row를 삭제하고, 이체서비스는 UserID가 0001인 Row를 모두 삭제한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;848&quot; data-origin-height=&quot;615&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WMABv/btrlSkdECvB/BLnwKKkFHcElrWDmAkfkjk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WMABv/btrlSkdECvB/BLnwKKkFHcElrWDmAkfkjk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WMABv/btrlSkdECvB/BLnwKKkFHcElrWDmAkfkjk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWMABv%2FbtrlSkdECvB%2FBLnwKKkFHcElrWDmAkfkjk%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;615&quot; data-origin-width=&quot;848&quot; data-origin-height=&quot;615&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Commit 단계에서는 모든 서비스에 정확히 동시에 적용된다고 보장할 수 없다는 점에 유의해야 한다. Coordinator는 모든 서비스에게 커밋 요청을 보내야 하며 해당 메시지는 다른 시간에 도착하여 처리될 수 있다. 이는 타이밍 이슈로 인해 고객서비스에 대한 변경 사항을 볼 수 있지만 이체서비스에 대한 변경 사항은 아직 반영되지 않을 수 있다는 점이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2PC는 서비스가 증가할수록 시스템의 대기 시간이 길어지며, 이는 응답시간의 증가를 초래한다. 특히 Lock을 잡아야 하는 Row의 범위가 크거나 트랜잭션 기간이 긴 경우 시스템에 엄청난 대기시간을 발생시키게 된다. 이러한 이유로 2PC는 일반적으로 수명이 매우 짧은 작업에만 사용하는 것을 권장한다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;&lt;/div&gt;
&lt;div id=&quot;idm46387401338840&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;결론&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;지금까지 마이크로서비스의 분산 트랜잭션 처리 방식과 2PC에 대해 알아 보았다. 위에 자세히 설명했듯이 마이크로서비스 전체에서 상태 변경을 조정하기 위해 2PC와 같은 분산 트랜잭션을 사용하지 않는 것이 좋다. 2PC는 결국 Coordinator를 기반으로 강력한 결합을 유도하고, 데이터에 직접적인 Lock을 잡고 처리하기 때문에 서비스간 영향도와 궁극적으로 성능에 지대한 영향을 줄 수 있기 때문이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;그렇다면 결국 분산 트랜잭션 환경에서 마이크로서비스의 트랜잭션 관리 방법은 무엇이 있을까?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;두가지를 고민해 볼 수 있을 것이다. 바로 데이터를 분리하지 않는 방법과 Saga Pattern을 적용하는 방법이다. 데이터를 분리하지 않는 방법은 결국 앞서 누누이 이야기 했던 오리진으로의 회귀를 의미한다. 결국 이와 같은 어려움에 직면하여 다시 모놀리스 아키텍처를 선택하게 되는 많은 프로젝트의 사례가 이를 증명하고 있다. 데이터베이스가 보장하는 ACID를 명확히 보장하기 위해서는 단일 데이터베이스로 데이터를 관리하는 것이 가장 좋은 방법이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;그러나 마이크로서비스의 최종 목적지인 데이터의 분리를 위해서는 결과적으로 이와 같은 문제를 감수해야 한다. Coordinator의 관리 방식에서 벗어나는 방법, 서비스간 Lock을 피하는 방법, 대기시간을 줄일 수 있는 방법에 대해 지속적인 고민을 해야 하며, 대안으로 Saga Pattern을 고려할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;다음 포스팅에서는 Saga Pattern을 적용한 분산트랜잭션 관리 방안에 대해 알아보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>③ 클라우드/ⓜ MSA</category>
      <category>MSA</category>
      <category>msa 2pc</category>
      <category>msa 2phase Commit</category>
      <category>msa saga</category>
      <category>msa 사가</category>
      <category>마이크로서비스</category>
      <category>분산트랜잭션</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/734</guid>
      <comments>https://waspro.tistory.com/734#entry734comment</comments>
      <pubDate>Tue, 23 Nov 2021 09:26:41 +0900</pubDate>
    </item>
    <item>
      <title>마이크로서비스 Schema 분리 설계 (테이블 분리, 외래키 참조관계, 조인, 데이터 정합성 보장)</title>
      <link>https://waspro.tistory.com/730</link>
      <description>&lt;div id=&quot;idm46387401567672&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;개요&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;앞선 포스팅에서 마이크로서비스 분산DB 환경에서 고려되어야 할 사항에 대해 살펴보았다. 자세한 내용은 아래 포스팅을 참고하기 바란다.&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: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;마이크로서비스&amp;nbsp;데이터베이스&amp;nbsp;분리&amp;nbsp;설계&amp;nbsp;:&amp;nbsp;&lt;a href=&quot;https://waspro.tistory.com/729&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://waspro.tistory.com/729&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;마이크로서비스&amp;nbsp;분산DB&amp;nbsp;설계&amp;nbsp;(분산DB&amp;nbsp;데이터&amp;nbsp;분할,&amp;nbsp;동기화&amp;nbsp;설계)&amp;nbsp;:&amp;nbsp;&lt;a href=&quot;https://waspro.tistory.com/726&quot;&gt;https://waspro.tistory.com/726&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;마이크로서비스&amp;nbsp;분산DB&amp;nbsp;설계&amp;nbsp;(분산DB&amp;nbsp;조회&amp;nbsp;설계)&amp;nbsp;:&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://waspro.tistory.com/724&quot;&gt;https://waspro.tistory.com/724&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;마이크로서비스 아키텍처의 기준과 DB 분리 :&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://waspro.tistory.com/718&quot;&gt;https://waspro.tistory.com/718&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이번 포스팅에서는 데이터베이스 Schema 분리에 대해 알아보도록 하자. &lt;span&gt;지금까지 데이터베이스 분리 또는 스키마 분리에 대한 다양한 패턴에 대해 알아보았지만, 이를 성공적으로 달성하기 위해서는 데이터베이스 분해와 관련된 몇가지 문제를 해소해야 한다. 이번 포스팅에서는 데이터 분해 패턴을 살펴보고 이러한 패턴이 미칠 수 있는 영향에 대해 알아보도록 하자.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000; font-size: 1.62em; letter-spacing: -1px;&quot;&gt;분할 패턴 1. 테이블 분리&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;둘 이상의 서비스 경계에 걸쳐 분할해야 하는 모놀리스 단일 테이블이 존재할 수 있다.&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt; 아래와 같이 기존 통합DB의 특정 테이블은 CUSTID, PW, CName, TransID, Credit 정보를 모두 포함하고 있었으며, 이를 고객서비스와 이체서비스에 각각 필요로 하는 Column 기준으로 테이블을 분할할 필요가 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;pattern-split-table&quot;&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1613&quot; data-origin-height=&quot;727&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgKM59/btrlQ0MK96d/dAdqeVvqkDeCO9nmyioolk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgKM59/btrlQ0MK96d/dAdqeVvqkDeCO9nmyioolk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgKM59/btrlQ0MK96d/dAdqeVvqkDeCO9nmyioolk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbgKM59%2FbtrlQ0MK96d%2FdAdqeVvqkDeCO9nmyioolk%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;1613&quot; height=&quot;727&quot; data-origin-width=&quot;1613&quot; data-origin-height=&quot;727&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이 패턴은 &lt;span style=&quot;color: #000000;&quot;&gt;Column 별로 데이터 소유권을 쉽게 분리할 수 &lt;/span&gt;있을 것처럼 보인다. 그러나 실제로는 여러 마이크로서비스에서 동일한 Column을 업데이트하는 경우가 발생할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;683&quot; data-origin-height=&quot;707&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bU4zhI/btrlSZflwaO/3HT79kCuYKduHvzOokhMM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bU4zhI/btrlSZflwaO/3HT79kCuYKduHvzOokhMM1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bU4zhI/btrlSZflwaO/3HT79kCuYKduHvzOokhMM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbU4zhI%2FbtrlSZflwaO%2F3HT79kCuYKduHvzOokhMM1%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;683&quot; height=&quot;707&quot; data-origin-width=&quot;683&quot; data-origin-height=&quot;707&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p id=&quot;ch05c-finance-and-customer-using-same-table&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;예를 들어 위와 같이 Status라는 컬럼의 경우 고객서비스와 이체서비스 양쪽에서 모두 업데이트를 관리하는 열이라고 가정 해보자. 고객서비스의 경우 특정 기관을 통해 필수로 확인해야 하는 고객정보(주민번호, 이름, 성별 등)가 변경되었는지 확인하여 업데이트 하며, 이체 서비스의 경우 Status 컬럼 중 Normal인 Row에 대해 계좌번호 유효성 검사 후 정상일 경우 Success로 변경하여 업데이트 한다고 가정하자. 이 경우 고객의 상태는 고객서비스에서 관리되어야 하며, 계좌 관리의 경우 이체서비스에서 관리되어야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;물론 공유 컬럼에 대해 대표 서비스를 지정하고, 대표 서비스의 API를 호출하여 CUD를 요청할 수 있다. 다만, 이와 같은 테이블 분할의 근본적인 문제는 데이터베이스 트랜잭션이 제공하는 안전성을 상실한다는 점이다. 이후 포스팅에서 계속 다루겠지만, 분산DB 환경에서의 트랜잭션 문제와 이를 보장하기 위한 SAGA 패턴에 대해서 이해하고 분산트랜잭션 환경을 설계해야 할 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: -1px;&quot;&gt;분할 패턴 2. Foreign-Key Relationship 활용&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;아래 모놀리스 서비스 내 고객 서비스는 고객 정보를 저장하고, 이체 서비스는 입금, 출금 관련 정보를 저장한다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;pattern-move-foreign-key-to-code&quot;&gt;
&lt;div id=&quot;ch05c-finance-ledger-overview&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1021&quot; data-origin-height=&quot;606&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l4X13/btrlQ1LEkil/7Q4Ta2bti6pRfqIpozKov1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l4X13/btrlQ1LEkil/7Q4Ta2bti6pRfqIpozKov1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l4X13/btrlQ1LEkil/7Q4Ta2bti6pRfqIpozKov1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl4X13%2FbtrlQ1LEkil%2F7Q4Ta2bti6pRfqIpozKov1%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;1021&quot; height=&quot;606&quot; data-origin-width=&quot;1021&quot; data-origin-height=&quot;606&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;매달 말에는 각 사용자 별 입/출금 내역을 정리하여 고객 이메일로 전송하는 배치업무가 있다고 가정해 보자. Trans 테이블은 UserID별로 매달 기간을 기준으로 TrandID와 Credit을 조합하여 리포트를 작성한다. 그리고 '0001님은 21년 11월 한달 동안 10,000원을 입금하고, 1,000원을 이체하여 총 +9,000원 계좌 내 금액이 증가하였습니다.'는 말보다는 'NRSON&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;님은 21년 11월 한달 동안 10,000원을 입금하고, 1,000원을 이체하여 총 +9,000원 계좌 내 금액이 증가하였습니다.&lt;/span&gt;'라고 표현하고 싶을 것이다. 이를 위해, Trans 테이블에서 Cust 테이블로 정보를 결합해야 한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;Schema에서 Foreign-Key RelationShip을 정의하여, Trans 테이블의 행이 Cust 테이블의 행과 관계가 있는 것으로 식별한다. 이러한 관계를 정의함으로써 기본 데이터베이스 엔진은 데이터 일관성을 보장할 수 있다. 즉, Trans 테이블의 행이 Cust 테이블의 행을 참조하는 경우 행이 존재함을 알 수 있다. 즉 Trans 테이블에서 언제든지 Cust 테이블의 CName(Customer Name)을 얻어올 수 있다는 의미이다. 또한 이러한 외래 키 관계를 통해 데이터베이스 엔진은 조인 작업이 최대한 빨리 수행되도록 성능 최적화를 수행할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;물론 이와 같은 패턴은 단일 DB 내의 여러 테이블 간 관계를 정의할 수 있을 경우에만 사용이 가능하다. 따라서 고객서비스와 이체서비스가 독립적인 서비스로 분리되는 시점 특히 분산DB로 구성되는 경우에는 Foreign-Key를 적용할 수 없게 되므로, 다음과 같은 고민을 해야 할 것이다. 먼저, 다른 마이크로서비스의 데이터를 조회하는 방법은 무엇이 있을까? 그리고 데이터 정합성은 어떻게 보장할 것인가?&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;div id=&quot;idm46387401528104&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;데이터 조회 방안 (어플리케이션 조인)&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;월말 정보를 생성할 때 이체 서비스는 먼저 이체 테이블을 쿼리하여 지난 달의 입금, 출금 목록을 추출한다. 이 시점에서 CUSTID와 CName이 필요하다.&lt;/span&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;517&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kDJ0v/btrlKgidmi5/3sgNBwU1qUG6MhKtkPZDG1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kDJ0v/btrlKgidmi5/3sgNBwU1qUG6MhKtkPZDG1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kDJ0v/btrlKgidmi5/3sgNBwU1qUG6MhKtkPZDG1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkDJ0v%2FbtrlKgidmi5%2F3sgNBwU1qUG6MhKtkPZDG1%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;517&quot; data-origin-width=&quot;848&quot; data-origin-height=&quot;517&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1. UserID별로 월 단위 입금, 출금 내역 조회&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2. UserID에 대한 세부 정보 요청&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;3. 세부 정보 Cust 테이블 내 조회&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;4. 조회 결과 리턴&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;5. API Composition&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;논리적으로 조인 작업은 여전히 ​​발생하고 있지만 이제는 데이터베이스가 아니라 이체 서비스(어플리케이션) 내에서 발생한다. JOIN을 서비스 내에서 처리하는 것은 굉장히 비효율적인 방식이라고 볼 수 있다. 데이터베이스가 Join 처리에 특화된 엔지임을 감안해야 하며, 어플리케이션은 이 Join 처리를 위해 비효율적인 루프를 반복적으로 수행해야 할 것이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이 상황에서 해당 트랜잭션의 전체 대기 시간이 급격하게 증가할 것이고, 특히나 대량/대용량 쿼리 결과에 따른 Join 처리에서는 더더욱 그 차이가 급격하게 발생할 것임이 자명하다. 앞서 서두에 밝힌바와 같이 매월 사용자별 입/출금 내역을 이메일로 발신하는 작업은 실시간 성의 처리가 아니므로 크게 문제가 되지 않을 수 있다. 매월 리포트가 9시에 오던 10시에 오던 사실 크게 중요하지 않기 때문이다. 그러나 이것이 빈번한 작업이라면 더 큰 문제가 될 수 있다. 고객 서비스에서 CUSTID를 대량으로 조회할 경우 로컬로 캐싱하여 이러한 지연 시간 증가의 영향을 완화할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;또한, MSA 분산DB 조회 패턴으로 많이 사용되는 CQRS 설계를 적용해 볼 수 있다. CQRS는 비동기 Message Queue 등을 이용하여 공유 테이블에 대해 CQRS DB로 복제하고, 이를 독립된 분산DB를 하나의 DB로 모음으로써 View Join 또는 Table Join할 수 있도록 제공하는 형태를 활용할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;&lt;/div&gt;
&lt;div id=&quot;idm46387401526152&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;데이터 정합성 보장&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;더 까다로운 고려 사항은 고객서비스와 이체서비스가 별도의 서비스이고 별도의 스키마를 사용하면 데이터 불일치가 발생할 수 있다는 점이다. 단일 스키마를 사용하면 이체 테이블에 해당 행에 대한 참조가 있는 경우 고객 테이블의 행을 삭제할 수 없지만, 분리 된 환경에서는 상호간 정합성을 보장하는 것이 무엇보다 까다로운 일이 아닐 수 없다.&lt;/span&gt;&lt;/p&gt;
&lt;div id=&quot;idm46387401507576&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;삭제 전 확인&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;고객 테이블에서 레코드를 제거할 때 이체 서비스에 확인하여 레코드에 대한 참조가 없는지 확인하는 방법이다. 다만 이와 같은 방법은 올바르게 동작한다고 보장하기 어렵다는 문제가 있다. 예를 들어 CUSTID 0001을 삭제하고 싶다고 가정해 보자. 고객 서비스에서 이체 서비스쪽으로 현재 CUSTID를 참조하는 행이 있는지를 묻고 현재 없다는 답변을 받아 삭제를 진행하고자 한다. 이때 삭제하는 것은 문제가 되지 않을까? 이 작업을 수행하는 동안 이체 시스템에서 CUSTID 0001에 대한 새 참조가 생성될 수 있다. 이러한 일이 발생하지 않도록 하려면 삭제가 발생할 때까지 레코드 0001에서 생성되는 새 참조를 중지해야 한다. 즉 해당 Row에 대한 lock이 필요할 수 있고 이는 분산 시스템에서 암시하는 모든 문제가 발생할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;레코드가 이미 사용 중인지 확인하는 또 다른 문제는 고객 서비스에서 사실상 역방향 종속성을 생성한다는 것이다. 결국 자체 서비스 내 데이터의 변화를 위해 다른 서비스를 확인해야 한다. 이것은 소비자가 많을질수록 훨씬 더 결합도가 높아지고, 확인해야 할 대상이 증가하는 것이다. 결국 &lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이 작업이 올바르게 구현되었는지 확인하기 어렵고 이로 인해 발생하는 높은 수준의 서비스 결합 때문에 이 옵션을 고려하지 않을 것을 권고한다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;idm46387401509288&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;삭제 정상 처리&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;고객 서비스에 CUSTID에 대한 정보가 없을 수 있다는 사실을 이체 서비스에서 처리하도록 하는 것이다. 주어진 CUSTID를 조회할 수 없는 경우 월별 이체 정보에 &quot;탈퇴한 사용자입니다.&quot;와 같은 표시가 되도록 하는 것처럼 간단 할 수 있다 .&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이 상황에서 고객 서비스는 이전에 존재했던 CUSTID를 요청할 때 알려줄 수 있다. 예를 들어 &lt;span style=&quot;color: #000000;&quot;&gt;410 GONE &lt;/span&gt;HTTP Response를 응답 코드로 내려주는 것도 좋은 방법이다. 410은 요청된 리소스를 사용할 수 있었지만 더 이상 존재하지 않음을 의미한다. 특히 해당 HTTP Status Code를 활용하여 데이터 불일치 문제를 추적할 때 활용할 수도 있을 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;CUSTIS 항목이 제거될 때 이벤트를 구독하여 이체 서비스에 알릴 수 있다. CUSTID 삭제 이벤트를 선택할 때 현재 삭제된 Customer 정보를 로컬 데이터베이스에 복사할 수 있다. 이 방법은 특히 서비스 경계를 넘어 단계적 삭제와 같은 작업을 수행하기 위해 분산 시스템을 구현하려는 경우 유용할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;idm46387401485816&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;삭제 불가&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;시스템에 불일치가 발생하지 않도록 하는 방법은 고객 서비스의 레코드 삭제를 허용하지 않는 것이다. 기존 시스템에서 항목을 삭제하는 것과 유사한 소프트 삭제 기능을 구현할 수 있다. 예를 들어 상태 열을 사용하여 행을 사용할 수 없는 것으로 표시할 수 있다. 이러한 상황에서 CUSTID는 여전히 이체 서비스에서 호출 할 수 있는 상태가 된다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;그럼 삭제는 어떻게 처리해야 할까? &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;개인적으로, 고객서비스에서 CUSTID 삭제권한을 허용하지 않는 것과 이체 서비스에서 누락된 레코드를 처리할 수 있도록 하는 방법을 적용하여 방어로직을 구현하는 방법 등이 있을 것이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;결론&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;foreign-key relationship을 해소하기 위해 고민하는 것은 위와 같이 중요하지만, 그보다 먼저 데이터의 분할에 대해 다시한번 고민해 볼 필요가 있다. 별도의 서비스로 분할할 경우 데이터 무결성 문제를 고려해야 하며, &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;스키마를 더 크게 가져감으로써 손쉽게 데이터를 관리할 수 있다는 점을 기억해야 할 것이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>③ 클라우드/ⓜ MSA</category>
      <category>MSA</category>
      <category>MSA Join</category>
      <category>MSA 데이터 정합성</category>
      <category>MSA 조인</category>
      <category>마이크로서비스</category>
      <category>분산 아키텍처</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/730</guid>
      <comments>https://waspro.tistory.com/730#entry730comment</comments>
      <pubDate>Mon, 22 Nov 2021 23:34:31 +0900</pubDate>
    </item>
    <item>
      <title>마이크로서비스 데이터베이스 분리 설계</title>
      <link>https://waspro.tistory.com/729</link>
      <description>&lt;div id=&quot;idm46387401703160&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;개요&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;앞선 포스팅에서 마이크로서비스 분산DB 환경에서 데이터 조회 및 데이터 분할/동기화 설계 방법에 대해 살펴보았다. 자세한 내용은 아래 포스팅을 참고하기 바란다.&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: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;마이크로서비스&amp;nbsp;분산DB&amp;nbsp;설계&amp;nbsp;(분산DB&amp;nbsp;데이터&amp;nbsp;분할,&amp;nbsp;동기화&amp;nbsp;설계)&amp;nbsp;:&amp;nbsp;&lt;a href=&quot;https://waspro.tistory.com/726&quot;&gt;https://waspro.tistory.com/726&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;마이크로서비스&amp;nbsp;분산DB&amp;nbsp;설계&amp;nbsp;(분산DB&amp;nbsp;조회&amp;nbsp;설계)&amp;nbsp;:&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://waspro.tistory.com/724&quot;&gt;https://waspro.tistory.com/724&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;마이크로서비스 아키텍처의 기준과 DB 분리 :&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://waspro.tistory.com/718&quot;&gt;https://waspro.tistory.com/718&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이번 포스팅에서는 데이터베이스 분리에 대해 알아보도록 하자. 데이터베이스 분리 방법은 어플리케이션 기준 분리와 데이터베이스 기준 분리를 고려할 수 있다. 두방식 모두 비즈니스의 설계 방향에 따라 데이터를 처리하는 방식이 달라질 수 있으므로, 그 영향도를 파악하고 점진적인 전환을 진행하는 것이 바람직하다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;물리/논리 데이터베이스&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;데이버베이스를 분리해 나가는 방법에 대해 살펴보기 전에 논리적 분리와 물리적 분리가 어떤 관련이 있는지 먼저 알아보도록 하자.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;먼저 살펴볼 내용은 바로 논리적 분리 구조이다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;우리가 이야기 하는 대부분의 데이터베이스 분리는 논리적 분리를 의미한다. 단일 데이터베이스는 논리적으로 분리된 둘 이상의 스키마를 완벽하게 호스팅할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div id=&quot;ch05c-two-services-one-database-engine&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1066&quot; data-origin-height=&quot;752&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmMPoM/btrlLxdvPKp/jR5KyXXNYNgcblzEr7hSaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmMPoM/btrlLxdvPKp/jR5KyXXNYNgcblzEr7hSaK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmMPoM/btrlLxdvPKp/jR5KyXXNYNgcblzEr7hSaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbmMPoM%2FbtrlLxdvPKp%2FjR5KyXXNYNgcblzEr7hSaK%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;1066&quot; height=&quot;752&quot; data-origin-width=&quot;1066&quot; data-origin-height=&quot;752&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;다음으로 물리적 분리 구조이다. 아래와 같이 데이터베이스 엔진에 각 논리적 스키마를 가질 수 있다.&lt;/span&gt;&lt;/div&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1254&quot; data-origin-height=&quot;749&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bf4tWR/btrlQ0FXcky/loh1DKsngDOZrOFxI1jtz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bf4tWR/btrlQ0FXcky/loh1DKsngDOZrOFxI1jtz0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bf4tWR/btrlQ0FXcky/loh1DKsngDOZrOFxI1jtz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbf4tWR%2FbtrlQ0FXcky%2Floh1DKsngDOZrOFxI1jtz0%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;1254&quot; height=&quot;749&quot; data-origin-width=&quot;1254&quot; data-origin-height=&quot;749&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 논리적/물리적 분리를 구분하는 이유는 무엇일까?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1) 리소스 독립 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;기본적으로 논리적 분리와 물리적 분리는 서로 다른 목표를 달성한다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;논리적 분리는 엔진에 대한 독립적인 변경이 어렵고 정보 은익을 허용하는 반면, 물리적 분리는 잠재적으로 시스템 견고성을 개선하고 리소스 경합을 제거하여 처리량이나 지연 시간을 개선할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;2) 장애 독립 : 논리적으로 데이터베이스 스키마를 분리할 경우 단일 장애 지점이 발생할 수 있다. 데이터베이스 엔진이 중단되면 두 서비스 모두에 영향을 미친다. 이를 해소하기 위한 방법으로 다중 데이터베이스 모드, Warm Failover 등과 같은 단&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;일 장애 지점을 방지하기 위한 메커니즘이 있으며, 실제로 조직에 복원력이 뛰어난 데이터베이스 클러스터를 만들기 위해 상당한 노력을 기울일 것이다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;물론 단순히 물리적으로 독립된 데이터베이스를 구성하는 것이 좋은 것은 아니다. 여러 이유가 있겠지만, 물리적으로 독립된 DB를 사용할 경우 지속적으로 증가하는 비용, 유지보수를 감당해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;그럼 본격적으로 데이터베이스 분리에 대해 알아보도록 하자. 데이터의 분리를 위한 과정은 크게&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: -1px;&quot;&gt;데이터베이스의 분리와 어플리케이션의 분리로 구분해 볼 수 있다.&lt;span&gt;&amp;nbsp; 마이크로서비스는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&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: 'Noto Serif KR'; color: #000000;&quot;&gt;먼저 데이터베이스를 분리한 다음 코드를 분할합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;먼저 코드를 분리한 다음 데이터베이스를 분할합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;한 번에 둘을 나눕니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;이제 이러한 옵션과 사용하는 방식에 따라 도움이 될 수 있는 몇 가지 패턴을 살펴보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;&lt;/div&gt;
&lt;div id=&quot;idm46387401663336&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; font-size: 1.62em; letter-spacing: -1px;&quot;&gt;데이터베이스 분리 우선&lt;/span&gt;&lt;/p&gt;
&lt;div id=&quot;idm46387401658200&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;비즈니스 단위 별 별도의 스키마를 사용하면 단일 작업을 수행하기 위한 데이터베이스 호출 수를 잠재적으로 늘릴 수 있다. 이전에는 단일 SELECT 문에서 원하는 모든 데이터를 가질 수 있었지만 이제는 두 위치에서 데이터를 다시 가져와 메모리에 결합해야 할 수 있다. 또한 두 개의 스키마로 이동할 때 트랜잭션 무결성이 깨져 결국 애플리케이션에 상당한 영향을 미칠 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;어플리케이션은 그대로 유지한 채 데이터베이스만 분리할 경우 소비자에게 영향을 미치지 않고 변경 사항을 되돌리거나 복원할 수 있다. DB 분리가 의미가 있다고 판단되면 애플리케이션 코드를 두 개의 서비스로 분할하는 것에 대해 생각할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;938&quot; data-origin-height=&quot;388&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nSpfw/btrlSZ7vc9I/Y06yCgS2CKXsAAqTMzdKRK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nSpfw/btrlSZ7vc9I/Y06yCgS2CKXsAAqTMzdKRK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nSpfw/btrlSZ7vc9I/Y06yCgS2CKXsAAqTMzdKRK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnSpfw%2FbtrlSZ7vc9I%2FY06yCgS2CKXsAAqTMzdKRK%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;938&quot; height=&quot;388&quot; data-origin-width=&quot;938&quot; data-origin-height=&quot;388&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p id=&quot;ch05c-one-monolith-two-schemas&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;다만, 이 접근 방식이 단기간에 많은 이익을 얻을 가능성은 낮다. 데이터의 분리에 따라 모놀리스 서비스가 갖는 문제점을 진단하고 개선할 수 있다는 장점은 있지만, 그 기간이 길어질 수 있기 때문에 잠재적인 성능 또는 데이터 일관성 문제가 특히 우려되는 경우 이와 같은 분리 방식을 권고한다. 또한 모놀리스 자체가 상용 소프트웨어와 같은 블랙박스 시스템인 경우 이 옵션을 사용할 수 없다는 점도 고려해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;div id=&quot;pattern-repo-per-bounded-context&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;분리 패턴 1. Bounded Context 단위의 리포지토리&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;일반적인 방법은 Hibernate와 같은 프레임워크에 의해 백업되는 저장소 계층을 가지고 코드를 데이터베이스에 바인딩하여 객체나 데이터 구조를 데이터베이스와 쉽게 매핑할 수 있도록 하는 것이다. 우리의 모든 데이터 액세스 문제에 대해 단일 저장소 계층을 갖는 대신, Bounded Context의 경계를 따라 저장소를 세분화한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;Bounded Context란 DDD 모델의 Context 즉 모델 간의 경계를 Bounded Context라고 한다. 하나의 도메인 안에는 여러 Context가 존재할 수도 있고, 여러 도메인에 걸처 하나의 Context가 생성될 수도 있다. 이와 같은 경계는 데이터를 분리하는 기준이 되며, 나아가 마이크로서비스를 구분하는 기준이 되기도 한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;주어진 컨텍스트에 대해 코드 내부에 데이터베이스 매핑 코드를 같은 위치에 배치하면 어떤 코드가 데이터베이스의 어떤 부분을 사용하는지 이해하는 데 도움이 될 수 있다. 예를 들어, Hibernate는 Bounded Context 당 매핑 파일을 사용하는 경우 이 문제를 명확하게 할 수 있다. 따라서 우리는 Bounded Context가 스키마의 어떤 테이블에 접근하는지를 볼 수 있다. 이는 향후 데이터베이스 분리의 일부로 어떤 테이블이 이동해야 하는지 이해하는 데 큰 도움이 될 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1424&quot; data-origin-height=&quot;806&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JZJ8p/btrlU6EOQmT/uSRiPpixpv6FTRKUtKJdpk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JZJ8p/btrlU6EOQmT/uSRiPpixpv6FTRKUtKJdpk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JZJ8p/btrlU6EOQmT/uSRiPpixpv6FTRKUtKJdpk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJZJ8p%2FbtrlU6EOQmT%2FuSRiPpixpv6FTRKUtKJdpk%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;1424&quot; height=&quot;806&quot; data-origin-width=&quot;1424&quot; data-origin-height=&quot;806&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 각각의 Context 별 Repository를 분리하면 데이터의 분리 구조로써 활용될 수 있을 것이다. 물론&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;데이터베이스 수준의 Constraint를 하나하나 따져봐야하겠지만, 앞서 이야기한 바와 같이 Repository를 구분하는 것부터 결합도를 분리하는 시작점이 될 수 있을 것이다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;이 모든 것은 나중에 서비스 경계가 될 테이블 간의 결합을 이해하는 데 도움이 될 것이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div id=&quot;idm46387401632664&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이 패턴은 DDD 개념에 따라 리포지토리 계층을 분류하면 데이터베이스뿐만 아니라 코드 자체에서도 마이크로서비스 용 Context를 분리하는데 많은 도움이 될 것이며, 대부분의 경우에 적용하기 용이한 패턴이다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;idm46387401624056&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;분리 패턴 2. Bounded Context 단위의 데이터베이스&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;애플리케이션 관점에서 데이터 액세스를 명확하게 분리했으면 이 접근 방식을 스키마에 계속 적용하는 것이 좋다. 마이크로서비스의 독립적인 배포는 자체 데이터를 소유해야 가능하다. 어플리케이션 코드를 분리하기 전에 식별된 Bounded Context를 중심으로 데이터베이스를 명확하게 분리하여 이 분해를 시작할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1424&quot; data-origin-height=&quot;918&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Fi1f4/btrlQ065xvN/mXTiUy5VTcqHm6MdlMmEg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Fi1f4/btrlQ065xvN/mXTiUy5VTcqHm6MdlMmEg1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Fi1f4/btrlQ065xvN/mXTiUy5VTcqHm6MdlMmEg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFi1f4%2FbtrlQ065xvN%2FmXTiUy5VTcqHm6MdlMmEg1%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;1424&quot; height=&quot;918&quot; data-origin-width=&quot;1424&quot; data-origin-height=&quot;918&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p id=&quot;ch05c-schema-per-bounded-context&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;각 Bounded Context에는 자체 데이터베이스 Schema가 존재한다. 나중에 마이크로서비스로 분리해야 하는 경우 손쉽게 전환해 나갈 수 있는 형태를 마련하게 된다. 이는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;단일 데이터베이스 Schema 보다 더 많은 작업이 필요하지만 마이크로서비스로 이동하는 것과 관련하여 결합도를 낮추고, 사전에 이슈 사항들을 점검할 수 있는 기틀을 마련하게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;div id=&quot;idm46387401617272&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이와 같은 패턴은 신규 프로젝트를 구성할때 항상 권장하는 패턴이다. DDD를 통해 마이크로서비스를 설계하는 것과 비교할 때 사실 이 패턴은 굉장히 단순하고, 실패의 가능성을 내재하고 있다. 다만, DDD에 대해 충분한 내재화가 되지 않은 상황에서 무턱대고 설계에 뛰어들기에는 대부분의 기업에서 안정적인 도메인 Bounded Context를 식별할 만큼 충분히 성숙하지 않다. 이때 이 패턴은 좋은 중간 지점이 될 수 있다. 미래에 서비스 분리가 발생할 수 있다고 생각되는 곳에 스키마 분리를 유지하고, 마이크로서비스 설계에 대응하거나, 또는 마이크로서비스로 변화하지 않더라도 시스템의 복잡성을 줄이면서 시스템 개선 포인트를 명확히 잡아 나가는데 도움이 될 수 있는 패턴이다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;idm46387401619688&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;코드 분리 우선&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;아마도 많은 프로젝트에서 데이터베이스 분리 이전에 코드를 먼저 분리한다. 전통적인 개발 방법론 중 하나인 FDD 중심의 기능 분해도를 작성하고, 이를 기준으로 설계를 진행하기 때문에 더더욱 그러한 경향이 있다. 대체로 프로젝트에서는 서비스 설계 &amp;gt; 인터페이스 설계 &amp;gt; 테이블 설계 순으로 진행하게 되며, 이때 데이터베이스의 분리는 가장 마지막에 고려하게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;980&quot; data-origin-height=&quot;388&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uyvKG/btrlSYU1xsf/k4LD0XAdSk7JxhvUcSKjmk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uyvKG/btrlSYU1xsf/k4LD0XAdSk7JxhvUcSKjmk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uyvKG/btrlSYU1xsf/k4LD0XAdSk7JxhvUcSKjmk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuyvKG%2FbtrlSYU1xsf%2Fk4LD0XAdSk7JxhvUcSKjmk%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;980&quot; height=&quot;388&quot; data-origin-width=&quot;980&quot; data-origin-height=&quot;388&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;애플리케이션 계층을 분할하면 새 서비스에 필요한 데이터를 훨씬 쉽게 이해할 수 있다. 또한 독립적으로 배포할 수 있는 코드 아티팩트를 더 일찍 확보할 수 있는 이점을 얻을 수 있다. 이 패턴은 영향도를 최소화 하여 분리해 나갈 수 있지만, 결국 데이터의 분리를 이뤄내지 못하고 중단되는 경우도 발생한다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div id=&quot;ch05c-monolith-as-data-access-layer&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;분리 패턴 1. 모놀리스 API Server&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;모놀리스 데이터에 직접 액세스하는 대신 모놀리스 서비스에 API를 생성하는 형태를 고려해 볼 수 있다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;아래와 같이 고객서비스는 고객 정보에 액세스할 수 있도록 모놀리스 서비스에 API를 만든다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;655&quot; data-origin-height=&quot;373&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TRsqF/btrlSYnbVWo/Zr0DlAvOBLs1OSRhyXzRP0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TRsqF/btrlSYnbVWo/Zr0DlAvOBLs1OSRhyXzRP0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TRsqF/btrlSYnbVWo/Zr0DlAvOBLs1OSRhyXzRP0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTRsqF%2FbtrlSYnbVWo%2FZr0DlAvOBLs1OSRhyXzRP0%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;655&quot; height=&quot;373&quot; data-origin-width=&quot;655&quot; data-origin-height=&quot;373&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;이와 같은 패턴은 사실 프로젝트에서 선호하는 패턴은 아니다. 모놀리스 어플리케이션 서비스는 조만간 사라질 서비스라는 인식으로 부터 모놀리스에 살을 붙이는 것은 불필요한 개발이라고 생각하기 때문일 것이다. 그러나 여기서 얻을 수 있는 이점은 분명하다. 데이터 분해 문제를 해결할 필요가 없고 정보를 숨겨야 하므로 새로운 서비스를 모노리스와 분리하여 보다 쉽게 유지할 수 있다. 만약 모놀리스의 데이터가 그대로 유지될 수 있다면 복잡한 분산데이터 처리를 적용하기에 앞서 이와 같은 형태를 검토해 보기를 추천한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;824&quot; data-origin-height=&quot;427&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IhLvc/btrlUNZHF2q/ikijOb94xFVLOfJkhT1rz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IhLvc/btrlUNZHF2q/ikijOb94xFVLOfJkhT1rz0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IhLvc/btrlUNZHF2q/ikijOb94xFVLOfJkhT1rz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIhLvc%2FbtrlUNZHF2q%2FikijOb94xFVLOfJkhT1rz0%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;824&quot; height=&quot;427&quot; data-origin-width=&quot;824&quot; data-origin-height=&quot;427&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;초기 모놀리스가 제공하던 계좌API는 결국 계좌서비스로 분리되어 마이크로서비스 형태로 변형되어 갈 것이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;894&quot; data-origin-height=&quot;589&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RAlm3/btrlSvZ1YeH/6av4tM7pnwCppyqXJz262K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RAlm3/btrlSvZ1YeH/6av4tM7pnwCppyqXJz262K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RAlm3/btrlSvZ1YeH/6av4tM7pnwCppyqXJz262K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRAlm3%2FbtrlSvZ1YeH%2F6av4tM7pnwCppyqXJz262K%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;894&quot; height=&quot;589&quot; data-origin-width=&quot;894&quot; data-origin-height=&quot;589&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;이 패턴은 데이터를 관리하는 코드가 여전히 모놀리스 어플리케이션에 있을 때 가장 잘 작동한다. &lt;/span&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;물론 반드시 데이터를 마이크로서비스 내에 소유해야 하는 경우 모놀리스 데이터베이스와 마이크로서비스 분산DB 간의 중복 데이터를 저장하는 것보다 이 패턴을 생략하고 데이터를 분할하는 것을 고려해야 한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;pattern-multi-schema-storage&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;분리 패턴 2. 다중 스키마 스토리지&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;모놀리스 서비스와 고객 서비스 간 공존하는 데이터에 대해 항상 모든 데이터가 동기화 되어야 하는 것은 아니다. 모놀리스 서비스에서 사용하는 데이터 또는 타 서비스에서 사용하는 데이터에 대해 동기화 하되 신규로 서비스 되는 데이터에 대해서는 고객 서비스에 저장하는 방식이 적합하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;예를 들어 아래와 같이 고객 서비스의 핵심 데이터는 CUSTID, PW, OrgID로 모놀리스, 고객서비스 모두에 저장된다. EventID의 경우 신규로 추가된 서비스로 고객서비스에 저장된다.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1037&quot; data-origin-height=&quot;617&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vgZ9s/btrlQZUCV4s/zxjIOKrjyTirM97w8SIfA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vgZ9s/btrlQZUCV4s/zxjIOKrjyTirM97w8SIfA1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vgZ9s/btrlQZUCV4s/zxjIOKrjyTirM97w8SIfA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvgZ9s%2FbtrlQZUCV4s%2FzxjIOKrjyTirM97w8SIfA1%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;1037&quot; height=&quot;617&quot; data-origin-width=&quot;1037&quot; data-origin-height=&quot;617&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p id=&quot;ch05c-invoice-service-two-schemas&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;좀 더 확장해서 생각해 보자면, 모놀리스 서비스에 기존 데이터를 유지하고 고객서비스에 신규 추가된 Column을 추가한 후 이를 Key를 통해 관리할 수 있다. 아래와 같이 CUSTID를 기준으로 데이터가 관리되어 질 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1037&quot; data-origin-height=&quot;617&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/P0Gbt/btrlTilqIq0/tzVdLSTEsCAeMKgDPmBtOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/P0Gbt/btrlTilqIq0/tzVdLSTEsCAeMKgDPmBtOk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/P0Gbt/btrlTilqIq0/tzVdLSTEsCAeMKgDPmBtOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FP0Gbt%2FbtrlTilqIq0%2FtzVdLSTEsCAeMKgDPmBtOk%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;1037&quot; height=&quot;617&quot; data-origin-width=&quot;1037&quot; data-origin-height=&quot;617&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;이 예에서 우리는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Foreign-Key&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;관계가 스키마 경계에 효과적으로 걸쳐 있을 때 어떤 일이 일어나는지 고려해야 한다. 이는 다음 포스팅에서 더 자세히 살펴보도록 하자.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div id=&quot;idm46387401581144&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이 패턴은 마이크로서비스에 새로운 기능을 추가할 때 적용하기 용이하다. 모놀리스가 필요로 하는 데이터가 아니므로 고객서비스에만 해당 데이터를 유지하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;idm46387401580072&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;데이터베이스와 코드를 함께 분리&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;앞선 두 단계를 하나의 큰 단계로 코드와 데이터베이스를 한번에 분리할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;980&quot; data-origin-height=&quot;394&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EbPmQ/btrlS0FvqZB/5aTKLyGYyYr5bjGqTm1Jmk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EbPmQ/btrlS0FvqZB/5aTKLyGYyYr5bjGqTm1Jmk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EbPmQ/btrlS0FvqZB/5aTKLyGYyYr5bjGqTm1Jmk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEbPmQ%2FbtrlS0FvqZB%2F5aTKLyGYyYr5bjGqTm1Jmk%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;980&quot; height=&quot;394&quot; data-origin-width=&quot;980&quot; data-origin-height=&quot;394&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;다만, 이와 같은 접근이 단계를 뛰어 넘어 빠르게 수행될 것이라 판단하는 경우가 있지만, 대체로 더 오래 걸리는 작업이다. 특히 리스크를 감안할 때 충분한 검증 없이 빅뱅 방식의 전환이 될 수 있어 가능하면 이와 같은 전환은 배제하는 것이 바람직하며 대신 스키마 또는 애플리케이션 계층을 먼저 분할하는 것이 좋다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;결론&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;자 그럼 데이터베이스와 어플리케이션 중 어떤 것 부터 분리해 나가는 것이 좋은가에 대한 답변이 필요하다. 프로젝트에 따라 다르다는 답변을 하는 경우가 대부분이겠지만, 이 글을 읽은 독자들께서 원하는 답변은 아닐 수 있기에 개인적인 주관이 들어간 기준을 세워보도록 하겠다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;모놀리스를 변경할 수 있고 성능이나 데이터 일관성에 대한 잠재적인 영향이 우려되는 경우 먼저 스키마를 분리하는 방법을 권고한다. 그렇지 않으면 코드를 먼저 분리하고 데이터 소유권에 미치는 영향을 파악해 나가는 것이 좋다. 물론 이것이 모든 상황을 결정할 수 있는 절대적인 기준은 아니며, 상황에 맞게 선택하고 수행해 나가는 것은 당연한 이치일 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;이번 포스팅에서는 데이터베이스와 코드의 분리 기준에 대해 살펴보았다. 다음 포스팅에서는 데이터베이스의 실질적인 분리 방안인 Schema 분리에 대해 알아보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>③ 클라우드/ⓜ MSA</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/729</guid>
      <comments>https://waspro.tistory.com/729#entry729comment</comments>
      <pubDate>Mon, 22 Nov 2021 10:37:37 +0900</pubDate>
    </item>
    <item>
      <title>마이크로서비스 분산DB 데이터 분할, 동기화 설계</title>
      <link>https://waspro.tistory.com/726</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;개요&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;앞선 포스팅에서 마이크로서비스 분산DB 환경에서 데이터 조회를 위한 방안에 대해 살펴보았다. 자세한 내용은 아래 포스팅을 참고하기 바란다.&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: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;마이크로서비스&amp;nbsp;분산DB&amp;nbsp;설계&amp;nbsp;(분산DB&amp;nbsp;조회&amp;nbsp;설계)&amp;nbsp;:&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://waspro.tistory.com/724&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://waspro.tistory.com/724&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;마이크로서비스 아키텍처의 기준과 DB 분리 :&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://waspro.tistory.com/718&quot;&gt;https://waspro.tistory.com/718&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;앞서 살펴본 분산 DB 조회 설계에서는 이미 분할된 데이터에 대한 접근을 어떻게 효과적으로 할 것이냐에 포커싱을 맞추었다면, 이번 포스팅에서는 어떻게 데이터를 모놀리식 DB에서 분할할 것인냐에 대해 알아보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;중요한 포인트는 바로 특정 데이터가 어느 분산 DB에 존재하는 것이 좋은지에 대한 결정을 내리는 일이다. 모놀리스에서 서비스를 분리할 때 일부 데이터는 함께 제공되어야 하고 일부는 그대로 있어야 한다. 또한 일부는 타 마이크로서비스로 이전될 수도 있다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;분산 데이터 분할(데이터 소유권) 설계&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;앞서 조회 설계 패턴에서도 이야기 했듯 데이터베이스를 설계하는 핵심 포인트는 바로 서비스간 호출 빈도를 줄일 수 있는 데이터 모델링이라고 할 수 있다. 각 서비스가 독립적으로 이용하는 데이터는 해당 서비스 전용 분산 DB로 마이그레이션하고, 공통으로 사용하는 DB는 공통 DB 또는 이와 상응하는 저장소에 저장하고 공유한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;아래와 같은 경우 고객데이터를 모놀리스에서 고객DB로 으로 이동한다. 이때, 고객DB에 저장된 고객관련 테이블에 접근하고자 할 경우 모놀리스 어플리케이션은 물론 타 마이크로서비스는 고객 서비스의 API를 호출하여 데이터를 읽거나 변경 사항을 반영하도록 해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;div id=&quot;pattern-database-as-a-service-interface&quot;&gt;
&lt;div id=&quot;idm46387401915384&quot;&gt;
&lt;div&gt;
&lt;div id=&quot;idm46387401942136&quot;&gt;
&lt;div id=&quot;change-data-ownership&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1285&quot; data-origin-height=&quot;725&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VAWXS/btrlIecCHyM/jsf83K7AvKkK4DG5uT7L51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VAWXS/btrlIecCHyM/jsf83K7AvKkK4DG5uT7L51/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VAWXS/btrlIecCHyM/jsf83K7AvKkK4DG5uT7L51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVAWXS%2FbtrlIecCHyM%2Fjsf83K7AvKkK4DG5uT7L51%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;1285&quot; height=&quot;725&quot; data-origin-width=&quot;1285&quot; data-origin-height=&quot;725&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;굉장히 간단한 것처럼 설명했지만, 사실 고객테이블을 모놀리식 DB에서 분리해 내는 것에는 복잡한 문제들이 있다. 먼저 Foreign-key constraints, 분산트랜잭션 환경에 따른 데이터 정합성 관리 문제, 보상처리 설계 등 굵직굵직한 이슈들을 해소해야 테이블을 분할할 수 있다. &lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이에 대해서는 5, 6, 7회차 포스팅에서 상세히 다뤄볼 예정이니 이를 참하고 하기 바라며, &lt;/span&gt;설계 요점만 짚어 보고 넘어가도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;데이터 동기화&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;다음으로 데이터베이스가 분할 되었을 경우 데이터 동기화가 필요한 상황들이 발생하게 된다. 예를 들어 병행운영&lt;span style=&quot;color: #000000;&quot;&gt;(as-is app과 to-be app간의 운영기간 중첩)&lt;/span&gt;을 해야 한다던지, 배치를 위한 조회용도로 데이터를 복제해야 한다던지, Join을 위한 분산DB간 조회를 해야 한다던지 등 다양한 케이스에서 데이터 동기화 요건은 발생할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;애플리케이션 레벨 데이터 동기화&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;먼저 살펴볼 동기화 패턴은 애플리케이션 레벨에서의 데이터 동기화이다. 애플리케이션 레벨에서 두 데이터소스 간의 동기화를 수행 직접 수행하는 방식이다. 데이터베이스의 마이그레이션 요건은 여러 형태로 존재한다. DBMS가 갖고 있는 특징을 적용하기 위함이라던지, MSA 환경에 분산DB를 적용하기 위해 오픈DB로의 전환을 목적으로 한다던지, 라이선스 비용을 줄이기 위함이라던지, OGG와 같은 DR 구성 요건으로 인해 전환한다던지, 그 목적에 따라 DB를 구성하고, 데이터를 전환하는 과정이 발생하게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;데이터 대량 동기화&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;데이터 동기화를 위해 제일 먼저 수행해야 하는 것은 Source 데이터베이스에서 Target 데이터베이스로의 데이터 일괄 복제하는 것이다. 복제가 진행되는 동안 기존 시스템에 반영된 데이터로 인해 복제 완료된 Target 데이터베이스와 데이터 정합성 문제가 발생할 수 있다. 복제가 완료되면 이후 변경사항에 대해 CDC 도구를 통해 동기화할 수 있으며, 동기화가 완료되는 시점에 Target 데이터베이스를 어플리케이션 서비스에 배포할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1929&quot; data-origin-height=&quot;653&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WiK1q/btrlGJdgvel/ukM0k4jYmLCISsdPa8Iti0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WiK1q/btrlGJdgvel/ukM0k4jYmLCISsdPa8Iti0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WiK1q/btrlGJdgvel/ukM0k4jYmLCISsdPa8Iti0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWiK1q%2FbtrlGJdgvel%2FukM0k4jYmLCISsdPa8Iti0%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;1929&quot; height=&quot;653&quot; data-origin-width=&quot;1929&quot; data-origin-height=&quot;653&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;두 데이터베이스가 동기화되어 모든 데이터를 기록하는 새 버전의 애플리케이션이 배포되었다. 이후에도 두 데이터베이스를 함께 사용하고자 할 경우 동기화는 지속적으로 이루어져야 한다. 여러 형태의 동기화 패턴에 대해 알아보자.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;양방향 쓰기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;먼저 양방향 쓰기이다. 양방향 쓰기는 통합DB, New 고객DB 양쪽에 동일한 CUD를 발생시키는 방식이다.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;545&quot; data-origin-height=&quot;374&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b81LfC/btrlFbagcGg/bRM0vWG8r7WkjCpBHhGO41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b81LfC/btrlFbagcGg/bRM0vWG8r7WkjCpBHhGO41/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b81LfC/btrlFbagcGg/bRM0vWG8r7WkjCpBHhGO41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb81LfC%2FbtrlFbagcGg%2FbRM0vWG8r7WkjCpBHhGO41%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;545&quot; height=&quot;374&quot; data-origin-width=&quot;545&quot; data-origin-height=&quot;374&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;양쪽에 동일한 CUD가 발생되기 때문에 정합성 유지가 간편하지만, 네트워크 비용이 두배로 발생한다는 단점이 있다. 또한, DB별 성능차로 인한 타이밍 이슈를 해소하기 위해 R(Read)의 경우 양쪽 DB 중 한쪽을 선택하는 것이 좋다. 나머지 DB는 장애 시 FailOver 용도로 활용할 수 있도록 Read 권한을 제어한다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;단일 DB 쓰기 &lt;br /&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;단방향 쓰기는 양쪽 DB간 데이터 동기화를 위한 별도의 수단이 필요하다는 점이 추가되지만, 일반적으로 가장 선호하는 방식이다. 단방향 쓰기를 통해 트랜잭션 실패에 유연하게 대응할 수 있으며, Read를 확장하므로써 높은 성능을 뽑아낼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;div id=&quot;idm46387401795176&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;546&quot; data-origin-height=&quot;374&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bw7Zyn/btrlFLh4Spp/visE4qJCruI1NvaVrDFChK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bw7Zyn/btrlFLh4Spp/visE4qJCruI1NvaVrDFChK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bw7Zyn/btrlFLh4Spp/visE4qJCruI1NvaVrDFChK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbw7Zyn%2FbtrlFLh4Spp%2FvisE4qJCruI1NvaVrDFChK%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;546&quot; height=&quot;374&quot; data-origin-width=&quot;546&quot; data-origin-height=&quot;374&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;FullMesh 방식&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;Read/Write를 모놀리스와 마이크로서비스가 모두 데이터에 액세스하는 방식이다.&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt; 이 패턴이 작동하려면 모놀리스와 마이크로서비스 모두 데이터베이스 전체에서 적절한 동기화를 보장해야 한다. 둘 중 하나가 잘못되면 문제가 발생할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;idm46387401788920&quot;&gt;
&lt;div id=&quot;ch05c-two-invoice-schemas-two-services&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;636&quot; data-origin-height=&quot;374&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bj8wkK/btrlOWI9GeM/pz1Iv0XaAOmKHt9gT1kwCK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bj8wkK/btrlOWI9GeM/pz1Iv0XaAOmKHt9gT1kwCK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bj8wkK/btrlOWI9GeM/pz1Iv0XaAOmKHt9gT1kwCK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbj8wkK%2FbtrlOWI9GeM%2Fpz1Iv0XaAOmKHt9gT1kwCK%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;636&quot; height=&quot;374&quot; data-origin-width=&quot;636&quot; data-origin-height=&quot;374&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;결론&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이번 포스팅에서는 데이터 분할 설계 및 데이터 동기화 패턴에 대해 알아 보았다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;데이터 분할 설계의 경우 테이블을 쪼개기 위한 선행되어야 하는 많은 작업들이 존재한다. 이에 대해서는 차차 알아보기로 하고, 분할된 데이터에 접근하기 위해 모놀리스 서비스는 직접 데이터에 접근하는 것이 아닌 API를 통해 접근하는 것이 보다 결합도를 낮추는 설계 패턴이라 할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;데이터 동기화의 경우 데이터 마이그레이션 과정을 포함한 분할 된 데이터 간 상호 유지하는 방법에 대해 알아 보았다. 가능한 데이터 정합성을 위해 Read는 하나의 DB에서 접근하도록 구성하는 것이 효과적이며, CDC 도구를 적극 활용하는 것을 권장한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;사실 이번 포스팅의 목적은 설계에 있지는 않다. 설계에 목적이 있었다면, 보다 다양한 패턴을 다뤄보고 하겠지만, 이 포스팅이 원하는 바는 바로 분산 트랜잭션과 분산 DB 환경에 대한 마이크로서비스 아키텍처의 대응 방안을 마련해 보자는 취지이다. 이로 인해 앞 3~4개의 포스팅은 개념적인 부분들만 짚어 보고 넘어가는 경향이 있을 수 있으나, 뒷부분에서 논의할 핵심 패턴의 기반이 되는 정보라는 점 이야기 하고 이번 포스팅을 마무리하고자 한다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>③ 클라우드/ⓜ MSA</category>
      <category>CDC</category>
      <category>MSA</category>
      <category>MSA 데이터 동기화</category>
      <category>MSA 데이터 분할</category>
      <category>OGG</category>
      <category>마이크로서비스</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/726</guid>
      <comments>https://waspro.tistory.com/726#entry726comment</comments>
      <pubDate>Sun, 21 Nov 2021 15:12:53 +0900</pubDate>
    </item>
    <item>
      <title>마이크로서비스 분산DB 조회 설계</title>
      <link>https://waspro.tistory.com/724</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;개요&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;앞선 포스팅에서 마이크로서비스 환경의 데이터베이스 분리 기준에 대해 알아보았다.&amp;nbsp;모놀리식 어플리케이션을 마이크로서비스 아키텍처로 전환하기 위해서는 단일DB를 분산DB 형태로 분리해 나가야 한다. 물론 한번에 모든 DB를 서비스 별로 쪼개는 것은 리스크를 확대시킬 수 있다. 서비스간 결합도가 낮은 마이크로서비스로부터 하나씩 DB를 분리해 나가면서 점진적 결합도를 낮추는 것이 무엇보다 중요하다는 점을 기억하고 다음 포스팅을 읽어주었으면 한다.&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: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;마이크로서비스 아키텍처의 기준과 DB 분리 :&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://waspro.tistory.com/718&quot;&gt;https://waspro.tistory.com/718&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;데이터베이스의 분리는 단순하게 DB의 스키마를 나누는데에 그치지 않는다. 하나의 프로젝트에서 분석/설계라는 과정을 거쳐 어플리케이션과 테이블, 인터페이스를 정의하고 이를 개발에 적용하는데, 특히 테이블 설계는 데이터를 정의하는 측면에서 어플리케이션과 인터페이스가 정의된 후 가장 후순으로 진행하게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;어플리케이션(API)의 변화와 인터페이스의 변화는 개발과정에서 감당할 수 있는 수준의 변화라 할 수 있지만, 데이터의 변화는 마이크로서비스 전체를 재설계 해야할 수 있는 중대한 변화라 할 수 있다. 따라서 초기 데이터의 변화를 정확하게 파악하고, 비즈니스를 개선해 나가는 것은 무엇보다 중요한 과정이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;데이터 동기화 문제&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;논리적 스키마 대 물리적 스키마 분해&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;트랜잭션 무결성&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;조인&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;대기 시간&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;지금부터 총 7번의 포스팅으로 데이터베이스를 분리하기 위한 고려사항들을 하나씩 되짚어보고, 다양한 분산DB 설계 패턴들에 대해 알아보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;div id=&quot;pattern-shared-database&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;단일 DB 패턴&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;우리는 분산DB 설계 패턴을 알아보기 전에 먼저 모놀리스 어플리케이션 내 단일 DB 환경의 문제점에 대해 알아보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;기존 모놀리식 어플리케이션을 마이크로서비스 아키텍처로 전환함으로써 여러 고려사항에 맞닫들이게 된다. 특히 여러 서비스 간 데이터 공존과 관련된 문제를 해소해 나가야 한다. 대표적인 단일 DB의 문제점은 다음과 같다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;마이크로서비스 간 정보 보호(은닉)의 어려움&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;데이터 통제의 어려움&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;결합도 증가에 따른 서비스 배포 독립성 확보 불가&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;다음은 분산 DB 환경에서 상호간 데이터 조회를 어떻게 효율적으로 할 것인지에 대한 고려사항이 반영된 설계 패턴들이다.&lt;/span&gt;&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;div id=&quot;idm46387402051000&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;설계 패턴 1. 마이크로서비스 간 독립 DB 사용&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;각 마이크로서비스가 자체 데이터를 소유하고 비즈니스를 서비스 내에서 처리할 수 있도록 데이터베이스를 분할하는 것은 어렵지만 가장 고객이 선호하는 패턴이라 할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;662&quot; data-origin-height=&quot;508&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dsC9Uy/btrlIl3A2Ki/GtEXJyifqOxqpiKs7c6qRK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dsC9Uy/btrlIl3A2Ki/GtEXJyifqOxqpiKs7c6qRK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dsC9Uy/btrlIl3A2Ki/GtEXJyifqOxqpiKs7c6qRK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdsC9Uy%2FbtrlIl3A2Ki%2FGtEXJyifqOxqpiKs7c6qRK%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;662&quot; height=&quot;508&quot; data-origin-width=&quot;662&quot; data-origin-height=&quot;508&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;신규 서비스를 위와 같은 형태로 설계하는 것은 가장 바람직한 설계 방법이다. 다만, 현행 서비스가 존재하고 이를 마이크로서비스로 전환하는 경우 데이터의 결합도를 끊어 낼 수 있도록 완벽하게 설계하는 것은 굉장히 어려운 일이다. 위와 같이 설계하기 위해서는 비즈니스의 대부분을 수정하여 서비스를 재 분류하는 작업부터 시작되어야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;idm46387402044984&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;각 서비스가 독립적인 스키마를 갖도록 설계할 경우 서비스간 결합도는 현저히 낮아져 각 서비스가 추구하는 목표에 맞게 서비스를 설계할 수 있을 것이다. 그 목표가 성능일 수도, 잦은 배포의 독립성일 수도, 비즈니스 요구사항일 수도 있으며, 독립된 데이터를 갖는 것은 바로 이 목표를 달성하기 위한 충분조건이라 할 수 있다. 다만 스키마의 분리가 쉽지 않기 때문에 모든 서비스를 한번에 전환하는 것보다는 순서를 정하고 분리해 나가는 것이 좋다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; font-size: 1.62em; letter-spacing: -1px;&quot;&gt;설계 패턴 2. 데이터 공유 방식 (View)&lt;/span&gt;&lt;/p&gt;
&lt;div id=&quot;ch05c-materialized-view&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;완전한 분리가 불가능하다면, 차선으로 서비스당 2개 이상의 데이터베이스에 접근하는 방법을 선택할 수 있다. 특히 서로 다른 서비스가 독립적인 DB를 갖고, 그 서비스간 데이터 조회를 고려해야 할 경우 테이블에 직접 접근하기 보다는 View를 사용하여 결합도를 낮출 수 있다. View를 사용함으로써 서비스에 표시되는 데이터를 제한하여 액세스해서는 안 되는 정보를 은닉할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;662&quot; data-origin-height=&quot;236&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbwrxt/btrlDWxItBT/FjYCTbFFIiditc4ybIuEz1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbwrxt/btrlDWxItBT/FjYCTbFFIiditc4ybIuEz1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbwrxt/btrlDWxItBT/FjYCTbFFIiditc4ybIuEz1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbbwrxt%2FbtrlDWxItBT%2FFjYCTbFFIiditc4ybIuEz1%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;662&quot; height=&quot;236&quot; data-origin-width=&quot;662&quot; data-origin-height=&quot;236&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;div id=&quot;idm46387402003032&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위는 타 서비스의 데이터소스에 직접 접근하는 형태의 조회 방식이다. 위와 같이 구성할 경우 공유하는 서비스간 결합도가 높아지는 문제가 발생할 수 있다. 고객 서비스의 고객 DB가 변경될 경우 계좌서비스와 이체서비스는 변경된 데이터 또는 스키마에 대한 검증을 함께 수행해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;662&quot; data-origin-height=&quot;240&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c1sGtB/btrlNckKH0k/iUCOqvdhSS9IMgXr0vsMY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c1sGtB/btrlNckKH0k/iUCOqvdhSS9IMgXr0vsMY1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c1sGtB/btrlNckKH0k/iUCOqvdhSS9IMgXr0vsMY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc1sGtB%2FbtrlNckKH0k%2FiUCOqvdhSS9IMgXr0vsMY1%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;662&quot; height=&quot;240&quot; data-origin-width=&quot;662&quot; data-origin-height=&quot;240&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이를 해소하기 위해 고객 DB에 접근하고자 하는 모든 외부 서비스를 위한 고객DB &lt;span style=&quot;color: #000000;&quot;&gt;전용&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;View 스키마를 만들고 외부 서비스가 대신 해당 스키마를 바라보도록 설계한다. 이를 통해 View가 유지되는 한 고객DB의 자체 스키마를 변경할 수 있다. 또한, 불필요한 데이터를 숨기거나, 데이블 조인을 수행한 후 View로 제공할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;662&quot; data-origin-height=&quot;395&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dM2Zxv/btrlEn2WjCx/2VlnQ1UcWCVNzAvR7Zwo3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dM2Zxv/btrlEn2WjCx/2VlnQ1UcWCVNzAvR7Zwo3k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dM2Zxv/btrlEn2WjCx/2VlnQ1UcWCVNzAvR7Zwo3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdM2Zxv%2FbtrlEn2WjCx%2F2VlnQ1UcWCVNzAvR7Zwo3k%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;662&quot; height=&quot;395&quot; data-origin-width=&quot;662&quot; data-origin-height=&quot;395&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;위와 같이 고객서비스에 저장되어 있는 고객DB 내의 PW, Account Num을 계좌서비스나, 이체서비스로 부터 보호할 수 있다.&lt;/span&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;다만, View를 활용할 경우 장단점이 존재한다. View는&amp;nbsp;일반적으로 캐시를 사용하여 미리 계산된다. 즉, View에서 데이터를 읽기 원하는 계좌서비스, 이체서비스는 View에서 매번 고객DB에서 데이터를 읽어올 필요가 없으므로 성능이 향상될 수 있다. 반면에 View에서 오래된 데이터를 읽을 수 있음을 고려해야 한다. 즉, View를 갱신하는 방식이 성능과 데이터 정합성 사이에서 중요하다는 점을 인지하고 설계해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;이와 같이 View를 설계하기 위해서는 몇가지 제약조건이 존재한다. 먼저 앞서 잠시 언급한 캐시를 사용하는 것과 같이 정합성의 이슈가 발생할 수 있다.(ReadOnly의 전형적인 이슈) 두번째로 고객DB와 고객View가 Schema는 분리되더라도 동일한 데이터베이스 엔진 내에 있어야 한다는 점이다. 즉 데이터베이스에 직접 접근하는 방식보다는 결합도를 낮출 수 있지만, 여전히 CUD와 R이 하나의 데이터베이스 내에서 발생한다는 점은 인지해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;데이터 공유 방식(View) 패턴은 단일 DB 내 계정이 분리되어 있는 환경 또는 현행 스키마를 모델링을 통해 분해하기 어려운 경우에 적용하기 용이하다. 물론 View는 여전히 서비스간 일부 결합도가 존재하기 때문에 최종 데이터베이스의 형태라 볼수는 없지만, 데이터 모델링에 들어가는 에포트가 너무 클 경우에는 한번쯤 고려해 볼 수 있는 패턴이 아닐까 싶다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; font-size: 1.62em; letter-spacing: -1px;&quot;&gt;설계 패턴 3. 공통 마이크로서비스 활용&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;앞서 각 서비스가 명확히 자신의 데이터만을 관리하고 서비스할 수 있다면 가장 좋은 설계라고 이야기 했다. 물론 현실적으로 굉장히 어려운 방식이지만, 이를 구현하기 위해 또 하나의 공통 서비스를 생성하고 Shared Data를 관리하는 방식을 고려해 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;764&quot; data-origin-height=&quot;420&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqsmAp/btrlEUr9rOx/HRkrCV20IlZXBgTkMWhKc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqsmAp/btrlEUr9rOx/HRkrCV20IlZXBgTkMWhKc1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqsmAp/btrlEUr9rOx/HRkrCV20IlZXBgTkMWhKc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqsmAp%2FbtrlEUr9rOx%2FHRkrCV20IlZXBgTkMWhKc1%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;764&quot; height=&quot;420&quot; data-origin-width=&quot;764&quot; data-origin-height=&quot;420&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;즉 고객/계좌/이체 서비스에서 개별적으로 사용하는 데이터는 각 서비스의 DB에 저장하고, 공통으로 사용하는 데이터 또는 상호 공유되어야 하는 데이터를 공통서비스 내 공통DB에 저장한다. 공통서비스는 Front 서비스에게 공통 데이터를 직접 액세서 할 수 있도록 엔드포인트를 제공하고, 마이크로서비스 간에는 공통 데이터 또는 공유 데이터를 조회할 수 있는 API를 제공한다. 고객/계좌/이체(호출자) 서비스는 DB에 직접 액세스 하지 않고 API를 호출하여 결과를 전달 받는 방식으로 구현한다.&lt;/span&gt;&lt;/p&gt;
&lt;div id=&quot;idm46387401951128&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;대체로 해당 패턴은 최종 모습은 아니지만, API 형태로 서비스를 호출하여 Schema를 분리하기 위한 초입단계로써 적용해 볼 수 있을 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;&lt;/div&gt;
&lt;div id=&quot;pattern-database-as-a-service-interface&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;설계 패턴 4. ReadOnly DB 활용&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;다음으로 타 마이크로서비스의 데이터를 CUD하는 경우 API, 조회는 ReadOnly DB를 이용하는 방식이다.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1091&quot; data-origin-height=&quot;568&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k7lES/btrlJMz6EyD/KXi2fo9qyGVX7dYuR9vSck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k7lES/btrlJMz6EyD/KXi2fo9qyGVX7dYuR9vSck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k7lES/btrlJMz6EyD/KXi2fo9qyGVX7dYuR9vSck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk7lES%2FbtrlJMz6EyD%2FKXi2fo9qyGVX7dYuR9vSck%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;1091&quot; height=&quot;568&quot; data-origin-width=&quot;1091&quot; data-origin-height=&quot;568&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;계좌서비스는 고객서비스에 데이터 변경을 위해 고객 API를 호출한다. 이때 고객DB에 변경된 데이터는 ReadOnly DB로 복제되며, 고객서비스를 조회할 경우 이 ReadOnly DB를 통해 접근할 수 있다. 이때 복제를 구현할 수 있는 방안들은 공통적으로 타이밍 이슈가 발생할 수 있다는 점을 염두해 두고 아키텍처를 설계해야 하며, 업데이트 된 시점을 응용관점에서 관리해 주는 것도 좋은 방법이 될 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;div id=&quot;idm46387401924664&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;복제 방법은 DB에서 지원하는 Replication 방식을 사용할 수도 있지만, 이기종 DB간 지원, Schema 변경에 대한 대응을 위한 Oracle GoldenGate(OGG), Debezium 등&lt;/span&gt;과 같은 CDC 도구를 사용하는 것이 안정적이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;참고 :&amp;nbsp;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;a style=&quot;color: #006dd7;&quot; href=&quot;https://hevodata.com/learn/7-best-cdc-tools/&quot;&gt;https://hevodata.com/learn/7-best-cdc-tools/&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;idm46387401915384&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;ReadOnly DB를 적용하면, 데이터를 보호하고, 읽기 전용 NoSQL DB를 활용하여 성능상 이점을 가져갈 수 있다. 특히 분산DB 데이터 관리 방안으로 CQRS나 API Composition을 위한 조회 용도의 DB로 활용하기 좋다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;결론&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;오늘은 첫 시간으로 분산 DB 환경에서 상호간 데이터 조회를 효율적으로 할 수 있는 4가지 패턴에 대해 알아보았다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;설계 패턴 1. 마이크로서비스 간 독립 DB 사용&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;설계 패턴 2. 데이터 공유 방식 (View)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;설계 패턴 3. 공통 마이크로서비스 활용&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;설계 패턴 4. ReadOnly DB 활용&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;설계 패턴 1의 경우 이상적인 마이크로서비스 환경 상의 분산 DB 형태이지만, 이는 비즈니스 처리 흐름에 따라 현실적으로 어려운 구성이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;설계 패턴 2의 경우 DB에 접근하기 보다는 불필요한 데이터를 제한하도록 View를 사용하는 방식을 적용할&amp;nbsp; 수 있지만, 물리적으로 동일한 DB 내에 Table과 View가 함께 공존한다는 차원에서 결합도가 완전히 분리되었다고 보기 어렵다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;설계 패턴 3의 경우 독립성을 현저히 낮춰 줄 수 있는 API 호출 방식으로 가장 선호하는 방식이다. 마이크로서비스 아키텍처를 구성해 나가기 위한 구성 요소로 Rest API를 이야기 하는 이유도 바로 이와 무관하지 않다. 독립적인 DB에 대한 조회는 특히 실시간성 조회가 강조되는 경우 API를 통해 조회하도록 설계하는 것이 좋다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;마지막 설계 패턴 4의 경우 2와 비슷하다고 볼 수 있지만, 물리적으로 독립된 환경에 Replication을 구성할 수 있어 보다 안정적인 서비스 제공이 가능하다. 특히 마이크로서비스 환경에서 CQRS DB 등을 적용하기 위한 패턴으로 적합핟. 다만, 데이터 정합성에 보다 노력을 기울여야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;다음 포스팅에서는 모놀리식 to 마이크로서비스 DB로의 전환 시 데이터 분할 방법에 대해 알아보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>③ 클라우드/ⓜ MSA</category>
      <category>MSA</category>
      <category>MSA 분산 DB 조회 설계</category>
      <category>MSA 분산DB</category>
      <category>마이크로서비스</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/724</guid>
      <comments>https://waspro.tistory.com/724#entry724comment</comments>
      <pubDate>Sun, 14 Nov 2021 15:47:19 +0900</pubDate>
    </item>
    <item>
      <title>마이크로서비스 아키텍처의 기준과 DB 분리</title>
      <link>https://waspro.tistory.com/718</link>
      <description>&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;개요&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;최근 3년 사이 마이크로서비스 아키텍처의 급격한 유행에 따라 많은 프로젝트에서 MSA로의 전환을 시도하고 있으며, 성공적으로 전환한 케이스가 있는 반면, 실패한 경우도 종종 발생하고 있다. 포스팅의 시작점에서 우리가 말하는 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;성공적인 마이크로서비스 전환 사례란 무엇인지에 대해 알아보도록 하자.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006DD7;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;마이크로서비스 아키텍처의 성공기준&lt;/span&gt;&lt;/span&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;i&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;RESTFul API가 적용된 프로젝트&lt;/span&gt;&lt;/span&gt;&lt;/i&gt;&lt;/li&gt;
 &lt;li&gt;&lt;i&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;독립적인 배포가 가능하도록 결합도를 낮춘 프로젝트&lt;/span&gt;&lt;/span&gt;&lt;/i&gt;&lt;/li&gt;
 &lt;li&gt;&lt;i&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;클라우드가 적용된 확장성, 가용성이 확보된 프로젝트&lt;/span&gt;&lt;/span&gt;&lt;/i&gt;&lt;/li&gt;
 &lt;li&gt;&lt;i&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;자동화된 배포 체계가 갖추어진 프로젝트&lt;/span&gt;&lt;/span&gt;&lt;/i&gt;&lt;/li&gt;
 &lt;li&gt;&lt;i&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;DevOps 조직 체계를 적용한 프로젝트&lt;/span&gt;&lt;/span&gt;&lt;/i&gt;&lt;/li&gt;
 &lt;li&gt;&lt;i&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;......&lt;/span&gt;&lt;/span&gt;&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;마이크로서비스로의 전환이 진행중인 또는 완료된 프로젝트 사례들을 살펴보면 위와 같은 공통의 목표를 달성해 내고자 했을 것이다.&lt;br&gt;다만, 이와 같은 기술 지향적 목표 수립만으로는 MSA 프로젝트를 온전히 성공해 낼수는 없으며, 성공적으로 전환하기 위해서는 다음과 같은 기준을 수립하는 것이 중요하다.&lt;/span&gt;&lt;br&gt;&lt;b&gt;&lt;i&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&quot;마이크로서비스 아키텍처는 그간 IT를 이끌어온 아키텍처 사상들의 Pain Point들을 수집하고 이를 어떻게 해소해 낼 것인가에 집중한 아키텍처 사상이며, 고객의 니즈를 신속하게 적용하기 위해 여러 기술셋들을 선택적으로 적용한 아키텍처이다. 성공적으로 전환한 프로젝트는 바로 이를 달성한 프로젝트라 할 수 있다.&quot;&lt;/span&gt;&lt;/i&gt;&lt;/b&gt;&lt;br&gt;중요한 점은&lt;span style=&quot;color: #000000;&quot;&gt; 마이크로서비스 아키텍처는 기술셋에 의존된 설계 방식이 아닌 반대로 목표를 수립하고 달성하기 위해 기술셋을 선택하는 방식으로 접근해야 한다는 것이다. 이와 같은 접근 방식이 있어야 다양한 오픈소스 소프트웨어의 적용여부를 검토하고 프로젝트에 적합한 개발방식 등을 선택해 낼 수 있을 것이다.&lt;/span&gt;&lt;br&gt;&lt;span style=&quot;color: #000000;&quot;&gt;특히 수많은 기술셋과 오픈소스를 선택해 나가는 과정에서 DB의 선택과 분리는 독립배포, 결합도 약화, 장애 차단 등 여러 측면에서 프로젝트 성공여부를 결정할 수 있는 핵심 고려사항이라 할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006DD7;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;MSA와 DB 분리 기준&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;b&gt;&lt;i&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&quot;마이크로서비스 아키텍처를 적용하기 위해서는 서비스 별로 DB를 반드시 쪼개야 하나?&quot;&lt;/span&gt;&lt;/i&gt;&lt;/b&gt;&lt;br&gt;&lt;span style=&quot;color: #000000;&quot;&gt;마이크로서비스에서 데이터가 갖는 의미는 굉장히 크다. 사실상 MSA의 성공 여부를 판단하는 기준이 데이터에 달려 있다고 해도 과언이 아니다. 대부분의 MSA 개발 방법들은 데이터 처리에 관련이 있으며, 데이터의 분할 방식에 따라 영향도가 커질 수도 작아 질수도 있다.&lt;/span&gt;&lt;br&gt;&lt;span style=&quot;color: #000000;&quot;&gt;기존 모놀리식 어플리케이션이 마이크로서비스로 변화하는 과정에서 어플리케이션은 화면, 백엔드, 데이터로 세분화 된다. 대체로 MVC 구조에 익숙한 모놀리식 어플리케이션과 다르게 View 영역이 하나의 마이크로서비스로 분리되며, Persistent 영역은 마이크로서비스 별 독립된 데이터베이스로 구성된다. 때로는 화면에서 직접 조회가 가능한 데이터베이스도 존재한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1294&quot; data-origin-height=&quot;631&quot; data-image-src=&quot;https://k.kakaocdn.net/dn/bfFfQW/btreMEo25AP/FxzLvysZxasQanMPXJETQk/img.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfFfQW/btreMEo25AP/FxzLvysZxasQanMPXJETQk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfFfQW/btreMEo25AP/FxzLvysZxasQanMPXJETQk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfFfQW/btreMEo25AP/FxzLvysZxasQanMPXJETQk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfFfQW%2FbtreMEo25AP%2FFxzLvysZxasQanMPXJETQk%2Fimg.png&quot; data-origin-width=&quot;1294&quot; data-origin-height=&quot;631&quot; data-image-src=&quot;https://k.kakaocdn.net/dn/bfFfQW/btreMEo25AP/FxzLvysZxasQanMPXJETQk/img.png&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;모놀리식 어플리케이션에서 마이크로서비스 아키텍처로의 전환은 BIG BANG 방식으로 전환하는 TOP DOWN 방식을 여전히 선호하는 것이 국내 프로젝트의 실정이지만, 아키텍처 사상의 변화는 커버넌스 측면은 물론 어플리케이션의 구조적인 변화가 크게 발생하기 때문에 옳바른 전환 방식이라 할 수 없다.&lt;/span&gt;&lt;br&gt;리스크를 최소화하며 마이크로서비스로 전환해 나가기위해서는 &lt;span style=&quot;color: #000000;&quot;&gt;백엔드 → 데이터베이스(데이터) → 프론트엔드 순으로 점진적인 변화를 가져가는 것이 효과적이다.&lt;br&gt;먼저 백엔드 어플리케이션을 마이크로서비스로 전환하는 과정에 대해 간단히 살펴보자.&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;b&gt;&lt;i&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&quot;아키텍트는 서비스 단위를 결정하기 위해 Bounded Context를 적용하여 서비스 범위를 정의하고, 그 기준에 따라 서비스가 결정되면, 서비스간 인터페이스 방식을 결정하며, 인터페이스를 위한 기술셋을 선택한다. 개발자는 API를 식별하고, 인터페이스에 필요한 기술요소들을 활용하여 개발한다.&quot;&lt;/span&gt;&lt;/i&gt;&lt;/b&gt;&lt;br&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이때 마이크로서비스 전환이 시작되는 시점부터 반드시 데이터베이스를 분리해야 하는가? 라는 질문이 있을 수 있다. 결론부터 말하자면 반드시 초기부터 데이터를 구분할 필요는 없다. 물론 장기적인 관점에서 바라보았을때, 점진적 이행이 가능한 형태로 데이터베이스를 분리해 나가는 것은 중요하지만, 초기 마이크로서비스 아키텍처를 적용하여 프로젝트를 시작하는 시점에서 데이터베이스를 분리하는 것은 위험도가 굉장히 높아 질뿐 아니라, 프로젝트 실패시 부담해야할 리스크 역시 커질 수 있다.&lt;/span&gt;&lt;br&gt;&lt;span style=&quot;color: #000000;&quot;&gt;MSA 방법론, 모델링, 분석/설계, 개발, 테스트, 이행을 거치며, 마이크로서비스의 단위는 유동적으로 변화할 수 있다. 어플리케이션 영역(화면, 백엔드)에서는 변화에 따라 대응 개발하기 용이하지만, 데이터의 재배치, 테이블의 재설계는 어플리케이션 전체에 영향을 끼칠 수 있는 영역으로 재설계가 용이하지 않고 데이터의 변화에 따라 어플리케이션 구조 변화에 큰 영향을 주게된다. 따라서 Persistent의 경우 백엔드 서비스의 전환이 완료되거나, 안정화 된 이후에 설계하는 것이 좋고, 특히나 빅뱅방식의 전환은 지양해야 한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1780&quot; data-origin-height=&quot;621&quot; data-image-src=&quot;https://k.kakaocdn.net/dn/n13gx/btreK6zbybA/UAVSl7bHbgwJAc0aVqCkzk/img.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/n13gx/btreK6zbybA/UAVSl7bHbgwJAc0aVqCkzk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/n13gx/btreK6zbybA/UAVSl7bHbgwJAc0aVqCkzk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/n13gx/btreK6zbybA/UAVSl7bHbgwJAc0aVqCkzk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fn13gx%2FbtreK6zbybA%2FUAVSl7bHbgwJAc0aVqCkzk%2Fimg.png&quot; data-origin-width=&quot;1780&quot; data-origin-height=&quot;621&quot; data-image-src=&quot;https://k.kakaocdn.net/dn/n13gx/btreK6zbybA/UAVSl7bHbgwJAc0aVqCkzk/img.png&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;MSA로의 전환을 이야기할때, MINISERVICE가 함께 등장하는 이유 역시 이와 같으며, 성공적인 전환을 위해 프로젝트는 장기간 점진적인 변화 구조를 가져가는 것이 무엇보다 중요하다.&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;지금부터는 본격적으로 DB가 분리된 마이크로서비스와 서비스만 분리된 마이크로서비스 간의 차이점을 알아보고, 점진적이행을 위해 고려되어야 할 부분에 대해 알아보도록 하자.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006DD7;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;아키텍처의 변화&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;제일 먼저 살펴보아야 할 부분은 바로 아키텍처의 변화 측면이다. 데이터베이스의 분리는 인프라 아키텍처, 어플리케이션 아키텍처 측면에서 커다란 변화를 불러일으킨다. 이를 하나씩 살펴보도록 하자.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006DD7;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;인프라 아키텍처&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;인프라 아키텍처 측면에서 가장 고려되어야 할 부분은 바로 구조의 변화 측면이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1282&quot; data-origin-height=&quot;505&quot; data-image-src=&quot;https://k.kakaocdn.net/dn/bgPjfW/btrePWvL5BJ/V72jkcZSijwF0XgRI6bG1K/img.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgPjfW/btrePWvL5BJ/V72jkcZSijwF0XgRI6bG1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgPjfW/btrePWvL5BJ/V72jkcZSijwF0XgRI6bG1K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgPjfW/btrePWvL5BJ/V72jkcZSijwF0XgRI6bG1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbgPjfW%2FbtrePWvL5BJ%2FV72jkcZSijwF0XgRI6bG1K%2Fimg.png&quot; data-origin-width=&quot;1282&quot; data-origin-height=&quot;505&quot; data-image-src=&quot;https://k.kakaocdn.net/dn/bgPjfW/btrePWvL5BJ/V72jkcZSijwF0XgRI6bG1K/img.png&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;각 마이크로서비스 별로 독립적인 데이터베이스를 구성할 경우 아래와 같은 사항에 주의해야 한다.&lt;/span&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;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;비용 : 데이터베이스의 물리적 노드 증가에 따른 비용 증가. 오픈소스 DB를 사용할 경우 구축/운영 인력 증가.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
 &lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;성능 : 호출 홉 증가에 따른 성능 저하. 데이터 전송에 따른 성능 저하.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
 &lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;인력 : 기술셋 확장에 따른 지원인력 증가.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
 &lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;모델링 : 마이크로서비스 인터페이스 모델링, 데이터베이스 모델링(테이블 분할 설계/데이터 오너쉽 정의 등)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006DD7;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;어플리케이션 아키텍처&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;어플리케이션 아키텍처 측면에서 가장 고려해야 할 부분은 바로 서비스 간 데이터의 동기화 측면이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1258&quot; data-origin-height=&quot;886&quot; data-image-src=&quot;https://k.kakaocdn.net/dn/TcXma/btreKlcKWk0/J1Rdqan87MoSuamgo3UH30/img.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TcXma/btreKlcKWk0/J1Rdqan87MoSuamgo3UH30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TcXma/btreKlcKWk0/J1Rdqan87MoSuamgo3UH30/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TcXma/btreKlcKWk0/J1Rdqan87MoSuamgo3UH30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTcXma%2FbtreKlcKWk0%2FJ1Rdqan87MoSuamgo3UH30%2Fimg.png&quot; data-origin-width=&quot;1258&quot; data-origin-height=&quot;886&quot; data-image-src=&quot;https://k.kakaocdn.net/dn/TcXma/btreKlcKWk0/J1Rdqan87MoSuamgo3UH30/img.png&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;각 마이크로서비스 별로 독립적인 데이터베이스를 구성할 경우 아래와 같은 사항에 주의해야 한다.&lt;/span&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;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;조인쿼리 : 모놀리식 어플리케이션 내 조인쿼리에 대응하기 위한 동기/비동기 처리 호출 설계.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
 &lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;트랜잭션관리 : 분산트랜잭션 관리를 위한 이벤트 처리 설계.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
 &lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;보상트랜잭션 : 데이터 복구를 위한 Saga 패턴 설계&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
 &lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;API 증가 : 데이터 호출 증가에 따른 API 설계.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
 &lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;배치 : 배치 아키텍처 설계를 위한 데이터 통합 방안 설계.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006DD7;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;개발의 변화&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;앞서 정의한 인프라/아키텍처의 변화는 그 지향점을 명확히 파악하고 대체할 수 있다. 물론 비용/시간/일정/인력의 변화를 감수한다면 말이다. 그러나, 개발의 경우 DB의 분리로부터 어떠한 영향이 발생할 것인지 파악하는 것은 굉장히 어려운 일이다.&lt;/span&gt;&lt;br&gt;&lt;span style=&quot;color: #000000;&quot;&gt;분석/설계를 진행하며, API 목록을 도출하고, 동기/비동기 서비스로 구분하여 어플리케이션 구조를 개선해야 나가야 한다. 인터페이스의 증가에 따른 비용/일정 그리고 무엇보다 리스크를 감내해야 하고 데이터베이스 분리에 따른 테이블/테이터 설계 측면에서도 고려해야 한다.&lt;/span&gt;&lt;br&gt;&lt;span style=&quot;color: #000000;&quot;&gt;무엇보다 단일 데이터베이스의 조인쿼리에 대해 API Composition, CQRS 테이블 생성 특히 보상 트랜잭션에 대한 설계 등은 단순히 개발 본수의 증가만을 이야기 하는 것이 아니라, 개발자가 설계에 참여하여 개발의 방향성을 결정해야 하는 문제들도 당면하게 된다. 물론 DevOps 조직이 갖춰진 플랫폼 기업의 경우 이미 그렇게 진행되고 있겠지만, 대부분의 SI 프로젝트를 발주하는 기업들의 경우 조직의 변화가 갖추어졌을리 만무하다.&lt;/span&gt;&lt;br&gt;&lt;span style=&quot;color: #000000;&quot;&gt;또한, 테이블 재설계는 물론 데이터 오너쉽 정의, 배치처리 업무, 서비스 연관도 분할, MSA 비 대상 서비스와의 결합도 약화, 인터페이스 개발, 비즈니스 개선, 프로세스 개선 등 개발에서 확장된 업무들이 개발자의 역할로 부여 받게 된다.&lt;/span&gt;&lt;br&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이로 인해 개발자는 정확한 공수 산정 및 개발에 필요한 기술셋, 일정 등을 사전에 파악하기 어려워 무엇보다 개발 PL의 역할이 중요해진다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;결론&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;마이크로서비스 아키텍처를 설명하는 기술셋에서 DB의 분리는 비즈니스 요건에 따라 명확히 구분하고 접근해야 한다. 무조건 모든 서비스를 분리하는 것은 인프라 측면, 어플리케이션 측면에서 많은 기회비용을 지불해야 하기 때문이다.&lt;/span&gt;&lt;br&gt;&lt;span style=&quot;color: #000000;&quot;&gt;비즈니스 요구사항 중 서비스 독립성/확장성이 강조되는 경우 요소 별 투입되는 아키텍처 기반 비용을 감안하여 분리 가능여부를 결정해야 한다. 초기 거론한것 처럼 점진적 이행을 위해 기반 환경을 구성하고 리스크 감소 차원에서 데이터베이스 분리는 서비스 별 점진적으로 확대해 나가는 것이 올바른 방향이라 할 수 있다.&lt;/span&gt;&lt;br&gt;&lt;span style=&quot;color: #000000;&quot;&gt;간혹 마이크로서비스 당 하나의 데이터베이스를 반드시 구성해야 한다는 강박관념으로부터 마이크로서비스를 설계하는 경우가 있다. 데이터베이스를 구분하는 것은 단순히 물리적인 공간을 구분하는 것이 아닌 데이터의 정합성, 연속성을 보장하기 위해 많은 노력과 비용이 발생하는 아키텍처 패턴임을 명심해야 한다. 불필요하게 보상 트랜잭션 처리하고, 비동기 서비스를 호출하는 것은 결과적으로 이행/오픈/유지보수 전 과정에 걸쳐 추가적인 Effort를 발생시키는 일임에는 분명한 사실이다.&lt;/span&gt;&lt;br&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그럼에도 불구하고 &lt;span style=&quot;color: #000000;&quot;&gt;결합도를 낮추고 신속한 배포가 가능하다는 점에서 &lt;/span&gt;DB의 분리를 통해 얻을 수 있는 장점 또한 굉장히 크다. &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;DB 분리를 통해 얻을 수 있는 장점과 기회비용을 판단하여 비즈니스 요구사항을 달성하기 위해 점진적인 이행 로드맵을 수립해나감으로써 성공적인 MSA 전환 사례를 만드는것이 무엇보다 중요하다는 점을 기억하고 이번 포스팅을 마치고자 한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>③ 클라우드/ⓜ MSA</category>
      <category>api composition</category>
      <category>MSA</category>
      <category>MSA Batch</category>
      <category>MSA DB분리</category>
      <category>MSA Join</category>
      <category>마이크로서비스</category>
      <category>보상트랜잭션</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/718</guid>
      <comments>https://waspro.tistory.com/718#entry718comment</comments>
      <pubDate>Sat, 11 Sep 2021 23:12:39 +0900</pubDate>
    </item>
    <item>
      <title>이미지 서명 (docker sign &amp;amp; notary)</title>
      <link>https://waspro.tistory.com/716</link>
      <description>&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;개요&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;급격하게 확대되고 있는 오픈소스 시장에서 소프트웨어 업그레이드를 이용한 공격사례가 증가하고 있다. 어떠한 악성 코드가 반영되어 있는지 확인하기 어렵고, 어떠한 소프트웨어가 설치되어 있는지 확인하기 어려운 상태에서 인터넷 상에 떠도는 오픈소스 소프트웨어를 업그레이드 하거나, 파일을 반입하는 것은 공격의 대상으로 타켓팅 될뿐 아니라, 때로는 심각한 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;정보들를 유출하는 심각한 문제를 초래하기도 한다.&lt;br /&gt;따라서 오픈소스를 구축하고 운영할 경우 업그레이드 관리에&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 많은 비용과 시간을 투자해야 함을 반드시 인지해야한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;도커 이미지 역시 마찬가지이다. 이미지&lt;span style=&quot;color: #000000;&quot;&gt; 내부에는 어떠한 파일과 소프트웨어가 설치되어 있는지 판단하기 어려운 상태에서 &lt;/span&gt;반입하는 경우가 많다. 따라서 이미지는 도커 허브와 같은 공식 사이트에서 검증된 official 이미지라고 하더라도 가능한 직접 origin 이미지로부터 생성하는 과정을 거치는 것이 중요하며, 생성한 이미지를 Signer를 통해 서명하고 서명된 이미지만이 반영될 수 있도록 관리체계를 수립해야 한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;지금부터는 Docker Image를 서명하는 과정에 대해 살펴보고, 이를 Harbor Notary를 적용하여 Private 환경에서 관리하는 방법에 대해 알아보자.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;포스팅 순서&lt;/span&gt;&lt;/span&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;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;TUF (The Update Framework)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;Docker Signer (docker trust sign)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;Notary (by Harbor)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;TUF (The Update Framework)&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;먼저, 이미지 서명관리에 대해 알아보기 전에 TUF (The Update Framework)에 대해 알아보자. TUF (The Update Framework)는 개발자가 소프트웨어 업데이트 시스템의 보안을 유지하도록 지원하며, 저장소나 서명 키를 손상시키는 공격자로부터 시스템을 보호하는 프레임워크를 통칭한다.&lt;br /&gt;지금부터 살펴볼 Notary가 대표적인 TUF 프레임워크라 볼 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;Docker Signer (docker trust sign)&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;Docker 이미지에 서명하는 방법에 대해 먼저 알아보도록 하자.&lt;/span&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;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;이미지 다운로드 (docker pull)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;이미지 태그 생성 (docker tag)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;public key 생성 (docker trust key)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;이미지 서명자 생성 (docker trust signer)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;이미지 서명 생성 (docker trust sign)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;이미지 서명 확인 (docker trust inspect)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이미지 서명 취소 (docker trust revoke) - OPTION&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;이미지 push (docker push)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;DCT 적용 (&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;DOCKER_CONTENT_TRUST)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;서명된 이미지 다운로드 (docker pull)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&amp;gt; 이미지 다운로드 (docker pull)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;html xml&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;[root@ip-192-168-93-115 harbor]# docker pull ubuntu:latest
latest: Pulling from library/ubuntu
35807b77a593: Pull complete 
Digest: sha256:9d6a8699fb5c9c39cf08a0871bd6219f0400981c570894cd8cbea30d3424a31f
Status: Downloaded newer image for ubuntu:latest
docker.io/library/ubuntu:latest
[root@ip-192-168-93-115 harbor]#&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&amp;gt; 이미지 태그 생성 (docker tag)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;html xml&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;[root@ip-192-168-93-115 sign]# docker tag ubuntu:latest sonnaraon/waspro-signed-ubuntu:latest
[root@ip-192-168-93-115 sign]# docker tag ubuntu:latest sonnaraon/unsigned-ubuntu:latest
[root@ip-192-168-93-115 sign]#&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;서명을 위한 waspro-signed-ubuntu 이미지와 서명하지 않은 unsigned-ubuntu 태그를 생성한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;gt; public key 생성 (docker trust key)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;html xml&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;[root@ip-192-168-93-115 sign]# docker trust key generate waspro 
Generating key for waspro... 
Enter passphrase for new waspro key with ID dda1569: 
Repeat passphrase for new waspro key with ID dda1569: 
Successfully generated and loaded private key. 
Corresponding public key available: /root/sign/waspro.pub 
[root@ip-192-168-93-115 sign]# ls -la total 4 
drwxr-xr-x 2 root root 24 Aug 29 14:41 . 
dr-xr-x--- 9 root root 250 Aug 29 14:37 .. 
-rw------- 1 root root 192 Aug 29 14:41 waspro.pub
[root@ip-192-168-93-115 sign]#&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;인증을 위한 public key를 생성한다. 생성한 키를 기반으로 notary 인증서버를 통해 서명을 진행한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;gt; 이미지 서명자 생성 (docker trust signer)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;html xml&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;[root@ip-192-168-93-115 sign]# docker trust signer add --key waspro.pub waspro sonnaraon/waspro-signed-ubuntu:latest 
Adding signer &quot;waspro&quot; to sonnaraon/waspro-signed-ubuntu:latest... 
Initializing signed repository for sonnaraon/waspro-signed-ubuntu:latest... 
Enter passphrase for root key with ID 721b098: 
Enter passphrase for new repository key with ID ef5aae1: 
Repeat passphrase for new repository key with ID ef5aae1: 
Successfully initialized &quot;sonnaraon/waspro-signed-ubuntu:latest&quot; 
Successfully added signer: waspro to sonnaraon/waspro-signed-ubuntu:latest 
[root@ip-192-168-93-115 sign]#&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Docker는 Notary와 함께 이미지 서명을 관리한다. Notary 서비스는 이미 DockerHub 내 구축되어 있어 별도 구성이 필요하지 않다. (default 4443 port) 다만, Private 환경에 별도로 구축할 경우 notary 서버 접근을 위한 환경변수를 구성해야 한다.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;위는 DockerHub와 연계되어 있는 notary 서버를 이용하여 이미지 서명을 위한 signer를 추가하는 과정이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;gt; 이미지 서명 생성 (docker trust sign)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;html xml&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;[root@ip-192-168-93-115 sign]# docker trust sign sonnaraon/waspro-signed-ubuntu:latest 
Signing and pushing trust data for local image sonnaraon/waspro-signed-ubuntu:latest, 
may overwrite remote trust data The push refers to repository [docker.io/sonnaraon/waspro-signed-ubuntu] 7555a8182c42: 
Pushed latest: digest: sha256:1e48201ccc2ab83afc435394b3bf70af0fa0055215c1e26a5da9b50a1ae367c9 size: 529 
Signing and pushing trust metadata 
Enter passphrase for waspro key with ID dda1569: 
Successfully signed docker.io/sonnaraon/waspro-signed-ubuntu:latest 
[root@ip-192-168-93-115 sign]#&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&amp;gt; 이미지 서명 확인 (docker trust inspect)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;html xml&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;[root@ip-192-168-93-115 sign]# docker trust inspect --pretty sonnaraon/unsigned-ubuntu:latest 
No signatures or cannot access sonnaraon/unsigned-ubuntu:latest 
[root@ip-192-168-93-115 sign]# docker trust inspect --pretty sonnaraon/waspro-signed-ubuntu:latest 
Signatures for sonnaraon/waspro-signed-ubuntu:latest 
SIGNED TAG DIGEST SIGNERS latest 1e48201ccc2ab83afc435394b3bf70af0fa0055215c1e26a5da9b50a1ae367c9 waspro List of signers and their keys for sonnaraon/waspro-signed-ubuntu:latest 
SIGNER KEYS waspro dda1569ada1c Administrative keys for sonnaraon/waspro-signed-ubuntu:latest 
Repository Key: ef5aae1bbd9bf9e918844c7677614cc3c077dd81fcc90f03ca0b8e90e0ea9546 
Root Key: b1bd363918ffc19e256ce9ae11fe47fc8311766771153129ede6cd0db2a10f76 
[root@ip-192-168-93-115 sign]#&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;앞서 생성한 두개의 태그를 기반으로 서명 여부를 검사한다.&lt;/span&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;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;unsigned-ubuntu:latest 이미지의 경우 &quot;No signatures or cannot access sonnaraon/unsigned-ubuntu:latest&quot;로 서명되지 않은 상태임을 확인할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;waspro-signed-ubuntu:latest 이미지의 경우 signer와 sign을 확인할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이와 같이 서명된 이미지를 repository에 업로드 하여 관리하고 이를 재 다운로드 받을 경우 DCT(Docker Content Trust)를 통해 제어하도록 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; 이미지 서명 취소 (docker trust revoke)&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1630803738293&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-93-115 harbor]# docker trust revoke sonnaraon/my-ubuntu:latest
Enter passphrase for waspro key with ID ced2399: 
Successfully deleted signature for sonnaraon/my-ubuntu:latest
[root@ip-192-168-93-115 harbor]# docker trust inspect sonnaraon/my-ubuntu:latest --pretty

No signatures for sonnaraon/my-ubuntu:latest


List of signers and their keys for sonnaraon/my-ubuntu:latest

SIGNER    KEYS
waspro    ac80c0dc7b14, ced23995604a

Administrative keys for sonnaraon/my-ubuntu:latest

  Repository Key:       768bb6ff476ab13c57629aeae2e648b8133bef16778206d01f406d4873f84411
  Root Key:     8719c895b67196527a96a59453fe9abe76fe80050b6dc66ac0bacf9dee9668b1
[root@ip-192-168-93-115 harbor]#&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;위와 같이 앞서 등록한 태그 서명이 취소된 것을 확인할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; 이미지 push (docker push)&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;html xml&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;[root@ip-192-168-93-115 ~]# docker push sonnaraon/unsigned-ubuntu:latest
The push refers to repository [docker.io/sonnaraon/unsigned-ubuntu] latest: 
digest: sha256:1e48201ccc2ab83afc435394b3bf70af0fa0055215c1e26a5da9b50a1ae367c9 
size: 529 
[root@ip-192-168-93-115 ~]# docker push sonnaraon/waspro-signed-ubuntu:latest 
The push refers to repository [docker.io/sonnaraon/waspro-signed-ubuntu] 7555a8182c42: 
Layer already exists latest: 
digest: sha256:1e48201ccc2ab83afc435394b3bf70af0fa0055215c1e26a5da9b50a1ae367c9 
size: 529 
Signing and pushing trust metadata Enter passphrase for waspro key with ID dda1569: 
Successfully signed docker.io/sonnaraon/waspro-signed-ubuntu:latest 
[root@ip-192-168-93-115 sign]#&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;이미지를 push하면 다음과 같이 DockerHub에 업로드 된 것을 확인할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;941&quot; data-origin-height=&quot;801&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cnXzkL/btrduHtqqHu/Ef4hxie1hUSmtwz7jC34h1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cnXzkL/btrduHtqqHu/Ef4hxie1hUSmtwz7jC34h1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cnXzkL/btrduHtqqHu/Ef4hxie1hUSmtwz7jC34h1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcnXzkL%2FbtrduHtqqHu%2FEf4hxie1hUSmtwz7jC34h1%2Fimg.png&quot; data-origin-width=&quot;941&quot; data-origin-height=&quot;801&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&amp;gt; DCT 적용 (DOCKER_CONTENT_TRUST)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;html xml&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;[root@ip-192-168-86-253 ~]# cat .bash_profile 
# .bash_profile 
# Get the aliases and functions 
if [ -f ~/.bashrc ]; then 
. ~/.bashrc fi 
# User specific environment and startup programs 
PATH=$PATH:$HOME/bin 
export PATH 
export DOCKER_CONTENT_TRUST=1 
[root@ip-192-168-86-253 ~]#&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;위는 서명된 이미지를 다른 workspace 환경에서 다운로드 받는 과정을 설명한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;DOCKER_CONTENT_TRUST = 1로 적용할 경우 서명된 이미지만 다운로드 받는다. 서명되지 않은 이미지는 다운로드 되지 않도록 차단함으로써 무분별한 이미지 적용 및 이미지를 이용한 해킹으로부터 1차적으로 방어할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;gt; 서명된 이미지 다운로드 (docker pull)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;html xml&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;[root@ip-192-168-86-253 ~]# docker images 
REPOSITORY TAG IMAGE ID CREATED SIZE 
[root@ip-192-168-86-253 ~]# docker pull sonnaraon/waspro-signed-ubuntu:latest 
Pull (1 of 1): sonnaraon/waspro-signed-ubuntu:latest@sha256:1e48201ccc2ab83afc435394b3bf70af0fa0055215c1e26a5da9b50a1ae367c9 docker.io/sonnaraon/waspro-signed-ubuntu@sha256:1e48201ccc2ab83afc435394b3bf70af0fa0055215c1e26a5da9b50a1ae367c9: 
Pulling from sonnaraon/waspro-signed-ubuntu 16ec32c2132b: Pull complete 
Digest: sha256:1e48201ccc2ab83afc435394b3bf70af0fa0055215c1e26a5da9b50a1ae367c9 
Status: Downloaded newer image for sonnaraon/waspro-signed-ubuntu@sha256:1e48201ccc2ab83afc435394b3bf70af0fa0055215c1e26a5da9b50a1ae367c9 
Tagging sonnaraon/waspro-signed-ubuntu@sha256:1e48201ccc2ab83afc435394b3bf70af0fa0055215c1e26a5da9b50a1ae367c9 as sonnaraon/waspro-signed-ubuntu:latest 
docker.io/sonnaraon/waspro-signed-ubuntu:latest 
[root@ip-192-168-86-253 ~]# docker pull sonnaraon/unsigned-ubuntu:latest 
Error: remote trust data does not exist for docker.io/sonnaraon/unsigned-ubuntu: 
notary.docker.io does not have trust data for docker.io/sonnaraon/unsigned-ubuntu 
[root@ip-192-168-86-253 ~]#&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;waspro-signed-ubuntu:latest 이미지의 경우 앞서 서명을 진행했기 때문에 정상적으로 다운로드 받아 지는 것을 확인할 수 있지만, unsigned-ubuntu:latest 이미지의 경우 서명이 되지 않은 상태의 이미지로 다운로드가 되지 않고, error가 발생하는 것을 볼 수 있다.&lt;br /&gt;위와 같이 적용할 경우 도커 이미지에 대한 서명 과정을 거쳐 레지스트리(Notary)와 이미지를 사용하는 환경을 모두 보호할 수 있다. 다만 서명은 정책적으로 차단하는 방식임을 인지하고, 근본적인 오픈소스(이미지 포함) 관리 체계를 구축하는 것은 반드시 필요하다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;지금까지는 DockerHub에 구축되어 있는 Notary 서버를 이용하여 Public 환경에 구성되어 있는 레지스트리 이미지 서명과정에 대해 알아보았다 다음으로 Private 환경에 구성되어 있는 Harbor(Notary)를 이용한 이미지 서명관리 방법에 대해 알아보자.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;Notary (by Harbor)&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Harbor는 여러 기능을 내장하고 있는 Registry이다. Docker 이미지 저장소는 물론 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Helm 차트 관리, OPA(&lt;a href=&quot;https://www.itworld.co.kr/news/160330&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span&gt;Open Policy Agent&lt;/span&gt;&lt;/a&gt;), Singularity 이미지 등과 같은 다양한 클라우드 네이티브 아티팩트를 저장할 수 있는 최초의 OCI(Open Container Initiative) 호환 오픈 소스 레지스트리이다. Harbor는 TUF와 같은 저장소 관련 서명 프레임워크를 지원하는데 바로 Notary이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;a href=&quot;https://github.com/notaryproject/notary&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span&gt;Notary&lt;/span&gt;&lt;/a&gt;는 TUF 프레임워크를 구현한 오픈소스 프레임워크로 CNCF에 Icubating 프로젝트로 관리되고 있다. &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Notary는 사용자 콘텐츠의 무결성과 최신성을 보장하기위해 필요한 메타데이터를 생성, 관리 및 배포작업을 처리한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;지금부터는 Notary를 활용하여 이미지 서명 관리 방법에 대해 알아보도록 하자.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;1. 인증서 설치 (in Harbor)&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Notary는 https 프로토콜을 사용하여 상호간 Handshake를 거쳐야 한다. 따라서 Notary를 구축하기 이전에는 반드시 인증서가 준비되어 있어야 한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;gt; 인증서 준비&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;각 사이트 또는 프로젝트에서 사용하는 인증서가 존재할 경우 해당 인증서를 활용할 수 있으며, 인증서가 존재하지 않을 경우 Self Signed 인증서를 발급받아 구축하는 것이 일반적이다. (개발환경의 경우)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;gt; CA 인증서 생성&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1630425842520&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-93-115 harbor]# openssl genrsa -out ca.key 4096
Generating RSA private key, 4096 bit long modulus
................................................................................................................................++
.....................................................................................................................++
e is 65537 (0x10001)
[root@ip-192-168-93-115 harbor]# openssl req -x509 -new -nodes -sha512 -days 3650 \
  -subj &quot;/C=KR/ST=Seoul/L=Seoul/O=example/OU=Personal/CN=www.swainno.com&quot; \
  -key ca.key \
  -out ca.crt
[root@ip-192-168-93-115 harbor]#&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;gt; 서버 인증서 생성&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1630426157139&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-93-115 harbor]# openssl genrsa -out www.swainno.com.key 4096
Generating RSA private key, 4096 bit long modulus
............................................................................................................................................................++
......................................................++
e is 65537 (0x10001)
[root@ip-192-168-93-115 harbor]# openssl req -sha512 -new \
     -subj &quot;/C=KR/ST=Seoul/L=Seoul/O=example/OU=Personal/CN=www.swainno.com&quot; \
     -key www.swainno.com.key \
     -out www.swainno.com.csr
[root@ip-192-168-93-115 harbor]# cat &amp;gt; v3.ext &amp;lt;&amp;lt;-EOF
 authorityKeyIdentifier=keyid,issuer
 basicConstraints=CA:FALSE
 keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
 extendedKeyUsage = serverAuth
 subjectAltName = @alt_names
 
 [alt_names]
 DNS.1=www.swainno.com
 DNS.2=swainno.com
 DNS.3=ip-192-168-93-115.ap-northeast-2.compute.internal
EOF
[root@ip-192-168-93-115 harbor]# openssl x509 -req -sha512 -days 3650 \
     -extfile v3.ext \
     -CA ca.crt -CAkey ca.key -CAcreateserial \
     -in www.swainno.com.csr \
     -out www.swainno.com.crt
Signature ok
subject=/C=KR/ST=Seoul/L=Seoul/O=example/OU=Personal/CN=www.swainno.com
Getting CA Private Key
[root@ip-192-168-93-115 harbor]#&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;gt; Docker에 인증서 반영&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1630427271915&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-93-115 harbor]# openssl x509 -inform PEM -in www.swainno.com.crt -out www.swainno.com.cert
[root@ip-192-168-93-115 harbor]# mkdir -p /etc/docker/certs.d/www.swainno.com:8443
[root@ip-192-168-93-115 harbor]# cd /etc/docker/certs.d/www.swainno.com:8443
[root@ip-192-168-93-115 www.swainno.com:8443]# pwd
/etc/docker/certs.d/www.swainno.com:8443
[root@ip-192-168-93-115 www.swainno.com:8443]# ls -la
total 24
drwxr-xr-x 2 root root  143 Aug 31 16:21 .
drwxr-xr-x 3 root root   34 Aug 31 14:55 ..
-rw-r--r-- 1 root root 2037 Aug 31 14:55 ca.crt
-rw-r--r-- 1 root root 3243 Aug 31 16:21 ca.key
-rw-r--r-- 1 root root 2163 Aug 31 14:55 www.swainno.com.cert
-rw-r--r-- 1 root root 2163 Aug 31 16:21 www.swainno.com.crt
-rw-r--r-- 1 root root 1825 Aug 31 16:21 www.swainno.com.csr
-rw-r--r-- 1 root root 3243 Aug 31 14:55 www.swainno.com.key
[root@ip-192-168-93-115 www.swainno.com:8443]#&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;디렉토리 생성 및 인증서를 복사한 후 systemctl restart docker 도커를 재기동한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;2. Harbor Notary 구성&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;gt; Harbor 설정&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1630427544315&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[harbor.yml]
...
...
# https related config
https:
  # https port for harbor, default is 443
  port: 8443
  # The path of cert and key files for nginx
  certificate: /root/harbor/harbor/www.swainno.com.crt
  private_key: /root/harbor/harbor/www.swainno.com.key
...
...&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Notary를 기동하기 위해서는 반드시 https가 설정되어 있어야 한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;gt; Harbor 설정 반영&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1630427588019&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-93-115 harbor]# ./prepare --with-chartmuseum --with-notary --with-trivy
prepare base dir is set to /root/harbor/harbor
Clearing the configuration file: /config/portal/nginx.conf
Clearing the configuration file: /config/log/logrotate.conf
Clearing the configuration file: /config/log/rsyslog_docker.conf
Clearing the configuration file: /config/nginx/conf.d/notary.upstream.conf
Clearing the configuration file: /config/nginx/conf.d/notary.server.conf
Clearing the configuration file: /config/nginx/nginx.conf
Clearing the configuration file: /config/core/env
Clearing the configuration file: /config/core/app.conf
Clearing the configuration file: /config/registry/passwd
Clearing the configuration file: /config/registry/config.yml
Clearing the configuration file: /config/registryctl/env
Clearing the configuration file: /config/registryctl/config.yml
Clearing the configuration file: /config/db/env
Clearing the configuration file: /config/jobservice/env
Clearing the configuration file: /config/jobservice/config.yml
Clearing the configuration file: /config/chartserver/env
Clearing the configuration file: /config/trivy-adapter/env
Clearing the configuration file: /config/notary/server-config.postgres.json
Clearing the configuration file: /config/notary/server_env
Clearing the configuration file: /config/notary/signer_env
Clearing the configuration file: /config/notary/signer-config.postgres.json
Generated configuration file: /config/portal/nginx.conf
Generated configuration file: /config/log/logrotate.conf
Generated configuration file: /config/log/rsyslog_docker.conf
Generated configuration file: /config/nginx/nginx.conf
Generated configuration file: /config/core/env
Generated configuration file: /config/core/app.conf
Generated configuration file: /config/registry/config.yml
Generated configuration file: /config/registryctl/env
Generated configuration file: /config/registryctl/config.yml
Generated configuration file: /config/db/env
Generated configuration file: /config/jobservice/env
Generated configuration file: /config/jobservice/config.yml
loaded secret from file: /data/secret/keys/secretkey
Copying nginx configuration file for notary
Generated configuration file: /config/nginx/conf.d/notary.upstream.conf
Generated configuration file: /config/nginx/conf.d/notary.server.conf
Generated configuration file: /config/notary/server-config.postgres.json
Generated configuration file: /config/notary/server_env
loaded secret from file: /data/secret/keys/defaultalias
Generated configuration file: /config/notary/signer_env
Generated configuration file: /config/notary/signer-config.postgres.json
Generated configuration file: /config/trivy-adapter/env
Generated configuration file: /config/chartserver/env
Generated configuration file: /compose_location/docker-compose.yml
Clean up the input dir
[root@ip-192-168-93-115 harbor]#&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;gt; Harbor 재기동&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1630427634067&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-93-115 harbor]# docker-compose down -v
Stopping harbor-jobservice ... done
Stopping nginx             ... done
Stopping notary-server     ... done
Stopping harbor-core       ... done
Stopping notary-signer     ... done
Stopping trivy-adapter     ... done
Stopping redis             ... done
Stopping registryctl       ... done
Stopping harbor-db         ... done
Stopping harbor-portal     ... done
Stopping harbor-log        ... done
Removing harbor-jobservice ... done
Removing nginx             ... done
Removing notary-server     ... done
Removing harbor-core       ... done
Removing notary-signer     ... done
Removing trivy-adapter     ... done
Removing redis             ... done
Removing chartmuseum       ... done
Removing registryctl       ... done
Removing harbor-db         ... done
Removing harbor-portal     ... done
Removing registry          ... done
Removing harbor-log        ... done
Removing network harbor_harbor
Removing network harbor_harbor-notary
Removing network harbor_harbor-chartmuseum
Removing network harbor_notary-sig
[root@ip-192-168-93-115 harbor]# docker-compose up -d
Creating network &quot;harbor_harbor&quot; with the default driver
Creating network &quot;harbor_harbor-notary&quot; with the default driver
Creating network &quot;harbor_harbor-chartmuseum&quot; with the default driver
Creating network &quot;harbor_notary-sig&quot; with the default driver
Creating harbor-log ... done
Creating chartmuseum   ... done
Creating harbor-portal ... done
Creating harbor-db     ... done
Creating registryctl   ... done
Creating redis         ... done
Creating registry      ... done
Creating trivy-adapter ... done
Creating harbor-core   ... done
Creating notary-signer ... done
Creating notary-server     ... done
Creating nginx             ... done
Creating harbor-jobservice ... done
[root@ip-192-168-93-115 harbor]#&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;gt; 로그인 테스트 및 Harbor UI 접속&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1630427775995&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-93-115 harbor]# docker login www.swainno.com:8443
Username: admin
Password: 
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded
[root@ip-192-168-93-115 harbor]#&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;아래는 Notary가 포함되지 않은 Harbor 대시보드 이미지 정보이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1301&quot; data-origin-height=&quot;706&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7cmWK/btrd1eLzooq/W9FwkyKGEKwpaRtVWhOl01/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7cmWK/btrd1eLzooq/W9FwkyKGEKwpaRtVWhOl01/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7cmWK/btrd1eLzooq/W9FwkyKGEKwpaRtVWhOl01/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7cmWK%2Fbtrd1eLzooq%2FW9FwkyKGEKwpaRtVWhOl01%2Fimg.png&quot; data-origin-width=&quot;1301&quot; data-origin-height=&quot;706&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;다음은 Notary를 포함한 Harbor의 대시보드 이미지 정보이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1299&quot; data-origin-height=&quot;696&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLpTZS/btrd03KjRuN/1YegTqFQABr60mb5bnXZtK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLpTZS/btrd03KjRuN/1YegTqFQABr60mb5bnXZtK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLpTZS/btrd03KjRuN/1YegTqFQABr60mb5bnXZtK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLpTZS%2Fbtrd03KjRuN%2F1YegTqFQABr60mb5bnXZtK%2Fimg.png&quot; data-origin-width=&quot;1299&quot; data-origin-height=&quot;696&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;위와 같이 Signed 여부를 확인할 수 있는 Column이 추가된 것을 볼 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;마찬가지로 https로 대시보드에 로그인이 가능한 것을 볼 수 있다. 개발환경에서 신뢰할 수 없는 인증서라는 경고 메시지가 발생할 수 있으나, 직접 발급하였기 때문에 발생하는 것으로 개발환경에서는 무시하고 테스트를 진행하도록 하자.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;# 참조 URL&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;a href=&quot;https://docs.docker.com/engine/security/trust/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://docs.docker.com/engine/security/trust/&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1630803878319&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;Content trust in Docker&quot; data-og-description=&quot; &quot; data-og-host=&quot;docs.docker.com&quot; data-og-source-url=&quot;https://docs.docker.com/engine/security/trust/&quot; data-og-url=&quot;https://docs.docker.com/engine/security/trust/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bekmxk/hyLuXpjGDY/YBHHQ5etKkLgXnoBNBCLYk/img.png?width=129&amp;amp;height=128&amp;amp;face=0_0_129_128,https://scrap.kakaocdn.net/dn/ezdMq/hyLuSnZS9p/Qj1Z9jIlAaMVp9sclB1EvK/img.png?width=950&amp;amp;height=500&amp;amp;face=0_0_950_500&quot;&gt;&lt;a href=&quot;https://docs.docker.com/engine/security/trust/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.docker.com/engine/security/trust/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bekmxk/hyLuXpjGDY/YBHHQ5etKkLgXnoBNBCLYk/img.png?width=129&amp;amp;height=128&amp;amp;face=0_0_129_128,https://scrap.kakaocdn.net/dn/ezdMq/hyLuSnZS9p/Qj1Z9jIlAaMVp9sclB1EvK/img.png?width=950&amp;amp;height=500&amp;amp;face=0_0_950_500');&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;Content trust in Docker&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.docker.com&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: 'Noto Serif KR';&quot;&gt;&lt;a href=&quot;https://docs.docker.com/engine/security/trust/trust_delegation/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://docs.docker.com/engine/security/trust/trust_delegation/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1630803892526&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;Delegations for content trust&quot; data-og-description=&quot; &quot; data-og-host=&quot;docs.docker.com&quot; data-og-source-url=&quot;https://docs.docker.com/engine/security/trust/trust_delegation/&quot; data-og-url=&quot;https://docs.docker.com/engine/security/trust/trust_delegation/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/GF5NP/hyLuVrtW6l/MFlPEHQlNZTkL7hprp3UCK/img.png?width=129&amp;amp;height=128&amp;amp;face=0_0_129_128,https://scrap.kakaocdn.net/dn/bs6Rf5/hyLuZObTF1/6OQY29PVr1ByAcapWGb0k1/img.png?width=950&amp;amp;height=500&amp;amp;face=0_0_950_500&quot;&gt;&lt;a href=&quot;https://docs.docker.com/engine/security/trust/trust_delegation/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.docker.com/engine/security/trust/trust_delegation/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/GF5NP/hyLuVrtW6l/MFlPEHQlNZTkL7hprp3UCK/img.png?width=129&amp;amp;height=128&amp;amp;face=0_0_129_128,https://scrap.kakaocdn.net/dn/bs6Rf5/hyLuZObTF1/6OQY29PVr1ByAcapWGb0k1/img.png?width=950&amp;amp;height=500&amp;amp;face=0_0_950_500');&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;Delegations for content trust&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.docker.com&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: 'Noto Serif KR';&quot;&gt;&lt;a href=&quot;https://goharbor.io/docs/2.1.0/install-config/configure-https/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://goharbor.io/docs/2.1.0/install-config/configure-https/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1630803907755&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;documentation&quot; data-og-title=&quot;Harbor &amp;ndash; Configure HTTPS Access to Harbor&quot; data-og-description=&quot;Configure HTTPS Access to Harbor&quot; data-og-host=&quot;goharbor.io&quot; data-og-source-url=&quot;https://goharbor.io/docs/2.1.0/install-config/configure-https/&quot; data-og-url=&quot;https://goharbor.io/docs/2.1.0/install-config/configure-https/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://goharbor.io/docs/2.1.0/install-config/configure-https/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://goharbor.io/docs/2.1.0/install-config/configure-https/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&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;Harbor &amp;ndash; Configure HTTPS Access to Harbor&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Configure HTTPS Access to Harbor&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;goharbor.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;</description>
      <category>③ 클라우드/ⓓ Docker</category>
      <category>docker notary</category>
      <category>docker trust</category>
      <category>docker trust key</category>
      <category>docker trust sign</category>
      <category>docker trust signer</category>
      <category>harbor notary</category>
      <category>notary 인증서</category>
      <category>이미지 서명</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/716</guid>
      <comments>https://waspro.tistory.com/716#entry716comment</comments>
      <pubDate>Mon, 30 Aug 2021 01:01:50 +0900</pubDate>
    </item>
    <item>
      <title>OpenSource Heimdall 통합 대시보드 구성하기</title>
      <link>https://waspro.tistory.com/713</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;서론&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;마이크로서비스 환경에서 폴리그랏의 의미는 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&quot;언어의 종속성만을 없애는 것이 아닌 기반 인프라와 소프트웨어를 입맛에 맞게 선정하여 대상의 폭을 넓혀갈 수 있음&quot;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;으로 해석할 수 있다. 이는 서비스 최적화 환경을 구성한다는 점에서 장점이 있고, 특히 많은 오픈소스 소프트웨어를 무상으로 활용할 있다는 데에 의미가 크다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;다양한 오픈소스 소프트웨어들은 많은 프로젝트에서 선호되고 있지만, 반대로 여러 문제를 야기하기도 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;가장 큰 문제는 유지보수이다. 오픈소스이다보니, 프로젝트 구성원 내에서 운영/유지보수가 가능한 경우가 아니라면, 장애나 주요 이벤트에 대응이 어려울 수 있다. 각 사에서는 이와 같은 문제를 해소해 나가기 위해 오픈소스 소프트웨어를 담당하는 팀을 만들고, 지속적으로 학습해 나가는 방안을 마련하고 있지만, 그 기술력을 높이기 위해서는 내재화가 선행되어야 하고, 이는 많은 시간이 소모될 수 밖에 없다. 결국은 오픈소스에서 제공하는 대시보드를 이해하고, 주요 기능에 대해서만 내재화를 진행하여 고도화 해 나가는 경우가 다반사이다. 이때 대부분의 회사에서 비슷하게 경험하고 있는 이슈가 있는데 바로 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;오픈소스들이 제공하는 다양한 대시보드의 늪에 갇혀 허우적대는 경우이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Prometheus Dashboard&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Grafana&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Kiali&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Zipkin&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Kibana&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Redis Insight&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Kafka CMAK&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;CA API Gateway Dashboard&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Developer Portal&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Kubernetes Dashboard&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Jenkins&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;GitLab&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Nexus&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Harbor&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;APM&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;SMS&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;그 밖에 프로젝트에서 사용하는 여러 포털&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;등을 MSA파트에서 사용했고, 대부분은 오픈소스 기반으로 제공하는 대시보드이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;물론 이러한 대시보드를 어떻게 잘 다루고 활용할 것이냐는 그 회사자체의 거버넌스로 접근해야 할 문제이긴 하지만, 본 포스팅에서는 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;OpenSource인 Heimdall 대시보드를 활용하여 여러 대시보드들을 통합 관리할 수 있는 손쉬운 과정에 대해 알아보도록 하자.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Heimdall 공식홈페이지 : &lt;a href=&quot;https://heimdall.site/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://heimdall.site/&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1629525158608&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;Heimdall Application Dashboard&quot; data-og-description=&quot;Generic Apps One of the benefits to Heimdall is you can add a link to absolutely anything, whether it's intrinsically supported or not. With a generic item, you just fill in the name, background colour, add an icon if you want (if you don't a default Heimd&quot; data-og-host=&quot;heimdall.site&quot; data-og-source-url=&quot;https://heimdall.site/&quot; data-og-url=&quot;https://heimdall.site/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://heimdall.site/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://heimdall.site/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&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;Heimdall Application Dashboard&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Generic Apps One of the benefits to Heimdall is you can add a link to absolutely anything, whether it's intrinsically supported or not. With a generic item, you just fill in the name, background colour, add an icon if you want (if you don't a default Heimd&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;heimdall.site&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;포스팅 순서&lt;/span&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;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Heimdall 설치&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Heimdall 커스터마이징&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;본론&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Heimdall 은 모든 애플리케이션과 자주 방문하는 링크를 한 페이지로 정리하는 북마크와 같은 기능을 오픈소스로 구현한 소프트웨어이다. Naver, Daum, Google 등의 웹포털사이트나 즐겨찾는 페이지를 추가하여 나만의 북마크 환경을 구성할 수 있다. 지금부터 Heimdall을 설치해 보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #006dd7;&quot;&gt;1) Heimdall 설치&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Heimdall은 두 과정만 거치면 설치가 완료된다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;docker volume 생성&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;docker run 기동&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1) docker volume 생성&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1629513162686&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker volume create heimdall&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Heimdall 구성 정보를 영구적으로 저장하기 위해 볼륨을 생성한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1629513172022&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-86-253 heimdall]# docker volume create heimdall
heimdall
[root@ip-192-168-86-253 heimdall]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;생성한 볼륨은 이후 container 내부 config 디렉토리를 저장하여 재기동 후에도 동일 상태를 유지하기 위함이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1629514750566&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-86-253 heimdall]# docker volume ls
DRIVER    VOLUME NAME
local     heimdall
local     netdatacache
local     netdataconfig
local     netdatalib
[root@ip-192-168-86-253 heimdall]# docker volume inspect heimdall
[
    {
        &quot;CreatedAt&quot;: &quot;2021-08-21T02:57:14Z&quot;,
        &quot;Driver&quot;: &quot;local&quot;,
        &quot;Labels&quot;: {},
        &quot;Mountpoint&quot;: &quot;/var/lib/docker/volumes/heimdall/_data&quot;,
        &quot;Name&quot;: &quot;heimdall&quot;,
        &quot;Options&quot;: {},
        &quot;Scope&quot;: &quot;local&quot;
    }
]
[root@ip-192-168-86-253 heimdall]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;아래 기동이 완료된 이후 다음과 같이 확인해 보면 실제로 볼륨이 동기화 되어 로컬에 저장되고 있는 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1629515386834&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[Internal Heimdall Container]
[root@ip-192-168-86-253 heimdall]# docker exec -it heimdall /bin/bash
root@894baa6ea919:/# ls
app  bin  config  defaults  dev  docker-mods  etc  home  init  lib  libexec  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
root@894baa6ea919:/# cd config/
root@894baa6ea919:/config# ls
custom-cont-init.d  custom-services.d  keys  log  nginx  php  www
root@894baa6ea919:/config# 

[Local Directory]
[root@ip-192-168-86-253 heimdall]# docker volume inspect heimdall
[
    {
        &quot;CreatedAt&quot;: &quot;2021-08-21T02:57:14Z&quot;,
        &quot;Driver&quot;: &quot;local&quot;,
        &quot;Labels&quot;: {},
        &quot;Mountpoint&quot;: &quot;/var/lib/docker/volumes/heimdall/_data&quot;,
        &quot;Name&quot;: &quot;heimdall&quot;,
        &quot;Options&quot;: {},
        &quot;Scope&quot;: &quot;local&quot;
    }
]
[root@ip-192-168-86-253 heimdall]# cd /var/lib/docker/volumes/heimdall/_data
[root@ip-192-168-86-253 _data]# ls
custom-cont-init.d  custom-services.d  keys  log  nginx  php  www
[root@ip-192-168-86-253 _data]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2) docker run 기동&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1629513145590&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker run \
--name=heimdall \
-e PUID=1000 \
-e PGID=1000 \
-e TZ=america/new_york \
-p 80:80 \
-p 443:443 \
-v heimdall:/config \
--restart unless-stopped \
linuxserver/heimdall&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;볼륨이 생성되면 도커 이미지를 다운로드하고 기동한다. &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;옵션정보는&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 130px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 28.8372%; height: 20px; text-align: center;&quot;&gt;&lt;span style=&quot;color: #ffffff; font-family: 'Noto Serif KR';&quot;&gt;옵션&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 71.1628%; height: 20px; text-align: center;&quot;&gt;&lt;span style=&quot;color: #ffffff; font-family: 'Noto Serif KR';&quot;&gt;설명&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 28.8372%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;-p 80:80&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 71.1628%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;노드 80 포트 &amp;gt; 도커 컨테이너 80 포트 라우팅&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 28.8372%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;-p 443:443&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 71.1628%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;노드 443 포트 &amp;gt; 도커 컨테이너 443 포트 라우팅&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 28.8372%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;-v heimdall:/config&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 71.1628%; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;heimdall 도커볼륨 = 도커 컨테이너 /config 디렉토리 동기화&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 28.8372%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;-e TZ=america/new_york&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 71.1628%; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;타임존 설정&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 28.8372%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;-e PGID=1000&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 71.1628%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Process Group ID&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 10px;&quot;&gt;
&lt;td style=&quot;width: 28.8372%; height: 10px;&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;-e PUID=1000&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 71.1628%; height: 10px;&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Process User ID&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre id=&quot;code_1629513028935&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-86-253 heimdall]# docker run \
&amp;gt; --name=heimdall \
&amp;gt; -e PUID=1000 \
&amp;gt; -e PGID=1000 \
&amp;gt; -e TZ=america/new_york \
&amp;gt; -p 80:80 \
&amp;gt; -p 443:443 \
&amp;gt; -v heimdall:/config \
&amp;gt; --restart unless-stopped \
&amp;gt; linuxserver/heimdall
Unable to find image 'linuxserver/heimdall:latest' locally
latest: Pulling from linuxserver/heimdall
564738e1d4e3: Pull complete 
05602526fc2e: Pull complete 
b440ce367f41: Pull complete 
46f9403880e3: Pull complete 
1e6aece89c58: Pull complete 
41dae65a5d47: Pull complete 
ad2806e5005c: Pull complete 
12fbd2f2bfb9: Pull complete 
d23f641ab4b3: Pull complete 
455b29562127: Pull complete 
Digest: sha256:a27beaa5de9cec355f29e44ab8310a36fff47f351711b4ffe2e11c237d14ffd4
Status: Downloaded newer image for linuxserver/heimdall:latest
[s6-init] making user provided files available at /var/run/s6/etc...exited 0.
[s6-init] ensuring user provided files have correct perms...exited 0.
[fix-attrs.d] applying ownership &amp;amp; permissions fixes...
[fix-attrs.d] done.
[cont-init.d] executing container initialization scripts...
[cont-init.d] 01-envfile: executing... 
[cont-init.d] 01-envfile: exited 0.
[cont-init.d] 10-adduser: executing... 

-------------------------------------
          _         ()
         | |  ___   _    __
         | | / __| | |  /  \ 
         | | \__ \ | | | () |
         |_| |___/ |_|  \__/


Brought to you by linuxserver.io
-------------------------------------

To support LSIO projects visit:
https://www.linuxserver.io/donate/
-------------------------------------
GID/UID
-------------------------------------

User uid:    1000
User gid:    1000
-------------------------------------

[cont-init.d] 10-adduser: exited 0.
[cont-init.d] 20-config: executing... 
[cont-init.d] 20-config: exited 0.
[cont-init.d] 30-keygen: executing... 
generating self-signed keys in /config/keys, you can replace these with your own keys if required
Generating a RSA private key
..+++++
...........................................................................................+++++
writing new private key to '/config/keys/cert.key'
-----
[cont-init.d] 30-keygen: exited 0.
[cont-init.d] 50-config: executing... 
New container detected, installing Heimdall
Creating app key. This may take a while on slower systems
Application key set successfully.
Setting permissions
[cont-init.d] 50-config: exited 0.
[cont-init.d] 90-custom-folders: executing... 
[cont-init.d] 90-custom-folders: exited 0.
[cont-init.d] 99-custom-files: executing... 
[custom-init] no custom files found exiting...
[cont-init.d] 99-custom-files: exited 0.
[cont-init.d] done.
[services.d] starting services
[services.d] done.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 기동이 완료되면 Heimdall 접속이 가능한 상태가 된다. 이제 http://노드IP로 접속하여 Heimdall을 커스터마이징해 보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #006dd7;&quot;&gt;2) Heimdall 커스터마이징&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;http://SERVERIP:PORT 로 접속하면 아래와 같은 초기 화면을 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1560&quot; data-origin-height=&quot;871&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVqTaF/btrcQgpie1p/lgDddVBxYVmCFzIXBEEcWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVqTaF/btrcQgpie1p/lgDddVBxYVmCFzIXBEEcWK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVqTaF/btrcQgpie1p/lgDddVBxYVmCFzIXBEEcWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVqTaF%2FbtrcQgpie1p%2FlgDddVBxYVmCFzIXBEEcWK%2Fimg.png&quot; data-origin-width=&quot;1560&quot; data-origin-height=&quot;871&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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: 'Noto Serif KR'; color: #000000;&quot;&gt;대시보드 메뉴는 오른쪽 하단의 총 6개 항목으로 구성되어 있다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;a. Add Items&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;먼저 네번째 메뉴인 Items를 선택하여 새로운 북마크를 추가해 보도록 하자. &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ckUtzh/btrcMFjGOv3/qciaXyQuv9qMkMBWqSFri1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ckUtzh/btrcMFjGOv3/qciaXyQuv9qMkMBWqSFri1/img.png&quot; data-origin-width=&quot;1561&quot; data-origin-height=&quot;871&quot; style=&quot;width: 48.7441%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ckUtzh/btrcMFjGOv3/qciaXyQuv9qMkMBWqSFri1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FckUtzh%2FbtrcMFjGOv3%2FqciaXyQuv9qMkMBWqSFri1%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;1561&quot; height=&quot;871&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vzPc5/btrcNMbrwkj/ZnyFpW92kTOuuHSse2ziE1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vzPc5/btrcNMbrwkj/ZnyFpW92kTOuuHSse2ziE1/img.png&quot; data-origin-width=&quot;1560&quot; data-origin-height=&quot;847&quot; style=&quot;width: 50.0931%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vzPc5/btrcNMbrwkj/ZnyFpW92kTOuuHSse2ziE1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvzPc5%2FbtrcNMbrwkj%2FZnyFpW92kTOuuHSse2ziE1%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;1560&quot; height=&quot;847&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;네이버 북마크를 추가하는 과정이다. Application Name, Application Type, Colour, URL, Tags를 등록하고 Upload File을 통해 변경하고자 하는 로고 이미지를 반영한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;상단의 PINNED를 활성화 할 경우 첫번째 메뉴 항목이 자동으로 반영되어 메인 화면에 노출된다. PINNED 여부 결정 후 SAVE 버튼을 선택한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1561&quot; data-origin-height=&quot;848&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DoSUy/btrcNMvJqlo/12begihJhA42F19K8aZkQk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DoSUy/btrcNMvJqlo/12begihJhA42F19K8aZkQk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DoSUy/btrcNMvJqlo/12begihJhA42F19K8aZkQk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDoSUy%2FbtrcNMvJqlo%2F12begihJhA42F19K8aZkQk%2Fimg.png&quot; data-origin-width=&quot;1561&quot; data-origin-height=&quot;848&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 첫번째 북마크가 등록되었다. 이와 동일한 방식으로 대시보드를 추가해 보자.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1561&quot; data-origin-height=&quot;848&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/caUIwQ/btrcLBu9ZpO/kq0C5JCsjWbinkcF2WV8kK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/caUIwQ/btrcLBu9ZpO/kq0C5JCsjWbinkcF2WV8kK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/caUIwQ/btrcLBu9ZpO/kq0C5JCsjWbinkcF2WV8kK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcaUIwQ%2FbtrcLBu9ZpO%2Fkq0C5JCsjWbinkcF2WV8kK%2Fimg.png&quot; data-origin-width=&quot;1561&quot; data-origin-height=&quot;848&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;b. Pinned Items&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;첫번째 메뉴인 Pinned Items을 선택하면, Pin item to dashboard 메뉴활성화와 추가된 Item을 드래그앤 드랍이로 편집할 수 있도록 화면이 변경된다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1562&quot; data-origin-height=&quot;848&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgsLb1/btrcIU9HM3g/Xqb9518OvKmFsk9oTdXLj0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgsLb1/btrcIU9HM3g/Xqb9518OvKmFsk9oTdXLj0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgsLb1/btrcIU9HM3g/Xqb9518OvKmFsk9oTdXLj0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcgsLb1%2FbtrcIU9HM3g%2FXqb9518OvKmFsk9oTdXLj0%2Fimg.png&quot; data-origin-width=&quot;1562&quot; data-origin-height=&quot;848&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;c. Settings&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;다음으로 Settings를 구성해보자.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1537&quot; data-origin-height=&quot;910&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mYaYj/btrcOOs6hYK/supcBDG3ZOsm4yL5XdMECK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mYaYj/btrcOOs6hYK/supcBDG3ZOsm4yL5XdMECK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mYaYj/btrcOOs6hYK/supcBDG3ZOsm4yL5XdMECK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmYaYj%2FbtrcOOs6hYK%2FsupcBDG3ZOsm4yL5XdMECK%2Fimg.png&quot; data-origin-width=&quot;1537&quot; data-origin-height=&quot;910&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 몇가지 기본 구성이 가능하다. (언어, 배경, 검색, 링크위치 등)&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;d. Users&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;마지막으로 User 관리이다. 프로젝트를 진행하다보면, 특정 개발자에게 특정 대시보드 접근 권한만 오픈하고자 할 경우가 있다. 각 사용자 별로 접근 권한이 필요한 대시보드를 북마크로 제공하여 접근할 수 있도록 편의 구성이 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9yI3d/btrcMZ3tDAb/nYwtdk4IsYEwaiMKvh7Pek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9yI3d/btrcMZ3tDAb/nYwtdk4IsYEwaiMKvh7Pek/img.png&quot; data-origin-width=&quot;1537&quot; data-origin-height=&quot;912&quot; style=&quot;width: 49.3804%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9yI3d/btrcMZ3tDAb/nYwtdk4IsYEwaiMKvh7Pek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9yI3d%2FbtrcMZ3tDAb%2FnYwtdk4IsYEwaiMKvh7Pek%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;1537&quot; height=&quot;912&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdmlWp/btrcLBIMR9m/6Ko98wlqW9dblxNWBPJvl1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdmlWp/btrcLBIMR9m/6Ko98wlqW9dblxNWBPJvl1/img.png&quot; data-origin-width=&quot;1536&quot; data-origin-height=&quot;910&quot; style=&quot;width: 49.4568%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdmlWp/btrcLBIMR9m/6Ko98wlqW9dblxNWBPJvl1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdmlWp%2FbtrcLBIMR9m%2F6Ko98wlqW9dblxNWBPJvl1%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;1536&quot; height=&quot;910&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;기본으로 추가되어 있는 Super User인 admin 외에 사용자를 2개 추가한다. son.nara의 경우 Password는 설정하였으나, Public Access를 허용한 계정이며, cns의 경우 Private Access로 설정한 계정이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Public Access를 허용한 계정의 경우 그룹으로 관리되며, Private Access로 관리되는 계정의 경우 유저로 관리할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1538&quot; data-origin-height=&quot;909&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cn8jkS/btrcOd0Zht3/RJzzMqaE19PX97qhsx074K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cn8jkS/btrcOd0Zht3/RJzzMqaE19PX97qhsx074K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cn8jkS/btrcOd0Zht3/RJzzMqaE19PX97qhsx074K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcn8jkS%2FbtrcOd0Zht3%2FRJzzMqaE19PX97qhsx074K%2Fimg.png&quot; data-origin-width=&quot;1538&quot; data-origin-height=&quot;909&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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: 'Noto Serif KR'; color: #000000;&quot;&gt;왼쪽 하단의 Switch User를 클릭하면, 아래와 같이 사용자 별 접근이 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eH03u7/btrcMDM1fTS/13aG6ckxJE5L6JXP9ZLz7K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eH03u7/btrcMDM1fTS/13aG6ckxJE5L6JXP9ZLz7K/img.png&quot; data-origin-width=&quot;1537&quot; data-origin-height=&quot;908&quot; style=&quot;width: 32.5391%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eH03u7/btrcMDM1fTS/13aG6ckxJE5L6JXP9ZLz7K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeH03u7%2FbtrcMDM1fTS%2F13aG6ckxJE5L6JXP9ZLz7K%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;1537&quot; height=&quot;908&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7vEkV/btrcNJr9OS3/PeWfkQ1ubLbHEkZzBkn5Dk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7vEkV/btrcNJr9OS3/PeWfkQ1ubLbHEkZzBkn5Dk/img.png&quot; data-origin-width=&quot;1538&quot; data-origin-height=&quot;909&quot; style=&quot;width: 32.5244%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7vEkV/btrcNJr9OS3/PeWfkQ1ubLbHEkZzBkn5Dk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7vEkV%2FbtrcNJr9OS3%2FPeWfkQ1ubLbHEkZzBkn5Dk%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;1538&quot; height=&quot;909&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CBASt/btrcNLKpjhn/7KKdCrbtpFsQgLsZ0waxZk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CBASt/btrcNLKpjhn/7KKdCrbtpFsQgLsZ0waxZk/img.png&quot; data-origin-width=&quot;1537&quot; data-origin-height=&quot;906&quot; style=&quot;width: 32.6109%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CBASt/btrcNLKpjhn/7KKdCrbtpFsQgLsZ0waxZk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCBASt%2FbtrcNLKpjhn%2F7KKdCrbtpFsQgLsZ0waxZk%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;1537&quot; height=&quot;906&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;각 유저별 특징은 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 26.5116%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;유저&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 73.4884%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;설명&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 26.5116%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;admin&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 73.4884%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Super User&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 26.5116%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;son.nara&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 73.4884%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Developer, Operator 등 그룹에게 할당하기 유용한 단위 - 북마크 Public 공개. User 추가 권한은 없으며, 나머지 권한은 계정 내에 적용 가능(비밀번호 접속)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 26.5116%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;cns&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 73.4884%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;개별 유저에게 권한을 부여하기 유용한 단위 - 북마크 Private 공개(비밀번호 접속).&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;결론&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;오픈소스 소프트웨어의 활용이 확대되어 감에 따라 여러가지 지원도구들이 등장하고 있다. 지원도구들은 대체로 구축과 사용이 간편하기 때문에 접근성이 높다는 특징이 있다. &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;오늘 살펴본 Heimdall 역시 손쉽게 구축이 가능하고 OutPut을 빠르게 확인할 수 있다는 특징은 이와 같은 맥락이라 볼 수 있다. &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Heimdall에서 제공하는 대시보드는 크게 3가지 형태를 갖고 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;먼저 None 타입의 대시보드이다. None 타입의 대시보드는 Heimdall에서 별도로 관리하지 않는 대시보드이다. 예를 들어 상단의 북마크 추가 중 Naver와 같이 공식으로 등록되어 있지 않은 프로젝트들을 의미한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;두번째는 Foundation Apps이다.(&lt;a href=&quot;https://apps.heimdall.site/applications/foundation&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://apps.heimdall.site/applications/foundation&lt;/a&gt;) &lt;span style=&quot;color: #24292e;&quot;&gt;Foundation App은 아이콘을 자동으로 채우고 타일의 기본 색상을 제공한다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #24292e;&quot;&gt;세번째는 Enhanced Apps이다.(&lt;a href=&quot;https://apps.heimdall.site/applications/enhanced&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://apps.heimdall.site/applications/enhanced&lt;/a&gt;) &lt;span style=&quot;color: #24292e;&quot;&gt;Enhanced App&lt;/span&gt;&lt;span style=&quot;color: #24292e;&quot;&gt;을 사용하면 API를 통해 세부 정보를 확인할 수 있어 Heimdall 대시보드에서 직접 실시간 통계를 볼 수 있다. 대표적으로 Jaeger나 Transmission 등의 통계정보를 대시보드에 접근하지 않고도 확인할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;앞서 살펴본 유저 접근 권한과 함께 대시보드에서 제공하는 Foundation Apps / Enhanced Apps를 조합하여 관리할 경우 프로젝트 내 대시보드를 효과적으로 관리할 수 있지 않을까 싶다.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>⑦ Open Source Software</category>
      <category>heimdall</category>
      <category>opensource heimdall</category>
      <category>오픈소스 대시보드</category>
      <category>오픈소스 북마크</category>
      <category>오픈소스 통합대시보드</category>
      <category>오픈소스 헤임달</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/713</guid>
      <comments>https://waspro.tistory.com/713#entry713comment</comments>
      <pubDate>Sat, 21 Aug 2021 10:46:12 +0900</pubDate>
    </item>
    <item>
      <title>Netdata를 활용한 EKS Observability and Analysis</title>
      <link>https://waspro.tistory.com/712</link>
      <description>&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;개요&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이번 포스팅에서는 Kubernetes 오픈소스 계열 중 Observability and Analysis 분야에서 높은 지지도를 얻고 있는 Netdata에 대해 알아보도록 하자.&lt;/span&gt;&lt;br&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Netdata는 대표적인 Telemetry 솔루션인 Prometheus보다 CNCF 내에서 더 높은 별점을 얻고 있는 오픈소스로 실시간 성능 모니터링을 위해 유용하게 활용되고 있다.&lt;/span&gt;&lt;br&gt;간결한 구성만으로&lt;span style=&quot;color: #000000;&quot;&gt; 시스템, 하드웨어, 컨테이너 및 애플리케이션에서 수천 개의 메트릭을 동시에 수집할 수 있다. 대부분의 Linux(Ubuntu, Debian, CentOS 등), 컨테이너 플랫폼(Kubernetes 클러스터, Docker) 및 기타 여러 운영 체제(FreeBSD, macOS)에 Netdata를 설치할 수 있다.&lt;br&gt;&lt;/span&gt;&lt;br&gt;&lt;span style=&quot;color: #000000;&quot;&gt;지금부터는 Amazon EKS 기반에 Netdata를 구축하여 EKS 내 Pod 모니터링 방법에 대해 알아보도록 하자.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot;&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;포스팅 순서&lt;/span&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Netdata 구축&lt;/span&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;사전 준비사항&lt;/span&gt;&lt;/li&gt; 
   &lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Netdata 설치&lt;/span&gt;&lt;/li&gt; 
   &lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;EKS 연동&lt;/span&gt;&lt;/li&gt; 
  &lt;/ul&gt; &lt;/li&gt; 
 &lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;대시보드 활용&lt;/span&gt;&lt;/li&gt; 
&lt;/ul&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot;&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;Netdata 구축&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;Netdata는 Kubernetes 만을 위한 오픈소스는 아니며, 모놀리스 환경의 On-Prem 또는 VM 환경의 SMS 솔루션으로도 활용 가능하다. 포스팅에서는 EKS에 접근 가능한 Workstation Server에 Netdata를 구축하고, Worker 노드와 EKS Pod를 함께 모니터링하는 과정에 대해 알아보도록 하자.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006DD7;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;1) 사전 준비사항&lt;/span&gt;&lt;/span&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;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;Amazon EKS&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
 &lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;EC2 Workstation&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
 &lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;Helm3&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006DD7;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;2) Netdata 설치&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;Netdata를 설치하는 방법은 매우 간단하다. 아래와 같이 도커만 설치 되어 있으면 손쉽게 Netdata를 기동할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;html&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;docker run -d --name=netdata \ -p 19999:19999 \ -v netdataconfig:/etc/netdata \ -v netdatalib:/var/lib/netdata \ -v netdatacache:/var/cache/netdata \ -v /etc/passwd:/host/etc/passwd:ro \ -v /etc/group:/host/etc/group:ro \ -v /proc:/host/proc:ro \ -v /sys:/host/sys:ro \ -v /etc/os-release:/host/etc/os-release:ro \ --restart unless-stopped \ --cap-add SYS_PTRACE \ --security-opt apparmor=unconfined \ netdata/netdata&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;기동이 완료되면 아래와 같이 Docker로 기동된 것을 확인할 수 있으며, 19999포트로 접근할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;html&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;[root@ip-192-168-86-253 ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e37ae4698a09 netdata/netdata &quot;/usr/sbin/run.sh&quot; 10 hours ago Up 10 hours (healthy) 0.0.0.0:19999-&amp;gt;19999/tcp netdata [root@ip-192-168-86-253 ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE netdata/netdata latest cdb212bb75cc 17 hours ago 331MB [root@ip-192-168-86-253 ~]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;대시보드 접근 시 다음과 같은 default 화면을 확인할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1543&quot; data-origin-height=&quot;833&quot; data-image-src=&quot;https://k.kakaocdn.net/dn/Zpz3H/btrbId3nYe1/GE3Rpp60zKu5YEXJDiBvA1/img.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Zpz3H/btrbId3nYe1/GE3Rpp60zKu5YEXJDiBvA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Zpz3H/btrbId3nYe1/GE3Rpp60zKu5YEXJDiBvA1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Zpz3H/btrbId3nYe1/GE3Rpp60zKu5YEXJDiBvA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZpz3H%2FbtrbId3nYe1%2FGE3Rpp60zKu5YEXJDiBvA1%2Fimg.png&quot; data-origin-width=&quot;1543&quot; data-origin-height=&quot;833&quot; data-image-src=&quot;https://k.kakaocdn.net/dn/Zpz3H/btrbId3nYe1/GE3Rpp60zKu5YEXJDiBvA1/img.png&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;기본으로 Netdata가 설치되어 있는 서버의 메트릭 정보를 확인할 수 있다. 주요 메트릭 정보로 CPU, MEMORY, DISK, NETWORK 등의 정보를 확인할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006DD7;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;3) EKS 연동&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;연동을 위해서는 먼저 Netdata에 로그인을 해야 한다. 로그인이 되지 않은 상태에서는 커스터마이징이 불가능하며, 설치된 서버의 SMS 서버 역할만 수행할 수 있다.&lt;/span&gt;&lt;br&gt;&lt;span style=&quot;color: #000000;&quot;&gt;로그인이 완료되면, 비활성화 되어 있던 오른쪽 메뉴바들이 활성 상태로 변경된다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1560&quot; data-origin-height=&quot;871&quot; data-image-src=&quot;https://k.kakaocdn.net/dn/bbx0pp/btrbLfTC1AP/qZ6BJKhg43oXHKpn0jKsGK/img.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbx0pp/btrbLfTC1AP/qZ6BJKhg43oXHKpn0jKsGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbx0pp/btrbLfTC1AP/qZ6BJKhg43oXHKpn0jKsGK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbx0pp/btrbLfTC1AP/qZ6BJKhg43oXHKpn0jKsGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbbx0pp%2FbtrbLfTC1AP%2FqZ6BJKhg43oXHKpn0jKsGK%2Fimg.png&quot; data-origin-width=&quot;1560&quot; data-origin-height=&quot;871&quot; data-image-src=&quot;https://k.kakaocdn.net/dn/bbx0pp/btrbLfTC1AP/qZ6BJKhg43oXHKpn0jKsGK/img.png&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;gt; War Rooms Add&lt;/span&gt;&lt;br&gt;&lt;span style=&quot;color: #000000;&quot;&gt;모니터링 대상의 그룹을 지정하는 War Room을 생성한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b0hmKR/btrbQbimZ5p/RjVavBNAuuJwnaKgIzZwm0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b0hmKR/btrbQbimZ5p/RjVavBNAuuJwnaKgIzZwm0/img.png&quot; data-origin-width=&quot;1560&quot; data-origin-height=&quot;871&quot; style=&quot;width: 49.3869%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b0hmKR/btrbQbimZ5p/RjVavBNAuuJwnaKgIzZwm0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0hmKR%2FbtrbQbimZ5p%2FRjVavBNAuuJwnaKgIzZwm0%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;1560&quot; height=&quot;871&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GTrtc/btrbQ9Sbp8K/aKKV4ccu2l9mcact6qiHuK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GTrtc/btrbQ9Sbp8K/aKKV4ccu2l9mcact6qiHuK/img.png&quot; data-origin-width=&quot;1562&quot; data-origin-height=&quot;871&quot; style=&quot;width: 49.4503%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GTrtc/btrbQ9Sbp8K/aKKV4ccu2l9mcact6qiHuK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGTrtc%2FbtrbQ9Sbp8K%2FaKKV4ccu2l9mcact6qiHuK%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;1562&quot; height=&quot;871&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;위와 같이 War Room 이름을 지정하고 상단의 ADD 버튼을 클릭한다.&lt;/span&gt;&lt;br&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;gt; netdata parent/child 구성&lt;/span&gt;&lt;br&gt;&lt;span style=&quot;color: #000000;&quot;&gt;추가한 War Room에 모니터링할 대상 노드를 지정하기 위해&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; Kubernetes Cluster Node에 netdata parent를 등록한다. netdata는 helm chart를 활용하여 쉽게 설치할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;html&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;[root@ip-192-168-86-253 ~]# helm repo add netdata https://netdata.github.io/helmchart/ &quot;netdata&quot; has been added to your repositories [root@ip-192-168-86-253 ~]# helm install netdata netdata/netdata NAME: netdata LAST DEPLOYED: Tue Aug 10 18:57:56 2021 NAMESPACE: default STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: 1. netdata will be available on http://netdata.k8s.local/, on the exposed port of your ingress controller In a production environment, you You can get that port via `kubectl get services`. e.g. in the following example, the http exposed port is 31737, the https one is 30069. The hostname netdata.k8s.local will need to be added to /etc/hosts, so that it resolves to the exposed IP. That IP depends on how your cluster is set up: - When no load balancer is available (e.g. with minikube), you get the IP shown on `kubectl cluster-info` - In a production environment, the command `kubectl get services` will show the IP under the EXTERNAL-IP column The port can be retrieved in both cases from `kubectl get services` NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE exiled-tapir-nginx-ingress-controller LoadBalancer 10.98.132.169 &amp;lt;pending&amp;gt; 80:31737/TCP,443:30069/TCP 11h [root@ip-192-168-86-253 ~]# kubectl get pods -A | grep netdata default netdata-child-74kkz 2/2 Running 0 67s default netdata-parent-6975f94bd9-gjgw2 1/1 Running 0 67s [root@ip-192-168-86-253 ~]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;약 1분 정도 시간이 지나면 위와 같이 netdata parent와 netdata child가 기동된 것을 확인할 수 있다. netdata child는 각 노드에 기동되는 DaemonSet으로 보면되고, netdata parent는 대시보드로 전달해 주는 중간 접점 정도로 볼 수 있다.&lt;/span&gt;&lt;br&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;gt; Claim 요청&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1562&quot; data-origin-height=&quot;871&quot; data-image-src=&quot;https://k.kakaocdn.net/dn/bbHlgj/btrbJIIvcbU/WaqTGyiXuesAKiubYJnKlK/img.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbHlgj/btrbJIIvcbU/WaqTGyiXuesAKiubYJnKlK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbHlgj/btrbJIIvcbU/WaqTGyiXuesAKiubYJnKlK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbHlgj/btrbJIIvcbU/WaqTGyiXuesAKiubYJnKlK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbHlgj%2FbtrbJIIvcbU%2FWaqTGyiXuesAKiubYJnKlK%2Fimg.png&quot; data-origin-width=&quot;1562&quot; data-origin-height=&quot;871&quot; data-image-src=&quot;https://k.kakaocdn.net/dn/bbHlgj/btrbJIIvcbU/WaqTGyiXuesAKiubYJnKlK/img.png&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;netdata parent/child 구성이 완료되면, netdata 대시보드에 연결하기 위한 claim을 요청해야 한다. claim 요청에 사용되는 TOKEN과 ROOM 번호는 위와 같이 Connect Nodes - Nodes - 빨간박스 부분에서 확인할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;html&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;ex) sudo netdata-claim.sh -token=[TOKEN_ID] -rooms=[ROOM_ID] -url=https://app.netdata.cloud&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;위 정보를 기반으로 override.yaml 파일을 다음과 같이 생성한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;html&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;parent: claiming: enabled: true token: &quot;TOKEN&quot; rooms: &quot;ROOM&quot; child: claiming: enabled: true token: &quot;TOKEN&quot; rooms: &quot;ROOM&quot; configs: netdata: data: | [global] memory mode = ram history = 3600 [health] enabled = no&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;생성한 override.yaml을 helm upgrade를 통해 앞서 생성한 netdata chart에 반영한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;html&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;[root@ip-192-168-86-253 ~]# helm upgrade -f override.yaml netdata netdata/netdata Release &quot;netdata&quot; has been upgraded. Happy Helming! NAME: netdata LAST DEPLOYED: Tue Aug 10 19:15:43 2021 NAMESPACE: default STATUS: deployed REVISION: 2 TEST SUITE: None NOTES: 1. netdata will be available on http://netdata.k8s.local/, on the exposed port of your ingress controller In a production environment, you You can get that port via `kubectl get services`. e.g. in the following example, the http exposed port is 31737, the https one is 30069. The hostname netdata.k8s.local will need to be added to /etc/hosts, so that it resolves to the exposed IP. That IP depends on how your cluster is set up: - When no load balancer is available (e.g. with minikube), you get the IP shown on `kubectl cluster-info` - In a production environment, the command `kubectl get services` will show the IP under the EXTERNAL-IP column The port can be retrieved in both cases from `kubectl get services` NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE exiled-tapir-nginx-ingress-controller LoadBalancer 10.98.132.169 &amp;lt;pending&amp;gt; 80:31737/TCP,443:30069/TCP 11h [root@ip-192-168-86-253 ~]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&amp;gt; 노드 추가&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1561&quot; data-origin-height=&quot;837&quot; data-image-src=&quot;https://k.kakaocdn.net/dn/Zc2QB/btrbIcpKX7Y/oMKQxRyG3eqMsYyAFSexV0/img.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Zc2QB/btrbIcpKX7Y/oMKQxRyG3eqMsYyAFSexV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Zc2QB/btrbIcpKX7Y/oMKQxRyG3eqMsYyAFSexV0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Zc2QB/btrbIcpKX7Y/oMKQxRyG3eqMsYyAFSexV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZc2QB%2FbtrbIcpKX7Y%2FoMKQxRyG3eqMsYyAFSexV0%2Fimg.png&quot; data-origin-width=&quot;1561&quot; data-origin-height=&quot;837&quot; data-image-src=&quot;https://k.kakaocdn.net/dn/Zc2QB/btrbIcpKX7Y/oMKQxRyG3eqMsYyAFSexV0/img.png&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;EKS에서의 준비는 완료되었다. 이제 Netdata에서 노드를 추가해 보자. 중간의 ADD 버튼을 클릭하고 대상 노드를 선택한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1562&quot; data-origin-height=&quot;834&quot; data-image-src=&quot;https://k.kakaocdn.net/dn/cqYwPO/btrbJI2QK9z/2O1CuVjO5n0j92GLu3HCz1/img.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cqYwPO/btrbJI2QK9z/2O1CuVjO5n0j92GLu3HCz1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cqYwPO/btrbJI2QK9z/2O1CuVjO5n0j92GLu3HCz1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cqYwPO/btrbJI2QK9z/2O1CuVjO5n0j92GLu3HCz1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcqYwPO%2FbtrbJI2QK9z%2F2O1CuVjO5n0j92GLu3HCz1%2Fimg.png&quot; data-origin-width=&quot;1562&quot; data-origin-height=&quot;834&quot; data-image-src=&quot;https://k.kakaocdn.net/dn/cqYwPO/btrbJI2QK9z/2O1CuVjO5n0j92GLu3HCz1/img.png&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;위와 같이 정상적으로 연결되었을 경우 화면이 나타나는 것을 볼 수 있다.&lt;br&gt;간혹 연결자체가 실패하는 경우나 연결은 되었으나 데이터를 불러오지 못하는 경우가 있다. 이 경우 Claim 요청 시 RoomID/TOKEN 정보가 정확히 기입되었는지 확인해 보는것이 좋다&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot;&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;대시보드 활용&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;다양한 형태의 메트릭 정보는 물론 Pod의 상태 정보를 모두 확인할 수 있는 Netdata 대시보드 기능에 대해 알아보자.&lt;/span&gt;&lt;br&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;gt; System OS (CPU, MEMORY, DISK, APPLICATION Metrics)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/INyHh/btrbLeUJg13/gKKcTtxzpndPIcfPPvr2Ek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/INyHh/btrbLeUJg13/gKKcTtxzpndPIcfPPvr2Ek/img.png&quot; data-origin-width=&quot;1560&quot; data-origin-height=&quot;835&quot; style=&quot;width: 49.4007%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/INyHh/btrbLeUJg13/gKKcTtxzpndPIcfPPvr2Ek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FINyHh%2FbtrbLeUJg13%2FgKKcTtxzpndPIcfPPvr2Ek%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;1560&quot; height=&quot;835&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blLatD/btrbQbJrnUY/fMYvgYkGkhoks0RM6UwhCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blLatD/btrbQbJrnUY/fMYvgYkGkhoks0RM6UwhCk/img.png&quot; data-origin-width=&quot;1563&quot; data-origin-height=&quot;836&quot; style=&quot;width: 49.4365%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blLatD/btrbQbJrnUY/fMYvgYkGkhoks0RM6UwhCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblLatD%2FbtrbQbJrnUY%2FfMYvgYkGkhoks0RM6UwhCk%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;1563&quot; height=&quot;836&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wt0vt/btrbJJgkb8U/Qkfw8dhNtvKM2ySk6xOtc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wt0vt/btrbJJgkb8U/Qkfw8dhNtvKM2ySk6xOtc1/img.png&quot; data-origin-width=&quot;1564&quot; data-origin-height=&quot;838&quot; style=&quot;width: 49.3458%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wt0vt/btrbJJgkb8U/Qkfw8dhNtvKM2ySk6xOtc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fwt0vt%2FbtrbJJgkb8U%2FQkfw8dhNtvKM2ySk6xOtc1%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;1564&quot; height=&quot;838&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RucA1/btrbIHXrm0T/KJzGxEfrruSfjozEftkeXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RucA1/btrbIHXrm0T/KJzGxEfrruSfjozEftkeXk/img.png&quot; data-origin-width=&quot;1563&quot; data-origin-height=&quot;835&quot; style=&quot;width: 49.4914%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RucA1/btrbIHXrm0T/KJzGxEfrruSfjozEftkeXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRucA1%2FbtrbIHXrm0T%2FKJzGxEfrruSfjozEftkeXk%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;1563&quot; height=&quot;835&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;시스템 관점의 주요 지표들을 확인할 수 있다.&lt;/span&gt;&lt;br&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;gt; Kubernetes Metrics (API Server, Pods, Rest Client, Cluster Metrics)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbC2I1/btrbKFEzWeb/7OLnJ3KOJuWKqkLHsGpWD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbC2I1/btrbKFEzWeb/7OLnJ3KOJuWKqkLHsGpWD0/img.png&quot; data-origin-width=&quot;1561&quot; data-origin-height=&quot;836&quot; style=&quot;width: 49.389%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbC2I1/btrbKFEzWeb/7OLnJ3KOJuWKqkLHsGpWD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbC2I1%2FbtrbKFEzWeb%2F7OLnJ3KOJuWKqkLHsGpWD0%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;1561&quot; height=&quot;836&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cFsLr8/btrbRawNnLm/DOiki4CI9XLYBVX54J2Ar0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cFsLr8/btrbRawNnLm/DOiki4CI9XLYBVX54J2Ar0/img.png&quot; data-origin-width=&quot;1561&quot; data-origin-height=&quot;835&quot; style=&quot;width: 49.4482%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cFsLr8/btrbRawNnLm/DOiki4CI9XLYBVX54J2Ar0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcFsLr8%2FbtrbRawNnLm%2FDOiki4CI9XLYBVX54J2Ar0%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;1561&quot; height=&quot;835&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bg9vWx/btrbKF5JLix/ZDOjFCKAuobdD3fBYgefCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bg9vWx/btrbKF5JLix/ZDOjFCKAuobdD3fBYgefCk/img.png&quot; data-origin-width=&quot;1561&quot; data-origin-height=&quot;836&quot; style=&quot;width: 49.3732%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bg9vWx/btrbKF5JLix/ZDOjFCKAuobdD3fBYgefCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbg9vWx%2FbtrbKF5JLix%2FZDOjFCKAuobdD3fBYgefCk%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;1561&quot; height=&quot;836&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cUDgIK/btrbIHXrqFE/e5QKyBIGfzBhO5n3DCSd81/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cUDgIK/btrbIHXrqFE/e5QKyBIGfzBhO5n3DCSd81/img.png&quot; data-origin-width=&quot;1562&quot; data-origin-height=&quot;835&quot; style=&quot;width: 49.464%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cUDgIK/btrbIHXrqFE/e5QKyBIGfzBhO5n3DCSd81/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcUDgIK%2FbtrbIHXrqFE%2Fe5QKyBIGfzBhO5n3DCSd81%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;1562&quot; height=&quot;835&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;Kubernetes를 모니터링 할때 반드시 고려되어야할 주요 메트릭 정보를 모두 확인할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot;&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;결론&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이번 포스팅에서는 Netdata 구축 및 대시보드 활용에 대해 알아보았다.&lt;br&gt;Netdata는 Kubernetes가 구축되어 있는 환경에서 주요 지표들을 모니터링하는데 수분이내 구성을 완료할 수 있는 매력적인 Telemetry Component이다.&lt;/span&gt;&lt;br&gt;&lt;span style=&quot;color: #000000;&quot;&gt;여러 제약사항들이 존재하기도 하고, Prometheus &amp;amp; Grafana 조합만큼 유연성이 높은 것은 아니지만, 시스템 모니터링 환경을 구성하는 Starter 또는 Row 데이터를 기준으로 표출되는 시스템 모니터링의 용도로는 Grafana 이상의 Quality를 보여주는 것이 아닌가 싶다.&lt;/span&gt;&lt;br&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이후 포스팅에서는 커스터마이징 및 장애 알람 등의 추가 기능에 대해 알아보는 시간을 갖도록 하자.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>⑦ Open Source Software</category>
      <category>kubernetes monitoring</category>
      <category>kubernetes pod 모니터링</category>
      <category>kubernetes sms</category>
      <category>netdata</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/712</guid>
      <comments>https://waspro.tistory.com/712#entry712comment</comments>
      <pubDate>Wed, 11 Aug 2021 04:53:44 +0900</pubDate>
    </item>
    <item>
      <title>Tekton Pipeline 구축 - Maven/Image 빌드 및 Push</title>
      <link>https://waspro.tistory.com/711</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;개요&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;이번 포스팅에서는 Tekton Pipeline을 실제로 구축해 보도록 하자. 여러 단계에 걸쳐 Tekton에서 수행될 Task를 Pipeline으로 연결하고, 최종적으로 EKS에 배포하는 과정까지 알아보도록 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;먼저 이번 포스팅에서는 Docker Image를 생성하고 Docker Registry에 Push하는 과정에 대해 알아보자.&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: 'Noto Serif KR'; color: #ee2323;&quot;&gt;git-clone&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #ee2323;&quot;&gt;maven build&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #ee2323;&quot;&gt;image build&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #ee2323;&quot;&gt;image push&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;0. 구성 전 준비사항&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; Kubernetes 1.16 이상 버전 구축 : Amazon EKS(Kubernetes 1.19)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; Service Account 권한 부여 : GitHub / DockerHub&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; Workspace 용 pv, pvc 준비: 공유 데이터 저장소&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1627327571732&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv
spec:
  accessModes:
  - ReadWriteOnce
  capacity:
    storage: 500Mi
  nfs:
    path: /share/etc
    server: 192.168.71.110

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: maven-source-pvc
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 500Mi
  storageClassName: gp2
  volumeMode: Filesystem&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;1. git-clone task&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;첫번째 Task는 git-clone이다. git-clone은 소스코드를 다운로드 받아 빌드하기 위한 준비과정을 정의한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;1) hub.tekton.dev 에서 git-clone task 다운로드 및 메뉴얼 확인&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BsAJu/btraqSTWf3m/kWXgFKWh7XItKgLnciKvU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BsAJu/btraqSTWf3m/kWXgFKWh7XItKgLnciKvU0/img.png&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-origin-width=&quot;1060&quot; data-origin-height=&quot;978&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BsAJu/btraqSTWf3m/kWXgFKWh7XItKgLnciKvU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBsAJu%2FbtraqSTWf3m%2FkWXgFKWh7XItKgLnciKvU0%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;1060&quot; height=&quot;978&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpah0J/btraBUbnfDo/KfvAFryy5woAkaYLIeCrnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpah0J/btraBUbnfDo/KfvAFryy5woAkaYLIeCrnk/img.png&quot; style=&quot;width: 49.41860465116279%;&quot; data-origin-width=&quot;1060&quot; data-origin-height=&quot;978&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpah0J/btraBUbnfDo/KfvAFryy5woAkaYLIeCrnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbpah0J%2FbtraBUbnfDo%2FKfvAFryy5woAkaYLIeCrnk%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;1060&quot; height=&quot;978&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; 앞선 포스팅에서도 확인했듯이 Install 버튼을 클릭하여 기 정의되어 있는 Task Template을 Kubernetes에 적용한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1627327571733&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-71-110 tekton]# kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/git-clone/0.4/git-clone.yaml
task.tekton.dev/git-clone created
[root@ip-192-168-71-110 tekton]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; 커스터마이징이 필요할 경우 wget으로 다운로드 받아 수정후 반영한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1627327571733&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: git-clone
  labels:
    app.kubernetes.io/version: &quot;0.4&quot;
  annotations:
    tekton.dev/pipelines.minVersion: &quot;0.21.0&quot;
    tekton.dev/tags: git
    tekton.dev/displayName: &quot;git clone&quot;
spec:
  description: &amp;gt;-
    These Tasks are Git tasks to work with repositories used by other tasks
    in your Pipeline.

    The git-clone Task will clone a repo from the provided url into the
    output Workspace. By default the repo will be cloned into the root of
    your Workspace. You can clone into a subdirectory by setting this Task's
    subdirectory param. This Task also supports sparse checkouts. To perform
    a sparse checkout, pass a list of comma separated directory patterns to
    this Task's sparseCheckoutDirectories param.
  workspaces:
    - name: output
      description: The git repo will be cloned onto the volume backing this Workspace.
    - name: ssh-directory
      optional: true
      description: |
        A .ssh directory with private key, known_hosts, config, etc. Copied to
        the user's home before git commands are executed. Used to authenticate
        with the git remote when performing the clone. Binding a Secret to this
        Workspace is strongly recommended over other volume types.
    - name: basic-auth
      optional: true
      description: |
        A Workspace containing a .gitconfig and .git-credentials file. These
        will be copied to the user's home before any git commands are run. Any
        other files in this Workspace are ignored. It is strongly recommended
        to use ssh-directory over basic-auth whenever possible and to bind a
        Secret to this Workspace over other volume types.
  params:
    - name: url
      description: Repository URL to clone from.
      type: string
    - name: revision
      description: Revision to checkout. (branch, tag, sha, ref, etc...)
      type: string
      default: &quot;&quot;
    - name: refspec
      description: Refspec to fetch before checking out revision.
      default: &quot;&quot;
    - name: submodules
      description: Initialize and fetch git submodules.
      type: string
      default: &quot;true&quot;
    - name: depth
      description: Perform a shallow clone, fetching only the most recent N commits.
      type: string
      default: &quot;1&quot;
    - name: sslVerify
      description: Set the `http.sslVerify` global git config. Setting this to `false` is not advised unless you are sure that you trust your git remote.
      type: string
      default: &quot;true&quot;
    - name: subdirectory
      description: Subdirectory inside the `output` Workspace to clone the repo into.
      type: string
      default: &quot;&quot;
    - name: sparseCheckoutDirectories
      description: Define the directory patterns to match or exclude when performing a sparse checkout.
      type: string
      default: &quot;&quot;
    - name: deleteExisting
      description: Clean out the contents of the destination directory if it already exists before cloning.
      type: string
      default: &quot;true&quot;
    - name: httpProxy
      description: HTTP proxy server for non-SSL requests.
      type: string
      default: &quot;&quot;
    - name: httpsProxy
      description: HTTPS proxy server for SSL requests.
      type: string
      default: &quot;&quot;
    - name: noProxy
      description: Opt out of proxying HTTP/HTTPS requests.
      type: string
      default: &quot;&quot;
    - name: verbose
      description: Log the commands that are executed during `git-clone`'s operation.
      type: string
      default: &quot;true&quot;
    - name: gitInitImage
      description: The image providing the git-init binary that this Task runs.
      type: string
      default: &quot;gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/git-init:v0.21.0&quot;
    - name: userHome
      description: |
        Absolute path to the user's home directory. Set this explicitly if you are running the image as a non-root user or have overridden
        the gitInitImage param with an image containing custom user configuration.
      type: string
      default: &quot;/tekton/home&quot;
  results:
    - name: commit
      description: The precise commit SHA that was fetched by this Task.
    - name: url
      description: The precise URL that was fetched by this Task.
  steps:
    - name: clone
      image: &quot;$(params.gitInitImage)&quot;
      env:
      - name: HOME
        value: &quot;$(params.userHome)&quot;
      - name: PARAM_URL
        value: $(params.url)
      - name: PARAM_REVISION
        value: $(params.revision)
      - name: PARAM_REFSPEC
        value: $(params.refspec)
      - name: PARAM_SUBMODULES
        value: $(params.submodules)
      - name: PARAM_DEPTH
        value: $(params.depth)
      - name: PARAM_SSL_VERIFY
        value: $(params.sslVerify)
      - name: PARAM_SUBDIRECTORY
        value: $(params.subdirectory)
      - name: PARAM_DELETE_EXISTING
        value: $(params.deleteExisting)
      - name: PARAM_HTTP_PROXY
        value: $(params.httpProxy)
      - name: PARAM_HTTPS_PROXY
        value: $(params.httpsProxy)
      - name: PARAM_NO_PROXY
        value: $(params.noProxy)
      - name: PARAM_VERBOSE
        value: $(params.verbose)
      - name: PARAM_SPARSE_CHECKOUT_DIRECTORIES
        value: $(params.sparseCheckoutDirectories)
      - name: PARAM_USER_HOME
        value: $(params.userHome)
      - name: WORKSPACE_OUTPUT_PATH
        value: $(workspaces.output.path)
      - name: WORKSPACE_SSH_DIRECTORY_BOUND
        value: $(workspaces.ssh-directory.bound)
      - name: WORKSPACE_SSH_DIRECTORY_PATH
        value: $(workspaces.ssh-directory.path)
      - name: WORKSPACE_BASIC_AUTH_DIRECTORY_BOUND
        value: $(workspaces.basic-auth.bound)
      - name: WORKSPACE_BASIC_AUTH_DIRECTORY_PATH
        value: $(workspaces.basic-auth.path)
      script: |
        #!/usr/bin/env sh
        set -eu

        if [ &quot;${PARAM_VERBOSE}&quot; = &quot;true&quot; ] ; then
          set -x
        fi

        if [ &quot;${WORKSPACE_BASIC_AUTH_DIRECTORY_BOUND}&quot; = &quot;true&quot; ] ; then
          cp &quot;${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/.git-credentials&quot; &quot;${PARAM_USER_HOME}/.git-credentials&quot;
          cp &quot;${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/.gitconfig&quot; &quot;${PARAM_USER_HOME}/.gitconfig&quot;
          chmod 400 &quot;${PARAM_USER_HOME}/.git-credentials&quot;
          chmod 400 &quot;${PARAM_USER_HOME}/.gitconfig&quot;
        fi

        if [ &quot;${WORKSPACE_SSH_DIRECTORY_BOUND}&quot; = &quot;true&quot; ] ; then
          cp -R &quot;${WORKSPACE_SSH_DIRECTORY_PATH}&quot; &quot;${PARAM_USER_HOME}&quot;/.ssh
          chmod 700 &quot;${PARAM_USER_HOME}&quot;/.ssh
          chmod -R 400 &quot;${PARAM_USER_HOME}&quot;/.ssh/*
        fi

        CHECKOUT_DIR=&quot;${WORKSPACE_OUTPUT_PATH}/${PARAM_SUBDIRECTORY}&quot;

        cleandir() {
          # Delete any existing contents of the repo directory if it exists.
          #
          # We don't just &quot;rm -rf ${CHECKOUT_DIR}&quot; because ${CHECKOUT_DIR} might be &quot;/&quot;
          # or the root of a mounted volume.
          if [ -d &quot;${CHECKOUT_DIR}&quot; ] ; then
            # Delete non-hidden files and directories
            rm -rf &quot;${CHECKOUT_DIR:?}&quot;/*
            # Delete files and directories starting with . but excluding ..
            rm -rf &quot;${CHECKOUT_DIR}&quot;/.[!.]*
            # Delete files and directories starting with .. plus any other character
            rm -rf &quot;${CHECKOUT_DIR}&quot;/..?*
          fi
        }

        if [ &quot;${PARAM_DELETE_EXISTING}&quot; = &quot;true&quot; ] ; then
          cleandir
        fi

        test -z &quot;${PARAM_HTTP_PROXY}&quot; || export HTTP_PROXY=&quot;${PARAM_HTTP_PROXY}&quot;
        test -z &quot;${PARAM_HTTPS_PROXY}&quot; || export HTTPS_PROXY=&quot;${PARAM_HTTPS_PROXY}&quot;
        test -z &quot;${PARAM_NO_PROXY}&quot; || export NO_PROXY=&quot;${PARAM_NO_PROXY}&quot;

        /ko-app/git-init \
          -url=&quot;${PARAM_URL}&quot; \
          -revision=&quot;${PARAM_REVISION}&quot; \
          -refspec=&quot;${PARAM_REFSPEC}&quot; \
          -path=&quot;${CHECKOUT_DIR}&quot; \
          -sslVerify=&quot;${PARAM_SSL_VERIFY}&quot; \
          -submodules=&quot;${PARAM_SUBMODULES}&quot; \
          -depth=&quot;${PARAM_DEPTH}&quot; \
          -sparseCheckoutDirectories=&quot;${PARAM_SPARSE_CHECKOUT_DIRECTORIES}&quot;
        cd &quot;${CHECKOUT_DIR}&quot;
        RESULT_SHA=&quot;$(git rev-parse HEAD)&quot;
        EXIT_CODE=&quot;$?&quot;
        if [ &quot;${EXIT_CODE}&quot; != 0 ] ; then
          exit &quot;${EXIT_CODE}&quot;
        fi
        printf &quot;%s&quot; &quot;${RESULT_SHA}&quot; &amp;gt; &quot;$(results.commit.path)&quot;
        printf &quot;%s&quot; &quot;${PARAM_URL}&quot; &amp;gt; &quot;$(results.url.path)&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;2) Tekton Dashboard 확인&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; Task는 다음과 같이 추가된 것을 알 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;735&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nWN9S/btrax8uIAfx/yVtAMIxy4gt4EIA6hVUaOK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nWN9S/btrax8uIAfx/yVtAMIxy4gt4EIA6hVUaOK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nWN9S/btrax8uIAfx/yVtAMIxy4gt4EIA6hVUaOK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnWN9S%2Fbtrax8uIAfx%2FyVtAMIxy4gt4EIA6hVUaOK%2Fimg.png&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;735&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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; font-family: 'Noto Serif KR';&quot;&gt;3) Pipeline 구성&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;첫번째 파이프라인 Task로 clone-repository를 등록한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1627327571734&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
  name: tekton-sample-pipeline
spec:
  workspaces:
    - name: pipeline-shared-data
  tasks:
    - name: clone-repository
      params:
        - name: url
          value: https://github.com/sonnaraon/Xray-Sample
        - name: revision
          value: &quot;master&quot;
        - name: deleteExisting
          value: &quot;true&quot;
      taskRef:
        kind: Task
        name: git-clone
      workspaces:
        - name: output
          workspace: pipeline-shared-data&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; git-clone은 다음과 같은 필수 요소를 충족하게 구성해야 한다.&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: 'Noto Serif KR'; color: #ee2323;&quot;&gt;The URL of a git repo to clone provided with the&amp;nbsp;url&amp;nbsp;param.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #ee2323;&quot;&gt;A Workspace called&amp;nbsp;output.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;위 필수 파라미터는 url로부터 clone 받은 소스코드를 output으로 정의된 workspace로 복제하는 역할을 한다. 기본적으로 소스코드는 workspace의 루트 디렉토리에 복사된다. 해당 경로에 파일이 존재할 경우 deleteExisting 옵션으로 삭제 후 다운로드 받을 것인지를 결정할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; git-clone에서 사용되는 workspaces는 크게 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: 'Noto Serif KR'; color: #ee2323;&quot;&gt;output: A workspace for this Task to fetch the git repository in to.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;ssh-directory: An optional workspace to provide SSH credentials. At minimum this should include a private key but can also include other common files from&amp;nbsp;.ssh&amp;nbsp;including&amp;nbsp;config&amp;nbsp;and&amp;nbsp;known_hosts. It is&amp;nbsp;strongly&amp;nbsp;recommended that this workspace be bound to a Kubernetes&amp;nbsp;Secret.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;basic-auth: An optional workspace containing&amp;nbsp;.gitconfig&amp;nbsp;and&amp;nbsp;.git-credentials&amp;nbsp;files. This allows username/password/access token to be provided for basic auth.Note: Settings provided as part of a&amp;nbsp;.gitconfig&amp;nbsp;file can affect the execution of&amp;nbsp;git&amp;nbsp;in ways that conflict with the parameters of this Task. For example, specifying proxy settings in&amp;nbsp;.gitconfig&amp;nbsp;could conflict with the&amp;nbsp;httpProxy&amp;nbsp;and&amp;nbsp;httpsProxy&amp;nbsp;parameters this Task provides. Nothing prevents you setting these parameters but it is not advised.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;It is&amp;nbsp;strongly&amp;nbsp;recommended that this workspace be bound to a Kubernetes&amp;nbsp;Secret. For details on the correct format of the files in this Workspace see&amp;nbsp;Using basic-auth Credentials&amp;nbsp;below.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; git-clone에 적용가능한 parameter는 다음과 같다.&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: 'Noto Serif KR'; color: #ee2323;&quot;&gt;url: Repository URL to clone from. (required)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #ee2323;&quot;&gt;revision: Revision to checkout. (branch, tag, sha, ref, etc...) (default: &quot;&quot;)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;refspec: Refspec to fetch before checking out revision. (default:&quot;&quot;)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;submodules: Initialize and fetch git submodules. (default: true)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;depth: Perform a shallow clone, fetching only the most recent N commits. (default: 1)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;sslVerify: Set the&amp;nbsp;http.sslVerify&amp;nbsp;global git config. Setting this to&amp;nbsp;false&amp;nbsp;is not advised unless you are sure that you trust your git remote. (default: true)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;subdirectory: Subdirectory inside the&amp;nbsp;output&amp;nbsp;workspace to clone the repo into. (default:&amp;nbsp;&quot;&quot;)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #ee2323;&quot;&gt;deleteExisting: Clean out the contents of the destination directory if it already exists before cloning. (default: true)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;httpProxy: HTTP proxy server for non-SSL requests. (default: &quot;&quot;)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;httpsProxy: HTTPS proxy server for SSL requests. (default: &quot;&quot;)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;noProxy: Opt out of proxying HTTP/HTTPS requests. (default: &quot;&quot;)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #ee2323;&quot;&gt;verbose: Log the commands that are executed during&amp;nbsp;git-clone's operation. (default: true)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;sparseCheckoutDirectories: which directories to match or exclude when performing a sparse checkout (default: &quot;&quot;)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;gitInitImage: The image providing the git-init binary that this Task runs. (default: &quot;gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/git-init:TODO&quot;)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;userHome: The user's home directory. Set this explicitly if you are running the image as a non-root user. (default: &quot;/tekton/home&quot;)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;4) PipelineRun 구성&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;먼저, workspaces를 연동할 pvc를 등록하고 반영한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1627327571736&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-71-110 git-clone]# kubectl get pv,pvc
NAME                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM                      STORAGECLASS   REASON   AGE
persistentvolume/pv                                         500Mi      RWO            Retain           Available                                                      11h
persistentvolume/pvc-4ad1a0b6-ab3a-4fcd-86e7-85362465ed98   1Gi        RWO            Delete           Bound       default/maven-source-pvc   gp2                     11h

NAME                                     STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
persistentvolumeclaim/maven-source-pvc   Bound    pvc-4ad1a0b6-ab3a-4fcd-86e7-85362465ed98   1Gi        RWO            gp2            11h
[root@ip-192-168-71-110 git-clone]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; 아래와 같이 claimName을 지정한다. 이때 pipeline-shared-data는 git-clone task가 수행되며, cloning 된 소스코드가 저장되는 workspace 공간이 된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1627327571736&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
  name: tekton-sample-pipeline-run
spec:
  pipelineRef:
    name: tekton-sample-pipeline
  workspaces:
    - name: pipeline-shared-data
      persistentvolumeclaim:
        claimName: maven-source-pvc&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;5) 대시보드 확인&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;아래와 같이 반영 후 대시보드를 확인한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1627327571736&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-71-110 git-clone]# kubectl apply -f pipelinerun.yaml 
pipelinerun.tekton.dev/tekton-sample-pipeline-run created
[root@ip-192-168-71-110 git-clone]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; PipelineRuns와 Pipeline은 다음과 같이 등록되어 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bc0IIF/btrastM79xv/f87ijYeii0hKmCo7HwfbKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bc0IIF/btrastM79xv/f87ijYeii0hKmCo7HwfbKk/img.png&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;735&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bc0IIF/btrastM79xv/f87ijYeii0hKmCo7HwfbKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbc0IIF%2FbtrastM79xv%2Ff87ijYeii0hKmCo7HwfbKk%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;1568&quot; height=&quot;735&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c8RiB7/btraDzLkI2j/vWJvzDB67c5k7gYLIW0zxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c8RiB7/btraDzLkI2j/vWJvzDB67c5k7gYLIW0zxK/img.png&quot; style=&quot;width: 49.41860465116279%;&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;735&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c8RiB7/btraDzLkI2j/vWJvzDB67c5k7gYLIW0zxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc8RiB7%2FbtraDzLkI2j%2FvWJvzDB67c5k7gYLIW0zxK%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;1568&quot; height=&quot;735&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; PipelineRuns의 tekton-sample-pipeline-run을 선택하고 들어가면 다음과 같이 상세 정보를 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;735&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/q4uIJ/btraBTDydMg/0j4J61mEjySzxKAgFhPSM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/q4uIJ/btraBTDydMg/0j4J61mEjySzxKAgFhPSM0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/q4uIJ/btraBTDydMg/0j4J61mEjySzxKAgFhPSM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fq4uIJ%2FbtraBTDydMg%2F0j4J61mEjySzxKAgFhPSM0%2Fimg.png&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;735&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; 위 상세 화면에서 실행 가능한 또는 확인 가능한 정보는 5가지로 구분해 볼 수 있다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;성공여부 : 위와 같이 초록색 박스로 체크되어 있을 경우 의도한데로 동작하는 경우이며, 빨간색으로 표시될 경우 2,3,4를 통해 원인을 진단해 보아야 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Logs : 해당 Task가 동작하는 동안의 로그 정보를 확인할 수 있다. 아래와 같이 주요 액션을 확인하고, 오류 발생 시 발생 원인을 파악할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1627327571736&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;+ '[' false '=' true ]
+ '[' false '=' true ]
+ CHECKOUT_DIR=/workspace/output/
+ '[' true '=' true ]
+ cleandir
+ '[' -d /workspace/output/ ]
+ rm -rf /workspace/output//Dockerfile /workspace/output//ReadMe.txt /workspace/output//bin /workspace/output//deployment.yaml /workspace/output//logstash.conf /workspace/output//mvnw /workspace/output//mvnw.cmd /workspace/output//pom.xml /workspace/output//src
+ rm -rf /workspace/output//.git /workspace/output//.gitignore /workspace/output//.mvn /workspace/output//.tern-project
+ rm -rf '/workspace/output//..?*'
+ test -z 
+ test -z 
+ test -z 
+ /ko-app/git-init '-url=https://github.com/sonnaraon/Xray-Sample' '-revision=master' '-refspec=' '-path=/workspace/output/' '-sslVerify=true' '-submodules=true' '-depth=1' '-sparseCheckoutDirectories='
{&quot;level&quot;:&quot;info&quot;,&quot;ts&quot;:1625968012.138267,&quot;caller&quot;:&quot;git/git.go:169&quot;,&quot;msg&quot;:&quot;Successfully cloned https://github.com/sonnaraon/Xray-Sample @ d1ed4ef5138ee2d0eb2e4a00a347fbf6d071f217 (grafted, HEAD, origin/master) in path /workspace/output/&quot;}
{&quot;level&quot;:&quot;info&quot;,&quot;ts&quot;:1625968012.164239,&quot;caller&quot;:&quot;git/git.go:207&quot;,&quot;msg&quot;:&quot;Successfully initialized and updated submodules in path /workspace/output/&quot;}
+ cd /workspace/output/
+ git rev-parse HEAD
+ RESULT_SHA=d1ed4ef5138ee2d0eb2e4a00a347fbf6d071f217
+ EXIT_CODE=0
+ '[' 0 '!=' 0 ]
+ printf '%s' d1ed4ef5138ee2d0eb2e4a00a347fbf6d071f217
+ printf '%s' https://github.com/sonnaraon/Xray-Sample&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: 'Noto Serif KR'; color: #000000;&quot;&gt;Status : Status에서는 Task가 수행되면서 발생되는 액션의 in/out을 정의한다. 대체로 확인해야 할 정보는 terminated.message 정보이며, 해당 정보에서 commit(git-clone task에서 가져온 commit 정보), url(git-clone task에서 가져온 url 정보)를 확인하여 수행하고자 했던데로 동작하였는 확인할 필요가 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1627327571736&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;container: step-clone
imageID: &amp;gt;-
  docker-pullable://gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/git-init@sha256:db18a9c1607c8cbbcd72f61d0c4d795b9ff528669deacd5f8a1672e4ef198ffd
name: clone
terminated:
  containerID: 'docker://1032480e52de5d0db2368cc2152384cb7633d9758aa01e67af67856bd949af43'
  exitCode: 0
  finishedAt: '2021-07-11T01:46:52Z'
  message: &amp;gt;-
    [{&quot;key&quot;:&quot;commit&quot;,&quot;value&quot;:&quot;d1ed4ef5138ee2d0eb2e4a00a347fbf6d071f217&quot;,&quot;type&quot;:&quot;TaskRunResult&quot;},{&quot;key&quot;:&quot;url&quot;,&quot;value&quot;:&quot;https://github.com/sonnaraon/Xray-Sample&quot;,&quot;type&quot;:&quot;TaskRunResult&quot;}]
  reason: Completed
  startedAt: '2021-07-11T01:46:51Z'&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: 'Noto Serif KR'; color: #000000;&quot;&gt;Details : Task의 상세 정보를 확인한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Rerun : 동일 동작을 재빌드한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;735&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ccDX1J/btrat2hrLJ9/NwOweXLh3kgXpg0sdLwhd0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ccDX1J/btrat2hrLJ9/NwOweXLh3kgXpg0sdLwhd0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ccDX1J/btrat2hrLJ9/NwOweXLh3kgXpg0sdLwhd0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FccDX1J%2Fbtrat2hrLJ9%2FNwOweXLh3kgXpg0sdLwhd0%2Fimg.png&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;735&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; 위와 같이 Rerun을 선택하면 동일한 동작이 재 실행된다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;735&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cr2bhR/btrazMZbKcI/d6GVvEXFbMEzvkwDc6BOY0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cr2bhR/btrazMZbKcI/d6GVvEXFbMEzvkwDc6BOY0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cr2bhR/btrazMZbKcI/d6GVvEXFbMEzvkwDc6BOY0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcr2bhR%2FbtrazMZbKcI%2Fd6GVvEXFbMEzvkwDc6BOY0%2Fimg.png&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;735&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; 이때 위와 같이 동작하며, 상태를 재 진단할 수 있다. Pipeline/PipelineRun/Task 등에 수정이 발생된 경우 tkn 또는 kubectl로 반영하고 이를 재빌드하는 방법이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;6) tkn 명령어 확인&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;마지막으로 tkn 명령어 확인방법이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; tkn pr list (pipelinerun list)&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1627327571737&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-71-110 pipeline]# tkn pr list
NAME                                 STARTED         DURATION     STATUS               
tekton-sample-pipeline-run-r-fdvmw   2 minutes ago   14 seconds   Succeeded   
tekton-sample-pipeline-run-r-d2gm6   3 minutes ago   14 seconds   Succeeded   
tekton-sample-pipeline-run           1 hour ago      23 seconds   Succeeded   
[root@ip-192-168-71-110 pipeline]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; tkn pr logs [pr_name or --last -f] (pipelinerun log 확인)&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1627327571737&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-71-110 pipeline]# tkn pr logs --last -f 
[clone-repository : clone] + '[' false '=' true ]
[clone-repository : clone] + '[' false '=' true ]
[clone-repository : clone] + CHECKOUT_DIR=/workspace/output/
[clone-repository : clone] + '[' true '=' true ]
[clone-repository : clone] + cleandir
[clone-repository : clone] + '[' -d /workspace/output/ ]
[clone-repository : clone] + rm -rf /workspace/output//Dockerfile /workspace/output//ReadMe.txt /workspace/output//bin /workspace/output//deployment.yaml /workspace/output//logstash.conf /workspace/output//mvnw /workspace/output//mvnw.cmd /workspace/output//pom.xml /workspace/output//src
[clone-repository : clone] + rm -rf /workspace/output//.git /workspace/output//.gitignore /workspace/output//.mvn /workspace/output//.tern-project
[clone-repository : clone] + rm -rf '/workspace/output//..?*'
[clone-repository : clone] + test -z 
[clone-repository : clone] + test -z 
[clone-repository : clone] + test -z 
[clone-repository : clone] + /ko-app/git-init '-url=https://github.com/sonnaraon/Xray-Sample' '-revision=master' '-refspec=' '-path=/workspace/output/' '-sslVerify=true' '-submodules=true' '-depth=1' '-sparseCheckoutDirectories='
[clone-repository : clone] {&quot;level&quot;:&quot;info&quot;,&quot;ts&quot;:1625971686.682756,&quot;caller&quot;:&quot;git/git.go:169&quot;,&quot;msg&quot;:&quot;Successfully cloned https://github.com/sonnaraon/Xray-Sample @ d1ed4ef5138ee2d0eb2e4a00a347fbf6d071f217 (grafted, HEAD, origin/master) in path /workspace/output/&quot;}
[clone-repository : clone] {&quot;level&quot;:&quot;info&quot;,&quot;ts&quot;:1625971686.6967826,&quot;caller&quot;:&quot;git/git.go:207&quot;,&quot;msg&quot;:&quot;Successfully initialized and updated submodules in path /workspace/output/&quot;}
[clone-repository : clone] + cd /workspace/output/
[clone-repository : clone] + git rev-parse HEAD
[clone-repository : clone] + RESULT_SHA=d1ed4ef5138ee2d0eb2e4a00a347fbf6d071f217
[clone-repository : clone] + EXIT_CODE=0
[clone-repository : clone] + '[' 0 '!=' 0 ]
[clone-repository : clone] + printf '%s' d1ed4ef5138ee2d0eb2e4a00a347fbf6d071f217
[clone-repository : clone] + printf '%s' https://github.com/sonnaraon/Xray-Sample

[root@ip-192-168-71-110 pipeline]# tkn pr logs tekton-sample-pipeline-run-r-fdvmw
[clone-repository : clone] + '[' false '=' true ]
[clone-repository : clone] + '[' false '=' true ]
[clone-repository : clone] + CHECKOUT_DIR=/workspace/output/
[clone-repository : clone] + '[' true '=' true ]
[clone-repository : clone] + cleandir
[clone-repository : clone] + '[' -d /workspace/output/ ]
[clone-repository : clone] + rm -rf /workspace/output//Dockerfile /workspace/output//ReadMe.txt /workspace/output//bin /workspace/output//deployment.yaml /workspace/output//logstash.conf /workspace/output//mvnw /workspace/output//mvnw.cmd /workspace/output//pom.xml /workspace/output//src
[clone-repository : clone] + rm -rf /workspace/output//.git /workspace/output//.gitignore /workspace/output//.mvn /workspace/output//.tern-project
[clone-repository : clone] + rm -rf '/workspace/output//..?*'
[clone-repository : clone] + test -z 
[clone-repository : clone] + test -z 
[clone-repository : clone] + test -z 
[clone-repository : clone] + /ko-app/git-init '-url=https://github.com/sonnaraon/Xray-Sample' '-revision=master' '-refspec=' '-path=/workspace/output/' '-sslVerify=true' '-submodules=true' '-depth=1' '-sparseCheckoutDirectories='
[clone-repository : clone] {&quot;level&quot;:&quot;info&quot;,&quot;ts&quot;:1625971686.682756,&quot;caller&quot;:&quot;git/git.go:169&quot;,&quot;msg&quot;:&quot;Successfully cloned https://github.com/sonnaraon/Xray-Sample @ d1ed4ef5138ee2d0eb2e4a00a347fbf6d071f217 (grafted, HEAD, origin/master) in path /workspace/output/&quot;}
[clone-repository : clone] {&quot;level&quot;:&quot;info&quot;,&quot;ts&quot;:1625971686.6967826,&quot;caller&quot;:&quot;git/git.go:207&quot;,&quot;msg&quot;:&quot;Successfully initialized and updated submodules in path /workspace/output/&quot;}
[clone-repository : clone] + cd /workspace/output/
[clone-repository : clone] + git rev-parse HEAD
[clone-repository : clone] + RESULT_SHA=d1ed4ef5138ee2d0eb2e4a00a347fbf6d071f217
[clone-repository : clone] + EXIT_CODE=0
[clone-repository : clone] + '[' 0 '!=' 0 ]
[clone-repository : clone] + printf '%s' d1ed4ef5138ee2d0eb2e4a00a347fbf6d071f217
[clone-repository : clone] + printf '%s' https://github.com/sonnaraon/Xray-Sample

[root@ip-192-168-71-110 pipeline]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;이제 git-clone task에 대한 pipeline 동작이 완료된 것을 확인할 수 있다. 다음으로 maven 빌드 task를 살펴보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;2. maven task&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;두번째 Task는 maven이다. maven은 git-clone을 통해 다운로드 받은 소스코드를 빌드하는 과정에 대해 정의한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;1) hub.tekton.dev 에서 maven task 다운로드 및 메뉴얼 확인&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHb0qX/btraptMXW9L/UfX4746vQQV1nFtVluJEE1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHb0qX/btraptMXW9L/UfX4746vQQV1nFtVluJEE1/img.png&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-origin-width=&quot;1060&quot; data-origin-height=&quot;978&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHb0qX/btraptMXW9L/UfX4746vQQV1nFtVluJEE1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHb0qX%2FbtraptMXW9L%2FUfX4746vQQV1nFtVluJEE1%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;1060&quot; height=&quot;978&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cBshNQ/btrazuKPUoH/Waqt7BkpyqU4e9hF7SOR10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cBshNQ/btrazuKPUoH/Waqt7BkpyqU4e9hF7SOR10/img.png&quot; style=&quot;width: 49.41860465116279%;&quot; data-origin-width=&quot;1060&quot; data-origin-height=&quot;978&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cBshNQ/btrazuKPUoH/Waqt7BkpyqU4e9hF7SOR10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcBshNQ%2FbtrazuKPUoH%2FWaqt7BkpyqU4e9hF7SOR10%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;1060&quot; height=&quot;978&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; Install 버튼을 클릭하여 기 정의되어 있는 Task Template을 Kubernetes에 적용한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1627327571737&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-71-110 ~]# kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/maven/0.2/maven.yaml
task.tekton.dev/maven created
[root@ip-192-168-71-110 ~]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; 커스터마이징이 필요할 경우 wget으로 다운로드 받아 수정후 반영한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1627327571737&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: maven
  labels:
    app.kubernetes.io/version: &quot;0.2&quot;
  annotations:
    tekton.dev/pipelines.minVersion: &quot;0.12.1&quot;
    tekton.dev/tags: build-tool
spec:
  description: &amp;gt;-
    This Task can be used to run a Maven build.

  workspaces:
    - name: source
      description: The workspace consisting of maven project.
    - name: maven-settings
      description: &amp;gt;-
        The workspace consisting of the custom maven settings
        provided by the user.
  params:
    - name: MAVEN_IMAGE
      type: string
      description: Maven base image
      default: gcr.io/cloud-builders/mvn@sha256:57523fc43394d6d9d2414ee8d1c85ed7a13460cbb268c3cd16d28cfb3859e641 #tag: latest
    - name: GOALS
      description: maven goals to run
      type: array
      default:
        - &quot;package&quot;
    - name: MAVEN_MIRROR_URL
      description: The Maven repository mirror url
      type: string
      default: &quot;&quot;
    - name: SERVER_USER
      description: The username for the server
      type: string
      default: &quot;&quot;
    - name: SERVER_PASSWORD
      description: The password for the server
      type: string
      default: &quot;&quot;
    - name: PROXY_USER
      description: The username for the proxy server
      type: string
      default: &quot;&quot;
    - name: PROXY_PASSWORD
      description: The password for the proxy server
      type: string
      default: &quot;&quot;
    - name: PROXY_PORT
      description: Port number for the proxy server
      type: string
      default: &quot;&quot;
    - name: PROXY_HOST
      description: Proxy server Host
      type: string
      default: &quot;&quot;
    - name: PROXY_NON_PROXY_HOSTS
      description: Non proxy server host
      type: string
      default: &quot;&quot;
    - name: PROXY_PROTOCOL
      description: Protocol for the proxy ie http or https
      type: string
      default: &quot;http&quot;
    - name: CONTEXT_DIR
      type: string
      description: &amp;gt;-
        The context directory within the repository for sources on
        which we want to execute maven goals.
      default: &quot;.&quot;
  steps:
    - name: mvn-settings
      image: registry.access.redhat.com/ubi8/ubi-minimal:8.2
      script: |
        #!/usr/bin/env bash

        [[ -f $(workspaces.maven-settings.path)/settings.xml ]] &amp;amp;&amp;amp; \
        echo 'using existing $(workspaces.maven-settings.path)/settings.xml' &amp;amp;&amp;amp; exit 0

        cat &amp;gt; $(workspaces.maven-settings.path)/settings.xml &amp;lt;&amp;lt;EOF
        &amp;lt;settings&amp;gt;
          &amp;lt;servers&amp;gt;
            &amp;lt;!-- The servers added here are generated from environment variables. Don't change. --&amp;gt;
            &amp;lt;!-- ### SERVER's USER INFO from ENV ### --&amp;gt;
          &amp;lt;/servers&amp;gt;
          &amp;lt;mirrors&amp;gt;
            &amp;lt;!-- The mirrors added here are generated from environment variables. Don't change. --&amp;gt;
            &amp;lt;!-- ### mirrors from ENV ### --&amp;gt;
          &amp;lt;/mirrors&amp;gt;
          &amp;lt;proxies&amp;gt;
            &amp;lt;!-- The proxies added here are generated from environment variables. Don't change. --&amp;gt;
            &amp;lt;!-- ### HTTP proxy from ENV ### --&amp;gt;
          &amp;lt;/proxies&amp;gt;
        &amp;lt;/settings&amp;gt;
        EOF

        xml=&quot;&quot;
        if [ -n &quot;$(params.PROXY_HOST)&quot; -a -n &quot;$(params.PROXY_PORT)&quot; ]; then
          xml=&quot;&amp;lt;proxy&amp;gt;\
            &amp;lt;id&amp;gt;genproxy&amp;lt;/id&amp;gt;\
            &amp;lt;active&amp;gt;true&amp;lt;/active&amp;gt;\
            &amp;lt;protocol&amp;gt;$(params.PROXY_PROTOCOL)&amp;lt;/protocol&amp;gt;\
            &amp;lt;host&amp;gt;$(params.PROXY_HOST)&amp;lt;/host&amp;gt;\
            &amp;lt;port&amp;gt;$(params.PROXY_PORT)&amp;lt;/port&amp;gt;&quot;
          if [ -n &quot;$(params.PROXY_USER)&quot; -a -n &quot;$(params.PROXY_PASSWORD)&quot; ]; then
            xml=&quot;$xml\
                &amp;lt;username&amp;gt;$(params.PROXY_USER)&amp;lt;/username&amp;gt;\
                &amp;lt;password&amp;gt;$(params.PROXY_PASSWORD)&amp;lt;/password&amp;gt;&quot;
          fi
          if [ -n &quot;$(params.PROXY_NON_PROXY_HOSTS)&quot; ]; then
            xml=&quot;$xml\
                &amp;lt;nonProxyHosts&amp;gt;$(params.PROXY_NON_PROXY_HOSTS)&amp;lt;/nonProxyHosts&amp;gt;&quot;
          fi
          xml=&quot;$xml\
              &amp;lt;/proxy&amp;gt;&quot;
          sed -i &quot;s|&amp;lt;!-- ### HTTP proxy from ENV ### --&amp;gt;|$xml|&quot; $(workspaces.maven-settings.path)/settings.xml
        fi

        if [ -n &quot;$(params.SERVER_USER)&quot; -a -n &quot;$(params.SERVER_PASSWORD)&quot; ]; then
          xml=&quot;&amp;lt;server&amp;gt;\
            &amp;lt;id&amp;gt;serverid&amp;lt;/id&amp;gt;&quot;
          xml=&quot;$xml\
                &amp;lt;username&amp;gt;$(params.SERVER_USER)&amp;lt;/username&amp;gt;\
                &amp;lt;password&amp;gt;$(params.SERVER_PASSWORD)&amp;lt;/password&amp;gt;&quot;
          xml=&quot;$xml\
              &amp;lt;/server&amp;gt;&quot;
          sed -i &quot;s|&amp;lt;!-- ### SERVER's USER INFO from ENV ### --&amp;gt;|$xml|&quot; $(workspaces.maven-settings.path)/settings.xml
        fi

        if [ -n &quot;$(params.MAVEN_MIRROR_URL)&quot; ]; then
          xml=&quot;    &amp;lt;mirror&amp;gt;\
            &amp;lt;id&amp;gt;mirror.default&amp;lt;/id&amp;gt;\
            &amp;lt;url&amp;gt;$(params.MAVEN_MIRROR_URL)&amp;lt;/url&amp;gt;\
            &amp;lt;mirrorOf&amp;gt;central&amp;lt;/mirrorOf&amp;gt;\
          &amp;lt;/mirror&amp;gt;&quot;
          sed -i &quot;s|&amp;lt;!-- ### mirrors from ENV ### --&amp;gt;|$xml|&quot; $(workspaces.maven-settings.path)/settings.xml
        fi

    - name: mvn-goals
      image: $(params.MAVEN_IMAGE)
      workingDir: $(workspaces.source.path)/$(params.CONTEXT_DIR)
      command: [&quot;/usr/bin/mvn&quot;]
      args:
        - -s
        - $(workspaces.maven-settings.path)/settings.xml
        - &quot;$(params.GOALS)&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;2) Tekton Dashboard 확인&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; Task는 다음과 같이 추가된 것을 알 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;735&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvqNx2/btrat2u3FVx/doGrlbyQM6sGJ5jhmudIKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvqNx2/btrat2u3FVx/doGrlbyQM6sGJ5jhmudIKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvqNx2/btrat2u3FVx/doGrlbyQM6sGJ5jhmudIKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvqNx2%2Fbtrat2u3FVx%2FdoGrlbyQM6sGJ5jhmudIKK%2Fimg.png&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;735&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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; font-family: 'Noto Serif KR';&quot;&gt;3) Pipeline 구성&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;두번째 파이프라인 Task로 maven-run를 등록한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1627327571738&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
  name: tekton-sample-pipeline
spec:
  workspaces:
    - name: pipeline-shared-data
    - name: maven-settings
  tasks:
    - name: clone-repository
      params:
        - name: url
          value: https://github.com/sonnaraon/Xray-Sample
        - name: revision
          value: &quot;master&quot;
        - name: deleteExisting
          value: &quot;true&quot;
      taskRef:
        kind: Task
        name: git-clone
      workspaces:
        - name: output
          workspace: pipeline-shared-data
    - name: maven-run
      taskRef:
        name: maven
      runAfter:
        - clone-repository
      params:
        - name: GOALS
          value:
            - clean
            - package
      workspaces:
        - name: maven-settings
          workspace: maven-settings
        - name: source
          workspace: pipeline-shared-data&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; Maven에 적용 가능한 Parameter는 다음과 같다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;MAVEN_IMAGE: The base image for maven (default:&amp;nbsp;gcr.io/cloud-builders/mvn)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #ee2323;&quot;&gt;GOALS: Maven&amp;nbsp;goals&amp;nbsp;to be executed&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;MAVEN_MIRROR_URL: Maven mirror url (to be inserted into ~/.m2/settings.xml)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;SERVER_USER: Username to authenticate to the server (to be inserted into ~/.m2/settings.xml)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;SERVER_PASSWORD: Password to authenticate to the server (to be inserted into ~/.m2/settings.xml)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;PROXY_USER: Username to login to the proxy server (to be inserted into ~/.m2/settings.xml)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;PROXY_PASSWORD: Password to login to the proxy server (to be inserted into ~/.m2/settings.xml)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;PROXY_HOST: Hostname of the proxy server (to be inserted into ~/.m2/settings.xml)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;PROXY_NON_PROXY_HOSTS: Non proxy hosts to be reached directly bypassing the proxy (to be inserted into ~/.m2/settings.xml)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;PROXY_PORT: Port number on which the proxy port listens (to be inserted into ~/.m2/settings.xml)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;PROXY_PROTOCOL: http or https protocol whichever is applicable (to be inserted into ~/.m2/settings.xml)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #ee2323;&quot;&gt;CONTEXT_DIR: The context directory within the repository for sources on which we want to execute maven goals. (Default: &quot;.&quot;)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;mvn clean package를 수행하기 위해 GOALS를 등록한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;4) PipelineRun 구성&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;다음으로 PipelineRun을 구성하고 적용한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1627327571739&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
  name: tekton-sample-pipeline-run
spec:
  pipelineRef:
    name: tekton-sample-pipeline
  workspaces:
    - name: maven-settings
      emptyDir: {}
    - name: pipeline-shared-data
      persistentvolumeclaim:
        claimName: maven-source-pvc&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; 위와 같이 maven-settings workspace를 생성한다. 생성타입이 emptyDir로 Pod 기동 후 생성되는 임시 공유 볼륨으로 사용한다. Pod가 종료되면 해당 공유 볼륨은 제거된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1627327571739&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-71-110 tekton]# kubectl apply -f pipelinerun.yaml 
pipelinerun.tekton.dev/tekton-sample-pipeline-run configured
[root@ip-192-168-71-110 tekton]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;5) 대시보드 확인&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;735&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/chJVNx/btrasuFmKi6/5NE2pJyteOkXJ7ueA4LUxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/chJVNx/btrasuFmKi6/5NE2pJyteOkXJ7ueA4LUxk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/chJVNx/btrasuFmKi6/5NE2pJyteOkXJ7ueA4LUxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FchJVNx%2FbtrasuFmKi6%2F5NE2pJyteOkXJ7ueA4LUxk%2Fimg.png&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;735&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; 반영이 완료되면 다음과 같이 PipelineRun을 Rerun한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;gt; 위와 같이 clone-repository 이외에 maven-run step이 추가된 것을 확인할 수 있다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;maven-run task 내에는 mvn-settings/mvn-goals로 step이 구분되어 처리된다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;735&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dvrc7C/btrat3gmHJa/nWQXy3XpZ6LHNHxfwDDWNk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dvrc7C/btrat3gmHJa/nWQXy3XpZ6LHNHxfwDDWNk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dvrc7C/btrat3gmHJa/nWQXy3XpZ6LHNHxfwDDWNk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdvrc7C%2Fbtrat3gmHJa%2FnWQXy3XpZ6LHNHxfwDDWNk%2Fimg.png&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;735&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; 모든 동작이 완료되면 다음과 같이 Completed 상태로 변경된다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;3. buildah task&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;세번째 Task는 buildah이다. buildah는 컴파일한&amp;nbsp; 정의한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;1) hub.tekton.dev 에서 buildah task 다운로드 및 메뉴얼 확인&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dTrNHj/btrasuSNwd5/wYSb7bgledh4DZ7Gri0I9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dTrNHj/btrasuSNwd5/wYSb7bgledh4DZ7Gri0I9K/img.png&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-origin-width=&quot;1060&quot; data-origin-height=&quot;978&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dTrNHj/btrasuSNwd5/wYSb7bgledh4DZ7Gri0I9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdTrNHj%2FbtrasuSNwd5%2FwYSb7bgledh4DZ7Gri0I9K%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;1060&quot; height=&quot;978&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bOCjE6/btraCRyIqOB/S3dLhKFdyHn6JoqeQK972k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bOCjE6/btraCRyIqOB/S3dLhKFdyHn6JoqeQK972k/img.png&quot; style=&quot;width: 49.41860465116279%;&quot; data-origin-width=&quot;1060&quot; data-origin-height=&quot;978&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bOCjE6/btraCRyIqOB/S3dLhKFdyHn6JoqeQK972k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbOCjE6%2FbtraCRyIqOB%2FS3dLhKFdyHn6JoqeQK972k%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;1060&quot; height=&quot;978&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; 앞선 포스팅에서도 확인했듯이 Install 버튼을 클릭하여 기 정의되어 있는 Task Template을 Kubernetes에 적용한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1627327571740&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-71-110 tekton]# kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/buildah/0.2/buildah.yaml
task.tekton.dev/buildah created
[root@ip-192-168-71-110 tekton]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; 커스터마이징이 필요할 경우 wget으로 다운로드 받아 수정후 반영한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1627327571740&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;---
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: buildah
  labels:
    app.kubernetes.io/version: &quot;0.2&quot;
  annotations:
    tekton.dev/pipelines.minVersion: &quot;0.17.0&quot;
    tekton.dev/tags: image-build
spec:
  description: &amp;gt;-
    Buildah task builds source into a container image and
    then pushes it to a container registry.

    Buildah Task builds source into a container image using Project Atomic's
    Buildah build tool.It uses Buildah's support for building from Dockerfiles,
    using its buildah bud command.This command executes the directives in the
    Dockerfile to assemble a container image, then pushes that image to a
    container registry.

  params:
  - name: IMAGE
    description: Reference of the image buildah will produce.
  - name: BUILDER_IMAGE
    description: The location of the buildah builder image.
    default: quay.io/buildah/stable:v1.17.0
  - name: STORAGE_DRIVER
    description: Set buildah storage driver
    default: overlay
  - name: DOCKERFILE
    description: Path to the Dockerfile to build.
    default: ./Dockerfile
  - name: CONTEXT
    description: Path to the directory to use as context.
    default: .
  - name: TLSVERIFY
    description: Verify the TLS on the registry endpoint (for push/pull to a non-TLS registry)
    default: &quot;true&quot;
  - name: FORMAT
    description: The format of the built container, oci or docker
    default: &quot;oci&quot;
  - name: BUILD_EXTRA_ARGS
    description: Extra parameters passed for the build command when building images.
    default: &quot;&quot;
  - name: PUSH_EXTRA_ARGS
    description: Extra parameters passed for the push command when pushing images.
    type: string
    default: &quot;&quot;
  workspaces:
  - name: source
  - name: sslcertdir
    optional: true
  results:
  - name: IMAGE_DIGEST
    description: Digest of the image just built.
  steps:
  - name: build
    image: $(params.BUILDER_IMAGE)
    workingDir: $(workspaces.source.path)
    script: |
      [[ &quot;$(workspaces.sslcertdir.bound)&quot; == &quot;true&quot; ]] &amp;amp;&amp;amp; CERT_DIR_FLAG=&quot;--cert-dir $(workspaces.sslcertdir.path)&quot;
      buildah ${CERT_DIR_FLAG} --storage-driver=$(params.STORAGE_DRIVER) bud \
        $(params.BUILD_EXTRA_ARGS) --format=$(params.FORMAT) \
        --tls-verify=$(params.TLSVERIFY) --no-cache \
        -f $(params.DOCKERFILE) -t $(params.IMAGE) $(params.CONTEXT)
    volumeMounts:
    - name: varlibcontainers
      mountPath: /var/lib/containers
    securityContext:
      privileged: true

  - name: push
    image: $(params.BUILDER_IMAGE)
    workingDir: $(workspaces.source.path)
    script: |
      [[ &quot;$(workspaces.sslcertdir.bound)&quot; == &quot;true&quot; ]] &amp;amp;&amp;amp; CERT_DIR_FLAG=&quot;--cert-dir $(workspaces.sslcertdir.path)&quot;
      buildah ${CERT_DIR_FLAG} --storage-driver=$(params.STORAGE_DRIVER) push \
        $(params.PUSH_EXTRA_ARGS) --tls-verify=$(params.TLSVERIFY) \
        --digestfile $(workspaces.source.path)/image-digest $(params.IMAGE) \
        docker://$(params.IMAGE)
    volumeMounts:
    - name: varlibcontainers
      mountPath: /var/lib/containers
    securityContext:
      privileged: true

  - name: digest-to-results
    image: $(params.BUILDER_IMAGE)
    script: cat $(workspaces.source.path)/image-digest | tee /tekton/results/IMAGE_DIGEST

  volumes:
  - name: varlibcontainers
    emptyDir: {}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;2) Tekton Dashboard 확인&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; Task는 다음과 같이 추가된 것을 알 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;735&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cDxjPE/btrawBXL7FU/VyPxx9a9rYNpbdBBGzGaV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cDxjPE/btrawBXL7FU/VyPxx9a9rYNpbdBBGzGaV0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cDxjPE/btrawBXL7FU/VyPxx9a9rYNpbdBBGzGaV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcDxjPE%2FbtrawBXL7FU%2FVyPxx9a9rYNpbdBBGzGaV0%2Fimg.png&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;735&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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; font-family: 'Noto Serif KR';&quot;&gt;3) Pipeline 구성&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;세번째 파이프라인 Task로 build-image를 등록한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1627327571741&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
  name: tekton-sample-pipeline
spec:
  workspaces:
    - name: pipeline-shared-data
    - name: maven-settings
  params:
    - name: image-repo
      type: string
      description: Docker image name
      default: sonnaraon/tekton-sample-repository
  tasks:
    - name: clone-repository
      params:
        - name: url
          value: https://github.com/sonnaraon/Xray-Sample
        - name: revision
          value: &quot;master&quot;
        - name: deleteExisting
          value: &quot;true&quot;
      taskRef:
        kind: Task
        name: git-clone
      workspaces:
        - name: output
          workspace: pipeline-shared-data
    - name: maven-run
      taskRef:
        name: maven
      runAfter:
        - clone-repository
      params:
        - name: GOALS
          value:
            - clean
            - package
      workspaces:
        - name: maven-settings
          workspace: maven-settings
        - name: source
          workspace: pipeline-shared-data
    - name: build-image
      runAfter:
        - maven-run
      params:
        - name: IMAGE
          value: &quot;$(params.image-repo):$(tasks.clone-repository.results.commit)&quot;
      taskRef:
        kind: Task
        name: buildah
      workspaces:
        - name: source
          workspace: pipeline-shared-data&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; buildah에 적용 가능한 Parameter는 다음과 같다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;IMAGE: The name (reference) of the image to build.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;BUILDER_IMAGE:: The name of the image containing the Buildah tool. See note below. (default:&amp;nbsp;quay.io/buildah/stable:v1.17.0)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;DOCKERFILE: The path to the&amp;nbsp;Dockerfile&amp;nbsp;to execute (default:&amp;nbsp;./Dockerfile)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;CONTEXT: Path to the directory to use as context (default:&amp;nbsp;.)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;TLSVERIFY: Verify the TLS on the registry endpoint (for push/pull to a non-TLS registry) (default:&amp;nbsp;true)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;FORMAT: The format of the built container, oci or docker (default:oci)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;BUILD_EXTRA_ARGS: Extra parameters passed for the build command when building images. (default:&amp;nbsp;&quot;&quot;)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;PUSH_EXTRA_ARGS: Extra parameters passed for the push command when pushing images. (default:&amp;nbsp;&quot;&quot;)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; workspaces는 source와 sslcertdir를 적용할 수 있다.&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: 'Noto Serif KR'; color: #ee2323;&quot;&gt;source: A&amp;nbsp;Workspace&amp;nbsp;containing the source to build.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;sslcertdir: An&amp;nbsp;optional&amp;nbsp;Workspace&amp;nbsp;containing your custom SSL certificates to connect to the registry. Buildah will look for files ending with *.crt, *.cert, *.key into this workspace. See&amp;nbsp;this sample&amp;nbsp;for a complete example on how to use it with OpenShift internal registry.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;4) PipelineRun 구성&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;다음으로 PipelineRun을 구성하고 적용한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1627327571742&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
  name: tekton-sample-pipeline-run
spec:
  pipelineRef:
    name: tekton-sample-pipeline
  workspaces:
    - name: maven-settings
      emptyDir: {}
    - name: pipeline-shared-data
      persistentvolumeclaim:
        claimName: maven-source-pvc&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; 위와 같이 maven-settings workspace를 생성한다. 생성타입이 emptyDir로 Pod 기동 후 생성되는 임시 공유 볼륨으로 사용한다. Pod가 종료되면 해당 공유 볼륨은 제거된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1627327571742&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-71-110 tekton]# kubectl apply -f pipelinerun.yaml 
pipelinerun.tekton.dev/tekton-sample-pipeline-run configured
[root@ip-192-168-71-110 tekton]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;5) 대시보드 확인&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;735&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bC8sMk/btraDAKevjF/2s30swZuK0xqZPtJLRRa70/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bC8sMk/btraDAKevjF/2s30swZuK0xqZPtJLRRa70/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bC8sMk/btraDAKevjF/2s30swZuK0xqZPtJLRRa70/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbC8sMk%2FbtraDAKevjF%2F2s30swZuK0xqZPtJLRRa70%2Fimg.png&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;735&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; 반영이 완료되면 다음과 같이 PipelineRun을 Rerun한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;gt; 위와 같이 clone-repository, maven-run 이외에 build-image step이 추가된 것을 확인할 수 있다.&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;build-image task 내에는 build/push/digest-to-result로 step이 구분되어 처리된다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;735&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KL4tz/btrapstIE6L/ooNBhRukVDTUXpnkK9nJsk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KL4tz/btrapstIE6L/ooNBhRukVDTUXpnkK9nJsk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KL4tz/btrapstIE6L/ooNBhRukVDTUXpnkK9nJsk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKL4tz%2FbtrapstIE6L%2FooNBhRukVDTUXpnkK9nJsk%2Fimg.png&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;735&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; 위와 같이 Pipeline 동작 시 실패가 발생할 경우 빨간색으로 표시된다. 조치를 위해선느 Logs를 확인하여 상태를 점검한다. 현재 Failed가 발생한 원인은 Docker Image를 빌드하는 상황에서 Maven Build시 생성한 war 파일과 Dockerfile 내 복사대상인 war 파일명이 달라 복사에 실패하여 에러가 발생하였다. 이를 조치하고 다시 Rerun을 수행해 보자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1627327571742&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;+ [[ false == \t\r\u\e ]]
+ buildah --storage-driver=overlay bud --format=oci --tls-verify=true --no-cache -f ./Dockerfile -t sonnaraon/tekton-sample-repository:d1ed4ef5138ee2d0eb2e4a00a347fbf6d071f217 .
STEP 1: FROM tomcat:8-jdk8-openjdk
Getting image source signatures
Copying blob sha256:96ebf150606575a0e557aa7349033a274221a8ad5ac09ba35736e7b344a4033f
Copying blob sha256:a110e58716600c199fc95f633b30735c33a25b5adcfb16d1d7edbcb78a3f1b62
Copying blob sha256:83d3c0fa203acbade733bff627daa75b84c97f9d0553bcdf967a3f1d37471277
Copying blob sha256:26b72ffca293d7e6fd2f11bf2642cd47d74053bf88c43f9e196412926cf20372
Copying blob sha256:0bc3020d05f1e08b41f1c5d54650a157b1690cde7fedb1fafbc9cda70ee2ec5c
Copying blob sha256:a8fd09c11b021b756b7a92a4f70a3d444ce7e63a1c24e5749d236dc2c6e68514
Copying blob sha256:0bffa2ea17aac1bf6e4f06f8ee4bb8d8d08efec7e75a7a4880102a86d15f0444
Copying blob sha256:d880cebcc7a6e70ee655bba1a8287be46b199cad2a3d2574ec48a3fe5f2c8454
Copying blob sha256:bed01058e36667d2dc290ae1914fc650e40b02c7b1cdf538999602bd56051dac
Copying blob sha256:0f2ce10b8ddf8f6da706db36c50945eb5953273096853b32d69e4accbc7c4e59
Copying config sha256:ecd199dd86fe6f2b9fb8424bc80ae4f391061764f51f4620b477f37071de94a7
Writing manifest to image destination
Storing signatures
STEP 2: RUN apt-get update &amp;amp;&amp;amp; apt-get install apt-file -y &amp;amp;&amp;amp; apt-file update &amp;amp;&amp;amp; apt-get install vim -y &amp;amp;&amp;amp; apt-get install telnet -y 
Get:1 http://security.debian.org/debian-security buster/updates InRelease [65.4 kB]
Get:2 http://deb.debian.org/debian buster InRelease [122 kB]
Get:3 http://deb.debian.org/debian buster-updates InRelease [51.9 kB]
Get:4 http://security.debian.org/debian-security buster/updates/main amd64 Packages [293 kB]
Get:5 http://deb.debian.org/debian buster/main amd64 Packages [7907 kB]
Get:6 http://deb.debian.org/debian buster-updates/main amd64 Packages [15.2 kB]
Fetched 8454 kB in 2s (4203 kB/s)
Reading package lists...
Reading package lists...
Building dependency tree...
Reading state information...
The following additional packages will be installed:
  libapt-pkg-perl libexporter-tiny-perl liblist-moreutils-perl
  libregexp-assemble-perl
The following NEW packages will be installed:
  apt-file libapt-pkg-perl libexporter-tiny-perl liblist-moreutils-perl
  libregexp-assemble-perl
0 upgraded, 5 newly installed, 0 to remove and 0 not upgraded.
Need to get 297 kB of archives.
After this operation, 825 kB of additional disk space will be used.
Get:1 http://deb.debian.org/debian buster/main amd64 libapt-pkg-perl amd64 0.1.34+b1 [71.2 kB]
Get:2 http://deb.debian.org/debian buster/main amd64 libexporter-tiny-perl all 1.002001-1 [36.9 kB]
Get:3 http://deb.debian.org/debian buster/main amd64 liblist-moreutils-perl amd64 0.416-1+b4 [64.2 kB]
Get:4 http://deb.debian.org/debian buster/main amd64 libregexp-assemble-perl all 0.36-1 [86.6 kB]
Get:5 http://deb.debian.org/debian buster/main amd64 apt-file all 3.2.2 [38.5 kB]
debconf: delaying package configuration, since apt-utils is not installed
Fetched 297 kB in 0s (1089 kB/s)
Selecting previously unselected package libapt-pkg-perl.
(Reading database ... 
(Reading database ... 5%
(Reading database ... 10%
(Reading database ... 15%
(Reading database ... 20%
(Reading database ... 25%
(Reading database ... 30%
(Reading database ... 35%
(Reading database ... 40%
(Reading database ... 45%
(Reading database ... 50%
(Reading database ... 55%
(Reading database ... 60%
(Reading database ... 65%
(Reading database ... 70%
(Reading database ... 75%
(Reading database ... 80%
(Reading database ... 85%
(Reading database ... 90%
(Reading database ... 95%
(Reading database ... 100%
(Reading database ... 12572 files and directories currently installed.)
Preparing to unpack .../libapt-pkg-perl_0.1.34+b1_amd64.deb ...
Unpacking libapt-pkg-perl (0.1.34+b1) ...
Selecting previously unselected package libexporter-tiny-perl.
Preparing to unpack .../libexporter-tiny-perl_1.002001-1_all.deb ...
Unpacking libexporter-tiny-perl (1.002001-1) ...
Selecting previously unselected package liblist-moreutils-perl.
Preparing to unpack .../liblist-moreutils-perl_0.416-1+b4_amd64.deb ...
Unpacking liblist-moreutils-perl (0.416-1+b4) ...
Selecting previously unselected package libregexp-assemble-perl.
Preparing to unpack .../libregexp-assemble-perl_0.36-1_all.deb ...
Unpacking libregexp-assemble-perl (0.36-1) ...
Selecting previously unselected package apt-file.
Preparing to unpack .../apt-file_3.2.2_all.deb ...
Unpacking apt-file (3.2.2) ...
Setting up libapt-pkg-perl (0.1.34+b1) ...
Setting up libexporter-tiny-perl (1.002001-1) ...
Setting up libregexp-assemble-perl (0.36-1) ...
Setting up liblist-moreutils-perl (0.416-1+b4) ...
Setting up apt-file (3.2.2) ...
The system-wide cache is empty. You may want to run 'apt-file update'
as root to update the cache.
Hit:1 http://security.debian.org/debian-security buster/updates InRelease
Hit:2 http://deb.debian.org/debian buster InRelease
Hit:3 http://deb.debian.org/debian buster-updates InRelease
Get:4 http://deb.debian.org/debian buster/main amd64 Contents (deb) [37.3 MB]
Get:5 http://deb.debian.org/debian buster-updates/main amd64 Contents (deb) [422 kB]
Fetched 37.7 MB in 7s (5130 kB/s)
Reading package lists...
Reading package lists...
Building dependency tree...
Reading state information...
The following additional packages will be installed:
  libgpm2 vim-common vim-runtime xxd
Suggested packages:
  gpm ctags vim-doc vim-scripts
The following NEW packages will be installed:
  libgpm2 vim vim-common vim-runtime xxd
0 upgraded, 5 newly installed, 0 to remove and 0 not upgraded.
Need to get 7425 kB of archives.
After this operation, 33.8 MB of additional disk space will be used.
Get:1 http://deb.debian.org/debian buster/main amd64 xxd amd64 2:8.1.0875-5 [140 kB]
Get:2 http://deb.debian.org/debian buster/main amd64 vim-common all 2:8.1.0875-5 [195 kB]
Get:3 http://deb.debian.org/debian buster/main amd64 libgpm2 amd64 1.20.7-5 [35.1 kB]
Get:4 http://deb.debian.org/debian buster/main amd64 vim-runtime all 2:8.1.0875-5 [5775 kB]
Get:5 http://deb.debian.org/debian buster/main amd64 vim amd64 2:8.1.0875-5 [1280 kB]
debconf: delaying package configuration, since apt-utils is not installed
Fetched 7425 kB in 1s (12.1 MB/s)
Selecting previously unselected package xxd.
(Reading database ... 
(Reading database ... 5%
(Reading database ... 10%
(Reading database ... 15%
(Reading database ... 20%
(Reading database ... 25%
(Reading database ... 30%
(Reading database ... 35%
(Reading database ... 40%
(Reading database ... 45%
(Reading database ... 50%
(Reading database ... 55%
(Reading database ... 60%
(Reading database ... 65%
(Reading database ... 70%
(Reading database ... 75%
(Reading database ... 80%
(Reading database ... 85%
(Reading database ... 90%
(Reading database ... 95%
(Reading database ... 100%
(Reading database ... 12702 files and directories currently installed.)
Preparing to unpack .../xxd_2%3a8.1.0875-5_amd64.deb ...
Unpacking xxd (2:8.1.0875-5) ...
Selecting previously unselected package vim-common.
Preparing to unpack .../vim-common_2%3a8.1.0875-5_all.deb ...
Unpacking vim-common (2:8.1.0875-5) ...
Selecting previously unselected package libgpm2:amd64.
Preparing to unpack .../libgpm2_1.20.7-5_amd64.deb ...
Unpacking libgpm2:amd64 (1.20.7-5) ...
Selecting previously unselected package vim-runtime.
Preparing to unpack .../vim-runtime_2%3a8.1.0875-5_all.deb ...
Adding 'diversion of /usr/share/vim/vim81/doc/help.txt to /usr/share/vim/vim81/doc/help.txt.vim-tiny by vim-runtime'
Adding 'diversion of /usr/share/vim/vim81/doc/tags to /usr/share/vim/vim81/doc/tags.vim-tiny by vim-runtime'
Unpacking vim-runtime (2:8.1.0875-5) ...
Selecting previously unselected package vim.
Preparing to unpack .../vim_2%3a8.1.0875-5_amd64.deb ...
Unpacking vim (2:8.1.0875-5) ...
Setting up libgpm2:amd64 (1.20.7-5) ...
Setting up xxd (2:8.1.0875-5) ...
Setting up vim-common (2:8.1.0875-5) ...
Setting up vim-runtime (2:8.1.0875-5) ...
Setting up vim (2:8.1.0875-5) ...
update-alternatives: using /usr/bin/vim.basic to provide /usr/bin/vim (vim) in auto mode
update-alternatives: using /usr/bin/vim.basic to provide /usr/bin/vimdiff (vimdiff) in auto mode
update-alternatives: using /usr/bin/vim.basic to provide /usr/bin/rvim (rvim) in auto mode
update-alternatives: using /usr/bin/vim.basic to provide /usr/bin/rview (rview) in auto mode
update-alternatives: using /usr/bin/vim.basic to provide /usr/bin/vi (vi) in auto mode
update-alternatives: using /usr/bin/vim.basic to provide /usr/bin/view (view) in auto mode
update-alternatives: using /usr/bin/vim.basic to provide /usr/bin/ex (ex) in auto mode
update-alternatives: using /usr/bin/vim.basic to provide /usr/bin/editor (editor) in auto mode
Processing triggers for libc-bin (2.28-10) ...
Processing triggers for mime-support (3.62) ...
Reading package lists...
Building dependency tree...
Reading state information...
The following NEW packages will be installed:
  telnet
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 70.4 kB of archives.
After this operation, 167 kB of additional disk space will be used.
Get:1 http://deb.debian.org/debian buster/main amd64 telnet amd64 0.17-41.2 [70.4 kB]
debconf: delaying package configuration, since apt-utils is not installed
Fetched 70.4 kB in 0s (683 kB/s)
Selecting previously unselected package telnet.
(Reading database ... 
(Reading database ... 5%
(Reading database ... 10%
(Reading database ... 15%
(Reading database ... 20%
(Reading database ... 25%
(Reading database ... 30%
(Reading database ... 35%
(Reading database ... 40%
(Reading database ... 45%
(Reading database ... 50%
(Reading database ... 55%
(Reading database ... 60%
(Reading database ... 65%
(Reading database ... 70%
(Reading database ... 75%
(Reading database ... 80%
(Reading database ... 85%
(Reading database ... 90%
(Reading database ... 95%
(Reading database ... 100%
(Reading database ... 14597 files and directories currently installed.)
Preparing to unpack .../telnet_0.17-41.2_amd64.deb ...
Unpacking telnet (0.17-41.2) ...
Setting up telnet (0.17-41.2) ...
update-alternatives: using /usr/bin/telnet.netkit to provide /usr/bin/telnet (telnet) in auto mode
STEP 3: RUN rm -f /usr/local/tomcat/webapps/ROOT
STEP 4: COPY ROOT.war /usr/local/tomcat/webapps
error building at STEP &quot;COPY ROOT.war /usr/local/tomcat/webapps&quot;: error adding sources [/workspace/source/ROOT.war]: error checking on source /workspace/source/ROOT.war under &quot;/workspace/source&quot;: copier: stat: &quot;/ROOT.war&quot;: no such file or directory&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; 위와 같이 로그를 대시보드 상에서 확인이 가능하지만, 대시보드에 접근하기 어려운 상황에서는 다음과 같이 Pod Logs를 통해서도 확인이 가능하다. Tekton을 수행하는 Pipeline Task 들은 Pod로 기동되어 동작하면 동작이 완료되면 종료한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1627327571742&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-71-110 tekton]# kubectl get pods -A
NAMESPACE          NAME                                                              READY   STATUS      RESTARTS   AGE
default            affinity-assistant-0a5e832af3-0                                   1/1     Running     0          4m22s
default            my-nginx-5b56ccd65f-5ld6s                                         1/1     Running     0          27h
default            my-nginx-5b56ccd65f-s7ffr                                         1/1     Running     0          27h
default            tekton-sample-pipeline-run-clone-repository-jzrf2-pod-2p58g       0/1     Completed   0          174m
default            tekton-sample-pipeline-run-r-d2gm6-clone-repository-2fkwx-4h2kv   0/1     Completed   0          113m
default            tekton-sample-pipeline-run-r-dnpt9-build-image-c9f5t-pod-lwrgz    3/3     Running     0          14s
default            tekton-sample-pipeline-run-r-dnpt9-clone-repository-vwz8v-jzb9l   0/1     Completed   0          4m22s
default            tekton-sample-pipeline-run-r-dnpt9-maven-run-5xpkc-pod-gf2zk      0/2     Completed   0          3m59s
default            tekton-sample-pipeline-run-r-fdvmw-clone-repository-dkc4v-pqtph   0/1     Completed   0          113m
default            tekton-sample-pipeline-run-r-sh2cg-build-image-p9f5c-pod-99jbp    0/3     Error       0          10m
default            tekton-sample-pipeline-run-r-sh2cg-clone-repository-zb5br-wlpbr   0/1     Completed   0          14m
default            tekton-sample-pipeline-run-r-sh2cg-maven-run-lwxwr-pod-smmlw      0/2     Completed   0          13m
default            tekton-sample-pipeline-run-r-wctvf-clone-repository-ls7hh-dwqzp   0/1     Completed   0          92m
default            tekton-sample-pipeline-run-r-wctvf-maven-run-vjmr7-pod-98bnp      0/2     Completed   0          91m
kube-system        alb-ingress-controller-7bd489b997-dvfbh                           1/1     Running     0          28h
kube-system        aws-node-m2zwv                                                    1/1     Running     0          43h
kube-system        aws-node-x869f                                                    1/1     Running     0          43h
kube-system        coredns-78fb67b999-rv7b4                                          1/1     Running     0          43h
kube-system        coredns-78fb67b999-xnwrt                                          1/1     Running     0          43h
kube-system        kube-proxy-h76x7                                                  1/1     Running     0          43h
kube-system        kube-proxy-zn822                                                  1/1     Running     0          43h
tekton-pipelines   tekton-dashboard-748fb458c7-xn8v7                                 1/1     Running     0          28h
tekton-pipelines   tekton-pipelines-controller-558cc574b7-jglz5                      1/1     Running     0          29h
tekton-pipelines   tekton-pipelines-webhook-575b9bcd9f-s28p6                         1/1     Running     0          29h
tekton-pipelines   tekton-triggers-controller-7bdc5c466-dlkjp                        1/1     Running     0          29h
tekton-pipelines   tekton-triggers-webhook-7b59947444-2r7d4                          1/1     Running     0          29h
[root@ip-192-168-71-110 tekton]# kubectl logs -f   tekton-sample-pipeline-run-r-dnpt9-build-image-c9f5t-pod-lwrgz step-build
+ [[ false == \t\r\u\e ]]
+ buildah --storage-driver=overlay bud --format=oci --tls-verify=true --no-cache -f ./Dockerfile -t sonnaraon/tekton-sample-repository:a0d0146bfeb8eee94ab678ac7d609d0e383f2a18 .
STEP 1: FROM tomcat:8-jdk8-openjdk
Getting image source signatures
Copying blob sha256:26b72ffca293d7e6fd2f11bf2642cd47d74053bf88c43f9e196412926cf20372
Copying blob sha256:83d3c0fa203acbade733bff627daa75b84c97f9d0553bcdf967a3f1d37471277
Copying blob sha256:96ebf150606575a0e557aa7349033a274221a8ad5ac09ba35736e7b344a4033f
Copying blob sha256:a8fd09c11b021b756b7a92a4f70a3d444ce7e63a1c24e5749d236dc2c6e68514
Copying blob sha256:0bc3020d05f1e08b41f1c5d54650a157b1690cde7fedb1fafbc9cda70ee2ec5c
Copying blob sha256:a110e58716600c199fc95f633b30735c33a25b5adcfb16d1d7edbcb78a3f1b62
Copying blob sha256:0bffa2ea17aac1bf6e4f06f8ee4bb8d8d08efec7e75a7a4880102a86d15f0444
Copying blob sha256:d880cebcc7a6e70ee655bba1a8287be46b199cad2a3d2574ec48a3fe5f2c8454
Copying blob sha256:bed01058e36667d2dc290ae1914fc650e40b02c7b1cdf538999602bd56051dac
Copying blob sha256:0f2ce10b8ddf8f6da706db36c50945eb5953273096853b32d69e4accbc7c4e59
Copying config sha256:ecd199dd86fe6f2b9fb8424bc80ae4f391061764f51f4620b477f37071de94a7
Writing manifest to image destination
Storing signatures
STEP 2: RUN apt-get update &amp;amp;&amp;amp; apt-get install apt-file -y &amp;amp;&amp;amp; apt-file update &amp;amp;&amp;amp; apt-get install vim -y &amp;amp;&amp;amp; apt-get install telnet -y 
..
..
..
STEP 3: RUN rm -f /usr/local/tomcat/webapps/ROOT
STEP 4: COPY ROOT.war /usr/local/tomcat/webapps
error building at STEP &quot;COPY ROOT.war /usr/local/tomcat/webapps&quot;: error adding sources [/workspace/source/ROOT.war]: error checking on source /workspace/source/ROOT.war under &quot;/workspace/source&quot;: copier: stat: &quot;/ROOT.war&quot;: no such file or directory
[root@ip-192-168-71-110 tekton]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;gt; 빌드시 다음과 같은 error가 발생할 경우 참고하여 조치한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1627327571743&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;+ [[ false == \t\r\u\e ]]
+ buildah --storage-driver=overlay push --tls-verify=true --digestfile /workspace/source/image-digest sonnaraon/tekton-sample-repository:b106bc30785a4f8ba2633db6e7c8bef05fcd7035 docker://sonnaraon/tekton-sample-repository:b106bc30785a4f8ba2633db6e7c8bef05fcd7035
Getting image source signatures
Copying blob sha256:79c550eb7bd278d360284d86c39e05852c2026b64232267a43947300bcf54a2c
Copying blob sha256:c3d00b097cce7df7dff99107ed0005fc4ceb14abaeac24316c8b120b4cd4c03a
Copying blob sha256:fe6a4fdbedc0cbc560437fa700b3b034114e31a264f0818d0d32ed2ee6cbe7a3
Copying blob sha256:7095af798ace32173839a61cbf101048434e1065185c0f29cc888e67158d990b
Copying blob sha256:e4d0e810d54a9c47e3dface412b0b88045d156b18809a2e0bbfb0fc8a45d8127
Copying blob sha256:4e006334a6fdea37622f72b21eb75fe1484fc4f20ce8b8526187d6f7bd90a6fe
Copying blob sha256:027dc7e9e77b575f17662b90b7429cc34725e9ae0101a33c5545f5fed3a22fbc
Copying blob sha256:aed5f5426b278d2800d114b061cc51b745d042ca1ef9294f8f9a77dfa5c19315
Copying blob sha256:8fa53538e6277c5529be88cb00d4d302d79c76797dd825a24761f4cd3ea8527c
Copying blob sha256:9d48355da13b8a355aaf6c479d386dc4280cb1e491271490e9f85d88831adb9b
Copying blob sha256:a78544ee94c6c00bd76e2df5696390010f58242f06eb998edd9e60f32f29fb99
error copying layers and metadata from &quot;containers-storage:[overlay@/var/lib/containers/storage+/var/run/containers/storage]localhost/sonnaraon/tekton-sample-repository:b106bc30785a4f8ba2633db6e7c8bef05fcd7035&quot; to &quot;docker://sonnaraon/tekton-sample-repository:b106bc30785a4f8ba2633db6e7c8bef05fcd7035&quot;: Error writing blob: Error initiating layer upload to /v2/sonnaraon/tekton-sample-repository/blobs/uploads/ in registry-1.docker.io: errors:
denied: requested access to the resource is denied
unauthorized: authentication required&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;pipeline에 paramerter를 다음과 같이 추가하였으나, image를 push하기 위해서는 아래 image registry에 접속하기 위한 secret을 등록해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1627327571743&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  params:
    - name: image-repo
      type: string
      description: Docker image name
      default: sonnaraon/tekton-sample-repository&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;먼저 docker registry 접속을 위한 Secret을 생성한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1627327571743&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;kubectl create secret docker-registry regcred --docker-username={USERNAME} --docker-password={PASSWD} --docker-email={EMAIL}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;다음으로 ServiceAccount를 생성한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1627327571743&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: v1
kind: ServiceAccount
metadata:
  name: build-bot
secrets:
  - name: regcred&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;생성한 ServiceAccount build-bot을 PipelineRun에 연결한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1627327571743&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
  name: tekton-sample-pipeline-run
spec:
  serviceAccountName: build-bot
  pipelineRef:
    name: tekton-sample-pipeline
  workspaces:
    - name: maven-settings
      emptyDir: {}
    - name: pipeline-shared-data
      persistentvolumeclaim:
        claimName: maven-source-pvc&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;위와 같이 조치 후 다시 Pipeline을 동작해 보자.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;735&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bC7uKl/btrav6w6pM5/iob8HhwLExPLRZ7lJZfFC1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bC7uKl/btrav6w6pM5/iob8HhwLExPLRZ7lJZfFC1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bC7uKl/btrav6w6pM5/iob8HhwLExPLRZ7lJZfFC1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbC7uKl%2Fbtrav6w6pM5%2Fiob8HhwLExPLRZ7lJZfFC1%2Fimg.png&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;735&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; 모든 동작이 완료되면 다음과 같이 Completed 상태로 변경된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;6) Docker Push 이미지 확인&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;마지막으로 Docker 이미지 Push 상태를 확인해 보자.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;1020&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqTpNI/btraprVUOo9/BFutkEmKMlbKnUnKf0xl71/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqTpNI/btraprVUOo9/BFutkEmKMlbKnUnKf0xl71/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqTpNI/btraprVUOo9/BFutkEmKMlbKnUnKf0xl71/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqTpNI%2FbtraprVUOo9%2FBFutkEmKMlbKnUnKf0xl71%2Fimg.png&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;1020&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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; font-family: 'Noto Serif KR';&quot;&gt;위와 같이 Docker Hub에 접속하여 확인해 보니, sonnaraon/tekton-sample-repository Repositoy에는 pipeline에 정의한 형태로 이미지가 push 된것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1627327571743&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;      params:
        - name: IMAGE
          value: &quot;$(params.image-repo):$(tasks.clone-repository.results.commit)&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;마지막으로 도커 이미지를 직접 기동해 보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1627327571743&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-71-110 tekton]# docker run -it sonnaraon/tekton-sample-repository:b106bc30785a4f8ba2633db6e7c8bef05fcd7035
Using CATALINA_BASE:   /usr/local/tomcat
Using CATALINA_HOME:   /usr/local/tomcat
Using CATALINA_TMPDIR: /usr/local/tomcat/temp
Using JRE_HOME:        /usr/local/openjdk-8
Using CLASSPATH:       /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar
Using CATALINA_OPTS:   
11-Jul-2021 05:08:48.171 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version name:   Apache Tomcat/8.5.69
11-Jul-2021 05:08:48.183 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server built:          Jun 30 2021 18:00:00 UTC
11-Jul-2021 05:08:48.183 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version number: 8.5.69.0
11-Jul-2021 05:08:48.184 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Name:               Linux
11-Jul-2021 05:08:48.184 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Version:            4.14.232-177.418.amzn2.x86_64
11-Jul-2021 05:08:48.185 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Architecture:          amd64
11-Jul-2021 05:08:48.185 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Java Home:             /usr/local/openjdk-8/jre
11-Jul-2021 05:08:48.186 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Version:           1.8.0_292-b10
11-Jul-2021 05:08:48.186 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Vendor:            Oracle Corporation
11-Jul-2021 05:08:48.187 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_BASE:         /usr/local/tomcat
11-Jul-2021 05:08:48.187 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_HOME:         /usr/local/tomcat
11-Jul-2021 05:08:48.188 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties
11-Jul-2021 05:08:48.189 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
11-Jul-2021 05:08:48.189 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.security.egd=file:/dev/./urandom
11-Jul-2021 05:08:48.190 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djdk.tls.ephemeralDHKeySize=2048
11-Jul-2021 05:08:48.190 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.protocol.handler.pkgs=org.apache.catalina.webresources
11-Jul-2021 05:08:48.191 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dorg.apache.catalina.security.SecurityListener.UMASK=0027
11-Jul-2021 05:08:48.194 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dignore.endorsed.dirs=
11-Jul-2021 05:08:48.196 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.base=/usr/local/tomcat
11-Jul-2021 05:08:48.197 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.home=/usr/local/tomcat
11-Jul-2021 05:08:48.197 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.io.tmpdir=/usr/local/tomcat/temp
11-Jul-2021 05:08:48.198 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent Loaded Apache Tomcat Native library [1.2.30] using APR version [1.6.5].
11-Jul-2021 05:08:48.198 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent APR capabilities: IPv6 [true], sendfile [true], accept filters [false], random [true].
11-Jul-2021 05:08:48.198 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent APR/OpenSSL configuration: useAprConnector [false], useOpenSSL [true]
11-Jul-2021 05:08:48.218 INFO [main] org.apache.catalina.core.AprLifecycleListener.initializeSSL OpenSSL successfully initialized [OpenSSL 1.1.1d  10 Sep 2019]
11-Jul-2021 05:08:48.399 INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler [&quot;http-nio-8080&quot;]
11-Jul-2021 05:08:48.433 INFO [main] org.apache.tomcat.util.net.NioSelectorPool.getSharedSelector Using a shared selector for servlet write/read
11-Jul-2021 05:08:48.470 INFO [main] org.apache.catalina.startup.Catalina.load Initialization processed in 1407 ms
11-Jul-2021 05:08:48.543 INFO [main] org.apache.catalina.core.StandardService.startInternal Starting service [Catalina]
11-Jul-2021 05:08:48.544 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet engine: [Apache Tomcat/8.5.69]
11-Jul-2021 05:08:48.589 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployWAR Deploying web application archive [/usr/local/tomcat/webapps/ROOT.war]
11-Jul-2021 05:08:54.598 INFO [localhost-startStop-1] org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.4.RELEASE)

2021-07-11 05:08:56.771  INFO [springAppName_IS_UNDEFINED,,] Starting ServletInitializer v0.0.1-SNAPSHOT on 1dc433657674 with PID 1 (/usr/local/tomcat/webapps/ROOT/WEB-INF/classes started by root in /usr/local/tomcat)
2021-07-11 05:08:56.785  INFO [springAppName_IS_UNDEFINED,,] No active profile set, falling back to default profiles: default
2021-07-11 05:08:56.990  INFO [springAppName_IS_UNDEFINED,,] For additional web related logging consider setting the 'logging.level.web' property to 'DEBUG'
2021-07-11 05:08:59.566  INFO [springAppName_IS_UNDEFINED,,] Root WebApplicationContext: initialization completed in 2571 ms&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;위와 같이 push 된 이미지가 정상 기동되는 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>⑤ 개발, 데이터베이스/ⓒ CI CD</category>
      <category>TEKTON</category>
      <category>tekton git-clone</category>
      <category>tekton image</category>
      <category>tekton kubernetes</category>
      <category>tekton maven</category>
      <category>tekton pipeline</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/711</guid>
      <comments>https://waspro.tistory.com/711#entry711comment</comments>
      <pubDate>Tue, 27 Jul 2021 04:27:27 +0900</pubDate>
    </item>
    <item>
      <title>GitLab 이슈를 활용한 Git Branch Strategy</title>
      <link>https://waspro.tistory.com/710</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;개요&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;아키텍트는&amp;nbsp;&lt;/span&gt;대규모 프로젝트에서 원하는 목표를 달성하기 위해 &lt;span style=&quot;color: #000000;&quot;&gt;다양한 영역의 아키텍처를 설계하는 것은 물론 개발 생산성 향상을 위해 개발절차를 확정하고 개발에 필요한 환경과 가이드를 제공하는 등 &lt;/span&gt;담당해야 할 과제들이 존재한다. 이때 개발절차를 확정하기 위해 선행되어야하는 것이 있는데 바로 SCM 정책수립이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;SCM(Source Code Management)은 소스코드 저장소에 대한 수정 사항을 추적하고 여러 개발자의 소스코드 병합과정에서 발생가능한 Conflict를 해결하는데 도움을 주는 도구이다. 특히 대규모 프로젝트일수록 필수적으로 고려되어야 한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;최근 클라우드 환경 특히 마이크로서비스 아키텍처 환경으로 접어들어가며, 배포독립성, 민첩성이 강조되는 환경에서 Git이 떠올랐으며, 신규로 시작되는 프로젝트들은 Git 기반으로 개발하는 경우가 많아지고 있는 추세이다. &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;필자 역시 신규 프로젝트를 리딩하는 경우 Git을 권고하고 있다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;이번 포스팅에서는 Git 브랜치 전략에 따른 조직 구성원 별 역할을 정의하고, 이를 DevOps 체계에 어떻게 적용하는 것이 좋은지 알아보자.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;포스팅 순서&lt;/span&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;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;프로젝트 팀 구성&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;GitLab 프로젝트 준비&lt;/span&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Group 등록&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Member 등록&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Project 등록&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Mileston 등록&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Label 등록&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Issue 등록&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Git 브랜치 전략 수립&lt;/span&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; font-family: 'Noto Serif KR';&quot;&gt;Git Flow&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;GitHub Flow&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;GitLab Flow&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;GitLab 개발 프로세스&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;프로젝트 팀 구성&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;먼저 프로젝트를 수행할 팀을 구성해 보자. 여기서 프로젝트 팀이란 마이크로서비스 아키텍처 환경에서 서비스 단위로 팀을 구성하는 것을 가정한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;팀 구성은 피자 2판을 나눠먹을 수 있는 단위라고 하지만, 대체로 비슷한 비즈니스 유형을 처리하는 조직으로 구성하는 것이 바람직하다. 하나의 팀에는 Developer와 Operator가 공존해야 하며, 8:2 또는 7:3 비율로 팀을 구성한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Developer와 Operator 조직은 소수로 이루어지겠지만, 팀 내에서 역할 분리는 굉장히 중요하다. 소수의 프로젝트에서 역할이 명확히 구분되지 않을 경우 일에 대한 진척 지연은 물론 책임소지에 대한 문제가 발생할 가능성이 높다. 다음은 DevOps 조직이 10명으로 이루어져 있을 경우를 가정하고, 팀을 구성하는 예시이다.&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;1006&quot; data-origin-height=&quot;803&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcSTJI/btram99hPWv/MgCnsZgAj4CBoHT1EtTxQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcSTJI/btram99hPWv/MgCnsZgAj4CBoHT1EtTxQ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcSTJI/btram99hPWv/MgCnsZgAj4CBoHT1EtTxQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcSTJI%2Fbtram99hPWv%2FMgCnsZgAj4CBoHT1EtTxQ0%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;1006&quot; height=&quot;803&quot; data-origin-width=&quot;1006&quot; data-origin-height=&quot;803&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; font-family: 'Noto Serif KR';&quot;&gt;비율은 팀마다 요구되는 기술셋에 따라 다르게 구성될 수 있겠지만, 적정한 비율은 MSA리더 (1) : 개발리더 (1) : 개발자 (5) : QA (1) : 운영리더 (1) : 운영자 (1) 또는 개발자 (4) : 운영자 (2) 정도로 구분해 볼 수 있을 것이다. (참고해야 할 사항으로 최근 DevSecOps라고 하여 Security를 조직에 포함하는 형태로 발전되어 가고 있다. 다만, Security 담당자는 하나의 마이크로서비스 단위에 소속하기 어려운 상황(인력확보 측면, 범위 측면 등)이므로 본 포스팅에서는 Security는 제외하고 설명하고자 한다.)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;프로젝트 팀이 구성이 되면, 역할을 부여해야 한다. 역할 역시 범위를 조정해 볼 수 있지만, 일반적으로 아래와 같은 역할을 부여할 수 있다.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.0465%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;담당&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 83.9535%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;역할&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.0465%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;MSA리더&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 83.9535%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;- MSA리더는 담당 프로젝트 내 수행해야 하는 모든 의사결정 조율&lt;br /&gt;- 프로젝트 진척을 관리하는 주체&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.0465%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;개발리더&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 83.9535%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;- Developer 조직에서 수행되는 의사 결정 및 코드리뷰를 담당&lt;br /&gt;- 각 개발자의 진척을 관리하는 주체&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.0465%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;개발자&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 83.9535%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;- 마이크로서비스 개발 및 유지보수&lt;br /&gt;- 단위테스트 주체&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.0465%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;QA&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 83.9535%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;- CI/CD 구축 및 관리&lt;br /&gt;- E2E 테스트, Contract 테스트 등 다중 서비스 간의 테스트 담당 주체&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.0465%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;운영리더&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 83.9535%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;- Operator 조직에서 수행되는 의사 결정을 담당하고 조율&lt;br /&gt;- 개발자 지원을 위한 의사소통 창구 역할&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.0465%; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;운영자&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 83.9535%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;- 마이크로서비스 장애 대응&lt;br /&gt;- 주요 클라우드 관련 솔루션 구축 운영 (PaaS, API Gateway, Service Mesh, Telemetry, Backing 등)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;위와 같은 조직 구성으로 보면, 소규모 SI 프로젝트가 수행되는 형태로도 볼 수 있다. 다만, SI는 시스템을 통합한 이후 프로젝트에서 철수하지만, 마이크로서비스의 DevOps 조직은 지속적으로 개발하고 운영해 나간다는 측면에서 차이가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;GitLab 프로젝트 준비&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;지금부터는 Git 프로젝트 내에서 Git Branch 전략을 수립함에 있어 위 수행 담당자 별 역할을 정리해 보도록 하자. 다음은 GitLab 내에서 수행 가능한 범위로 한정하며, 외부 3rd Party 솔루션 적용은 고려하지 않았을 경우이다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7; font-family: 'Noto Serif KR';&quot;&gt;1) Group 등록&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그룹은 마이크로서비스 단위 또는 프로젝트 팀 단위로 구성할 수 있으며, 대체로 프로젝트 팀 단위로 구성하는 것이 좋다. 하나의 프로젝트 팀 내에서 담당하는 마이크로서비스가 때로는 하나 이상이 될 수 있고, 각 역할을 담당하는 구성원이 다를 수 있지만, 이는 Issue를 활용하여 구분해 나가는 것이 좋다.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;그룹을 등록하는 방법은 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Admin Area &amp;gt; Overview &amp;gt; Groups &amp;gt; New Group)&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;1898&quot; data-origin-height=&quot;1005&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwLeNz/btrax7bpAWe/5LFKUqaD4PAyXJIPM1cWg0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwLeNz/btrax7bpAWe/5LFKUqaD4PAyXJIPM1cWg0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwLeNz/btrax7bpAWe/5LFKUqaD4PAyXJIPM1cWg0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbwLeNz%2Fbtrax7bpAWe%2F5LFKUqaD4PAyXJIPM1cWg0%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;1898&quot; height=&quot;1005&quot; data-origin-width=&quot;1898&quot; data-origin-height=&quot;1005&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; font-family: 'Noto Serif KR';&quot;&gt;위와 같이 마케팅서비스팀이라는 그룹을 생성하였다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7; font-family: 'Noto Serif KR';&quot;&gt;2) Member 등록&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;생성한 그룹에 멤버를 등록한다. 등록한 멤버에게는 프로젝트에서 담당하게 될 역할에 따른 접근권한을 부여한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Admin Area &amp;gt; Overview &amp;gt; Groups &amp;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;1897&quot; data-origin-height=&quot;1006&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnWfN9/btrax7oYmsK/LBHzDxGk5czEo0tAkuMgeK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnWfN9/btrax7oYmsK/LBHzDxGk5czEo0tAkuMgeK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnWfN9/btrax7oYmsK/LBHzDxGk5czEo0tAkuMgeK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnWfN9%2Fbtrax7oYmsK%2FLBHzDxGk5czEo0tAkuMgeK%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;1897&quot; height=&quot;1006&quot; data-origin-width=&quot;1897&quot; data-origin-height=&quot;1006&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; font-family: 'Noto Serif KR';&quot;&gt;접근권한은 크게 5가지로 구분된다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 126px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 14.5349%; height: 21px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;접근권한&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 15.8139%; height: 21px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;담당&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.6511%; height: 21px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;역할&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 14.5349%; height: 21px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Owner&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 15.8139%; height: 21px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;MSA PL&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.6511%; height: 21px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;- 그룹 / 프로젝트 생성자&lt;br /&gt;- 그룹 / 프로젝트 내 수행되는 모든 권한 포함&lt;br /&gt;- 멤버 권한부여, 프로젝트 / 마일스톤 / 이슈 관리 등 전체 GitLab 프로젝트 수행에 필요한 권한을 부여&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 14.5349%; height: 21px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Maintainer&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 15.8139%; height: 21px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;개발리더&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.6511%; height: 21px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;- 그룹 / 프로젝트 내 수정/삭제 권한 제외 Owner와 동일한 권한&lt;br /&gt;- Issue 및 브랜치를 생성하여 개발자에게 업무를 부여하고, 개발된 소스코드에 대한 소스리뷰 및 Merge Request를 승인하는 역할&lt;br /&gt;- Master Branch에 Push하거나, Release하는 역할&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 14.5349%; height: 21px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Developer&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 15.8139%; height: 21px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;개발자&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.6511%; height: 21px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- 신규 개발 또는 유지보수 담당&lt;br /&gt;- 새로운 브랜치 생성 및 Push가 가능하지만, Maintainer에 의해 할당된 이슈와 브랜치에서 개발 수행&lt;br /&gt;- Protected 브랜치를 제외한 모든 브랜치에 push 가능. Develop 브랜치에 Push 권한을 제거하기 위해 main 브랜치 이외에 develop 브랜치를 protected 브랜치로 구성&lt;br /&gt;# Protected 브랜치 구성 방법 : Project - 3) 프로젝트 등록 과정이 완료된 이후 설정 가능 &amp;gt; Settings &amp;gt; Repository &amp;gt; Protected Branches &amp;gt; Allowed to merge/Allowed to push 설정&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1895&quot; data-origin-height=&quot;1003&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kJedM/btrat3glo9H/j5QKr0MHhO8spkjLR17k5K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kJedM/btrat3glo9H/j5QKr0MHhO8spkjLR17k5K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kJedM/btrat3glo9H/j5QKr0MHhO8spkjLR17k5K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkJedM%2Fbtrat3glo9H%2Fj5QKr0MHhO8spkjLR17k5K%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;1895&quot; height=&quot;1003&quot; data-origin-width=&quot;1895&quot; data-origin-height=&quot;1003&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;br /&gt;- 개발 후 코드리뷰 및 Develop 브랜치에 머지 요청&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 14.5349%; height: 21px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Reporter&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 15.8139%; height: 21px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;QA&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.6511%; height: 21px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;- 이슈 관리 가능&lt;br /&gt;- Merge 또는 Push 권한이 없음&lt;br /&gt;- Merge Request 생성 가능&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 14.5349%; height: 21px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Guest&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 15.8139%; height: 21px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;운영리더/운영자&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.6511%; height: 21px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;- 프로젝트를 직접적으로 수행하지는 않지만, 프로젝트에 커멘트를 남기거나 그룹 / 프로젝트 조회가 가능한 권한&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&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;1897&quot; data-origin-height=&quot;1000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WcYsG/btraDzYR36j/S2bVroeNdfW0ghExGzTdjK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WcYsG/btraDzYR36j/S2bVroeNdfW0ghExGzTdjK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WcYsG/btraDzYR36j/S2bVroeNdfW0ghExGzTdjK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWcYsG%2FbtraDzYR36j%2FS2bVroeNdfW0ghExGzTdjK%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;1897&quot; height=&quot;1000&quot; data-origin-width=&quot;1897&quot; data-origin-height=&quot;1000&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; font-family: 'Noto Serif KR';&quot;&gt;위는 그룹에 포함되는 멤버에게 권한을 부여한 예시이다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7; font-family: 'Noto Serif KR';&quot;&gt;3) Project 등록&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;프로젝트는 마이크로서비스 단위로 생성한다. 이는 클라우드 상에서 서비스로 매핑된다. 즉, 개발자가 개발하고, QA가 배포하기 위한 모든 서비스가 존재해야 하며, 독립적으로 빌드/배포가 가능해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Admin Area &amp;gt; Overviwe &amp;gt; Projects &amp;gt; New Project &amp;gt; Create new project)&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cwuHst/btraqRl5EI2/i2KfnkuoKnFDpBksBk8o10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cwuHst/btraqRl5EI2/i2KfnkuoKnFDpBksBk8o10/img.png&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;841&quot; style=&quot;width: 45.6052%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cwuHst/btraqRl5EI2/i2KfnkuoKnFDpBksBk8o10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcwuHst%2FbtraqRl5EI2%2Fi2KfnkuoKnFDpBksBk8o10%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;1360&quot; height=&quot;841&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cDD4qV/btraoQuUAiX/WFNLVShTewWkc5kDtkRYW0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cDD4qV/btraoQuUAiX/WFNLVShTewWkc5kDtkRYW0/img.png&quot; data-origin-width=&quot;1897&quot; data-origin-height=&quot;1005&quot; style=&quot;width: 53.232%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cDD4qV/btraoQuUAiX/WFNLVShTewWkc5kDtkRYW0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcDD4qV%2FbtraoQuUAiX%2FWFNLVShTewWkc5kDtkRYW0%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;1897&quot; height=&quot;1005&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;위는 마케팅서비스(marketing-service) 프로젝트를 생성하는 과정이다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7; font-family: 'Noto Serif KR';&quot;&gt;4) Mileston 등록&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;마일스톤은 큰 틀의 유지보수 단계를 정의할 수도 있지만, 단위 기능 개발에 필요한 단계를 정의할 수도 있다. 즉, 명확히 추구하는 목표를 정의하고, Due Date를 기준으로 업무를 세분화하여 관리될 수 있도록 일정을 정의한다. 프로젝트 내에 여러 마일스톤이 관리될 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;(Project &amp;gt; Issues &amp;gt; Milestones &amp;gt; New mileston)&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;1897&quot; data-origin-height=&quot;997&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHQm2i/btrastGopCq/yXzrGGitob6shvUJzZDjIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHQm2i/btrastGopCq/yXzrGGitob6shvUJzZDjIk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHQm2i/btrastGopCq/yXzrGGitob6shvUJzZDjIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHQm2i%2FbtrastGopCq%2FyXzrGGitob6shvUJzZDjIk%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;1897&quot; height=&quot;997&quot; data-origin-width=&quot;1897&quot; data-origin-height=&quot;997&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: 'Noto Serif KR'; color: #000000;&quot;&gt;주요 업무 / 업무 순서 정의 / Start Date / Due Date를 정의하여 이후 프로젝트의 이슈를 정의하고, 진척을 관리하는 지표로 삼을수 있다. 마일스톤의 계획을 세우는 일은 프로젝트 리더의 주요 업무라 할 수 있다.&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;1898&quot; data-origin-height=&quot;1000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ztLym/btrazMx9VUy/A88h1ZykKMwXnZWlf4B1K0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ztLym/btrazMx9VUy/A88h1ZykKMwXnZWlf4B1K0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ztLym/btrazMx9VUy/A88h1ZykKMwXnZWlf4B1K0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FztLym%2FbtrazMx9VUy%2FA88h1ZykKMwXnZWlf4B1K0%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;1898&quot; height=&quot;1000&quot; data-origin-width=&quot;1898&quot; data-origin-height=&quot;1000&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: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;위는 마일스톤 생성화면이다. 마일스톤에 연계된 이슈/머지요청/라벨/멤버 정보를 확인할 수 있다. &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Issue/Merge Request/Participants/Labels 등이 연동되었을 경우 아래와 같이 연계정보를 마일스톤에서 확인할 수 있다.&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;1897&quot; data-origin-height=&quot;994&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pIUSX/btraInK1HMj/OGBauO2boyqEqeuHWDDdDk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pIUSX/btraInK1HMj/OGBauO2boyqEqeuHWDDdDk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pIUSX/btraInK1HMj/OGBauO2boyqEqeuHWDDdDk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpIUSX%2FbtraInK1HMj%2FOGBauO2boyqEqeuHWDDdDk%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;1897&quot; height=&quot;994&quot; data-origin-width=&quot;1897&quot; data-origin-height=&quot;994&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7; font-family: 'Noto Serif KR';&quot;&gt;5) Label 등록&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Label은 해쉬태그와 같이 Issue와 Merge Request의 유형을 한눈에 알아보기 위한 방식이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;(Project &amp;gt; Project Information &amp;gt; Labels &amp;gt; New 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;1897&quot; data-origin-height=&quot;1004&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bX7xte/btrazM50t7v/4YZod1jkDJJxSE1malfCY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bX7xte/btrazM50t7v/4YZod1jkDJJxSE1malfCY1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bX7xte/btrazM50t7v/4YZod1jkDJJxSE1malfCY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbX7xte%2FbtrazM50t7v%2F4YZod1jkDJJxSE1malfCY1%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;1897&quot; height=&quot;1004&quot; data-origin-width=&quot;1897&quot; data-origin-height=&quot;1004&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; font-family: 'Noto Serif KR';&quot;&gt;위와 같이 액션아이템, 리스크, 버그, 신규기능, 커스터마이징, 이슈 등으로 구분하여 태그를 생성하고, Issue 및 Merge Request에 활용한다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7; font-family: 'Noto Serif KR';&quot;&gt;6) Issue 등록&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;이슈는 개선사항이나, 신규 추가되어야 할 부분들에 대해 프로젝트 별로 등록하여 관리하는 Documentation의 일종이다. 앞서 생성한 마일스톤과 라벨을 등록하고 이슈를 관리할 Assigner를 등록한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;(Project &amp;gt; Issues &amp;gt; List &amp;gt; New issue)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/77PGu/btraCRS0KR4/TYKjgUsHK2FdlSQZT3Orpk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/77PGu/btraCRS0KR4/TYKjgUsHK2FdlSQZT3Orpk/img.png&quot; data-origin-width=&quot;1897&quot; data-origin-height=&quot;992&quot; style=&quot;width: 49.7027%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/77PGu/btraCRS0KR4/TYKjgUsHK2FdlSQZT3Orpk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F77PGu%2FbtraCRS0KR4%2FTYKjgUsHK2FdlSQZT3Orpk%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;1897&quot; height=&quot;992&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/br5O6H/btrat2Pj4pr/zVyK8BGfNEh4GZvwKNTrBk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/br5O6H/btrat2Pj4pr/zVyK8BGfNEh4GZvwKNTrBk/img.png&quot; data-origin-width=&quot;1898&quot; data-origin-height=&quot;1004&quot; style=&quot;width: 49.1345%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/br5O6H/btrat2Pj4pr/zVyK8BGfNEh4GZvwKNTrBk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbr5O6H%2Fbtrat2Pj4pr%2FzVyK8BGfNEh4GZvwKNTrBk%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;1898&quot; height=&quot;1004&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;위와 같이 이슈 생성이 완료되면, 오른쪽 상단의 Assignee Edit 버튼을 통해 해당 이슈를 할당 할 수 있다. 이슈를 할당할 경우 자동으로 이슈가 생성된 프로젝트에 접근권한이 부여되며, 할당한 역할에 따라 프로젝트에서 업무 수행이 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;이때 할당된 사용자는 To-Do 리스트를 받게 되며, 아래와 같이 상단에 To-Do 리스트가 표기되고 이동 시 이슈 정보를 확인할 수 있다.&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;941&quot; data-origin-height=&quot;383&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mqTxG/btraqSGmuUK/9OIe3JdFHFl1Kvoa1zH39K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mqTxG/btraqSGmuUK/9OIe3JdFHFl1Kvoa1zH39K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mqTxG/btraqSGmuUK/9OIe3JdFHFl1Kvoa1zH39K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmqTxG%2FbtraqSGmuUK%2F9OIe3JdFHFl1Kvoa1zH39K%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;941&quot; height=&quot;383&quot; data-origin-width=&quot;941&quot; data-origin-height=&quot;383&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; font-family: 'Noto Serif KR';&quot;&gt;이슈는 프로젝트와 매핑되며, 프로젝트에 할당되어 있는 인원은 이슈에 동일한 권한으로 자동 할당된다. 그룹의 경우 마이크로서비스팀 단위로 생성했다면, 이슈의 경우 &lt;span style=&quot;color: #000000;&quot;&gt;팀 내에서도 여러 마이크로서비스를 개발할 경우 또는 여러 기능이 한번에 개발될 경우 각 할당 업무별로 구분하여 생성하는 것이 좋다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Git 브랜치 전략 수립&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;위와 같이 GitLab 프로젝트 준비가 완료되면, 생성된 Issue에 팀원이 배정되고 권한이 부여된 상태가 될 것이다. 지금부터는 Git 브랜치 전략들에 대해 살펴보고, 마이크로서비스에 적용하기 용이한 Git 브랜치 전략은 어떤게 있는지 알아보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7; font-family: 'Noto Serif KR';&quot;&gt;1) Git Flow&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Git Flow 브랜치 전략의 기본 사상은 개발 대상의 특성에 따라 브랜치를 분리하는데 있다. Git Flow는 아래와 같은 5개의 브랜치로 구성된다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;Master (main &amp;amp; protected)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Develop&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Feature&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Release&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Hotfix&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Master와 Develop 브랜치는 수명주기가 긴 또는 제거되지 않는 브랜치이다. Feature/Release/Hotfix 브랜치는 목적에 따라 생성되고 삭제되는 수명주기가 짧은 브랜치이다. PR에 따른 머지가 완료되면 Feature/Release/Hotfix 브랜치는 삭제된다. 특징은 복잡한 프로젝트 환경에서 배포가 적고 안정적인 배포를 진행해야 하는 경우 적합한 방식이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&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: 'Noto Serif KR'; color: #000000;&quot;&gt;Clone&lt;/span&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Master &amp;gt; Develop &amp;gt; Feature&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Master &amp;gt; Hotfix &amp;gt; Develop&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Merge&lt;/span&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Feature &amp;gt; Develop &amp;gt; Relase &amp;gt; Master&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Develop &amp;gt; Hotfix &amp;gt; Master&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;color: #000000; font-family: 'Noto Serif KR';&quot;&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; font-family: 'Noto Serif KR';&quot;&gt;Feature 브랜치는 sourcetree, gitkraken과 같은 개발자 로컬 repo에 저장관리하여 타 개발자의 영향 없이 순수 개발을 진행할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;브랜치를 세분화하여 개발에 집중할 수 있도록 머지, 병합, 충돌에 대비할 수 있으며, 직관적인 구성이 가능하다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;체계적인 개발 프로세스를 통해 효율적인 테스트 환경을 구축할 수 있도록 지원한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Release 브랜치를 적용하여 다중 버전의 배포가 가능하도록 구성할 수 있으며, 다양한 배포 전략을 적용할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;브랜치 전략의 복잡도에 따라 개발 프로세스 및 릴리즈 주기가 지나치게 복잡해지고 느려질 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Feature 브랜치 머지 및 코드 리뷰에 많은 시간이 소모된다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Git Flow 사상은 대체로 장기 프로젝트에 적합한 방식으로 민첩한 배포가 필요한 프로젝트에 적합하지 않다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7; font-family: 'Noto Serif KR';&quot;&gt;2) GitHub Flow&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;GitHub Flow 브랜치 전략은 소규모 팀에 적합한 Master / Feature 브랜치로만 이루어진 비교적 간단한 전략이다. &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: 'Noto Serif KR'; color: #000000;&quot;&gt;Master&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Feature&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;여러 버전을 지원할 필요가 없는 웹 애플리케이션이나 민첩성이 중요한 배포 프로세스에 적용하기 적합한 전략이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&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: 'Noto Serif KR'; color: #000000;&quot;&gt;Clone&lt;/span&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; font-family: 'Noto Serif KR';&quot;&gt;Master &amp;gt; Feature&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Merge&lt;/span&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; font-family: 'Noto Serif KR';&quot;&gt;Feature &amp;gt; Master&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;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;GitHub Flow는 Master 브랜치가 Release 브랜치 역할을 겸한다. Feature 브랜치는 신규 기능, 버그 픽스 등을 포함하며, 개발이 완료되면, Master 브랜치에 머지되어 배포한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;GitHub Flow 전략을 성공적으로 수행하기 위해 아래 사항을 준수하는 것이 좋다.&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Master 브랜치의 모든 코드는 배포 가능해야 한다. 즉 빌드가 실패하거나, 배포 시 에러가 발생되지 않아야 하며, 이는 Master 브랜치로의 머지에 대한 엄격한 검증(코드리뷰, 테스트 등)이 있어야 함을 의미한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;PR(Pull Request)을 적극적으로 활용한다. 단순히 소스리뷰나 머지 요청을 위해 생성하기 보다는 DevOps 조직 전체적으로 의견을 주고 받을 수 있는 창구로 활용한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Git Flow와 다르게 Feature 브랜치를 Remote에서 관리하는 것이 좋다. 엄격하게 Master 브랜치가 관리되어야 하므로 사전에 Feature 브랜치를 통해 동일 기능에 대한 검증을 선 진행하고 Master 브랜치의 병합이 진행되는 것이 효과적이다. 상단에서 살펴본 이슈를 활용하는 방법에 적합하다. 이슈를 통해 생성한 브랜치를 Feature 브랜치로 관리하고 브랜치에 Commit 권한을 모든 개발자에게 허용한다. 이후 Master 브랜치에 대한 MR이 완료되면 해당 브랜치는 삭제한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Master 브랜치에 병합되면 Webhook을 통해 즉시 배포가 가능한 환경이 구성되어 있어야 한다. CI/CD 프로세스에 적용하여 Master 브랜치 머지는 배포라는 의미를 심어두는 것이 좋다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;흐름이 간단하여 누구나 손쉽게 이해하고 접근할 수 있다. Git을 사용해 보지 않은 개발자도 쉽게 이해할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;GitHub에서 제공하는 이슈를 활용할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;배포가 빈번한 MSA 환경 등 민첩한 CI/CD 배포 전략을 수립하기 용이하다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;소규모 팀과 웹 애플리케이션에 적합하다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;구글의 대부분의 프로젝트는 GitHub Flow를 사용한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;동시에 여러 버전의 소스를 지원하지 않는다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;코드리뷰는 물론 인프라 관점의 이해도가 높은 리더가 반드시 존재해야 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Develop 브랜치가 없어 운영 버그에 더 취약할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7; font-family: 'Noto Serif KR';&quot;&gt;3) GitLab Flow&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;GitLab Flow 브랜치 전략은 GitHub Flow 브랜치 전략과 유사하지만 릴리스 버전에 따라 브랜치를 추가한다는 점이 다르다. GitLab Flow는 Master 브랜치가 있지만, 다른 브랜치 전략과 다르게&amp;nbsp;최종 릴리즈를 위한 소스를 관리하는 브랜치로 사용되지 않는다. GitLab Flow에서 Feature 브랜치에서 개발한 소스코드는 Master 브랜치를 타겟으로 PR, 코드리뷰 및 머지 승인과정이 진행된다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;Master (main &amp;amp; protected)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Feature&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;production&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;GitLab Flow 브랜치 전략은 두 가지 유형의 릴리스 방법을 제시한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&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: 'Noto Serif KR'; color: #000000;&quot;&gt;Clone&lt;/span&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Master &amp;gt; Feature&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Merge&lt;/span&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Feature &amp;gt; Master &amp;gt; Production&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;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;위와 같이 Master 브랜치가 배포 대상이 아닌 유일한 브랜치이다. 배포는 Production 브랜치에서 배포하며, Master 브랜치에 최종 머지되더라도 자동으로 CI/CD 파이프라인을 태우지 않는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Git Flow 브랜치 전략과 비교할 때 GitLab Flow은 더 간단하다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;GitLab Flow은 GitHub Flow 브랜치 전략보다 더 체계적이고 구조화되어 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;GitLab Flow은 CI/CD 및 다양한 버전의 릴리스를 배포할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;GitLab Flow는 가장 단순하지도 않고, 복잡한 협업으로 프로젝트에서 가장 구조화되어 있지도 않은 Git 브랜치 전략이다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7; font-family: 'Noto Serif KR';&quot;&gt;# 선택&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;그래서 어떤걸 사용할꺼야? 라고 묻는다면, 역시나 프로젝트에 맞는 전략을 선택하라고 말하고 싶다. 다만, 기본적인 선택 기준은 다음과 같이 가져 갔으면 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;GitHub Flow &amp;lt; GitLab Flow &amp;lt; Git Flow&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;GitHub Flow &amp;gt; GitLab Flow &amp;gt; Git Flow&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;사실 위 두가지 조건을 가지고 선택한다면, 명확한 기준이 수립될 것이라고 본다. 예를 들어 MSA와 같은 빈번한 개발과 배포가 필요한 프로젝트에는 GitHub Flow 또는 GitLab Flow, SI 대형 프로젝트의 경우 Git Flow 또는 GitLab Flow를 검토해 보는 것이 좋을 듯 하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;위와 같은 브랜치 전략 이외에 다양하게 조합하여 자신만의 프로젝트 브랜치 전략을 생각해 볼 수 있다. 특히 CI/CD 파이프라인과의 조합을 통해 완성된 형태의 구성을 이뤄낼 수 있다. 다만, 주의해야 할 점은 위와 같이 화려한 브랜치 전략을 적용한다고 하여 프로젝트 관리가 더 잘되고 문제를 해소할 수 있는 것은 아니라는 것이다. 무엇보다 개발자의 브랜치 전략을 이해하고 있는지를 파악하고, 누구나 이해하기 쉬운 수준에서 브랜치를 관리해 나가는 것이 바람직하다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;GitLab 개발 프로세스&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;마지막으로 살펴볼 내용은 GitLab 환경에서 개발하는 절차에 대해 알아보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;지금부터 살펴볼 내용은 GitHub Flow의 처리 흐름이다. 필자가 현재 진행 중인 마이크로서비스 환경에 적용하고자 고려 중에 있으며, 각 개발자들에게 제공할 개발 절차서에도 다음과 같은 내용이 담겨질 예정이다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7; font-family: 'Noto Serif KR';&quot;&gt;1) Feature 브랜치 생성&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;현재 환경은 Master 브랜치만 생성되어 있는 상태이며, &quot;마케팅 로그인 기능 개발&quot; 이라는 이슈를 생성한 상태이다. 이슈에는 jinfox와 narason이 초대되어 있고, jinfox는 Developer, narason은 Reporter 역할이 부여되어 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;먼저 이슈를 통해 Feature 브랜치를 생성해보자. 생성 권한은 Developer 이상에게 부여된다.&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;1898&quot; data-origin-height=&quot;995&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dywcGQ/btraNy67Hxg/aUMVcpCTF67mtNl8XStqLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dywcGQ/btraNy67Hxg/aUMVcpCTF67mtNl8XStqLk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dywcGQ/btraNy67Hxg/aUMVcpCTF67mtNl8XStqLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdywcGQ%2FbtraNy67Hxg%2FaUMVcpCTF67mtNl8XStqLk%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;1898&quot; height=&quot;995&quot; data-origin-width=&quot;1898&quot; data-origin-height=&quot;995&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; font-family: 'Noto Serif KR';&quot;&gt;Create merge request and branch와 Create branch 중 Create branch를 선택하고 feature 브랜치 이름과 clone할 대상 브랜치인 master 브랜치를 입력한다.&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;1897&quot; data-origin-height=&quot;1005&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WzLuA/btraKFMUovP/s53Tipo9jvgW3U2cSNnJ61/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WzLuA/btraKFMUovP/s53Tipo9jvgW3U2cSNnJ61/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WzLuA/btraKFMUovP/s53Tipo9jvgW3U2cSNnJ61/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWzLuA%2FbtraKFMUovP%2Fs53Tipo9jvgW3U2cSNnJ61%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;1897&quot; height=&quot;1005&quot; data-origin-width=&quot;1897&quot; data-origin-height=&quot;1005&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; font-family: 'Noto Serif KR';&quot;&gt;위와 같이 feature-login 브랜치가 생성되었다. Feature 브랜치의 경우 remote에서 관리하는 경우와 local에서 관리하는 경우로 구분해 볼 수 있지만, 가이드에서는 remote에 관리하는 방법에 대해 알아본다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;2) Feature 브랜치 clone &amp;amp; push&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;a. git clone&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1627568958421&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-93-115 feature]# git clone http://gitlaburl:gitlabport/root/marketing-service.git
Cloning into 'marketing-service'...
Username for 'http://localhost': jinfox
Password for 'http://jinfox@localhost': 
remote: Enumerating objects: 46, done.
remote: Total 46 (delta 0), reused 0 (delta 0), pack-reused 46
Receiving objects: 100% (46/46), 55.63 KiB | 27.81 MiB/s, done.
Resolving deltas: 100% (4/4), done.
[root@ip-192-168-93-115 feature]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;git clone의 경우 git pull과 비슷하지만, 초기 git init을 통해 .git 초기화 작업을 함께 수행해 준다. 쉽게 origin 생성을 자동으로 해준다는 의미이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;b. branch 변경&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1627569115203&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-93-115 feature]# cd marketing-service/
[root@ip-192-168-93-115 marketing-service]# git checkout -b  feature-login
Switched to a new branch 'feature-login'
[root@ip-192-168-93-115 marketing-service]# git branch -a
* feature-login
  master
  remotes/origin/HEAD -&amp;gt; origin/master
  remotes/origin/feature-login
  remotes/origin/master
[root@ip-192-168-93-115 marketing-service]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;소스코드 개발에 사용할 로컬 git 브랜치명을 결정한다. 일반적으로 remote와 동일한 브랜치명을 사용하거나, 뒤에 local을 붙여 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;또는 git checkout [source_branch] -b [target_branch] (ex - git checkout remotes/origin/feature-login -b feature-login-local)으로 생성할 경우 target 브랜치는 source 브랜치를 기준으로 생성된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;c. commit &amp;amp; push&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1627569971865&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-93-115 marketing-service]# git add .
[root@ip-192-168-93-115 marketing-service]# git commit -m &quot;18080 port&quot;
[feature-login 626c74c] 18080 port
 1 file changed, 2 insertions(+), 2 deletions(-)
[root@ip-192-168-93-115 marketing-service]# git push -u origin feature-login
Username for 'http://localhost': jinfox
Password for 'http://jinfox@localhost': 
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 4 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 278 bytes | 278.00 KiB/s, done.
Total 3 (delta 2), reused 0 (delta 0), pack-reused 0
remote: 
remote: To create a merge request for feature-login, visit:
remote:   http://ec2-3-35-134-81.ap-northeast-2.compute.amazonaws.com/root/marketing-service/-/merge_requests/new?merge_request%5Bsource_branch%5D=feature-login
remote: 
To http://localhost/root/marketing-service.git
   55a8747..626c74c  feature-login -&amp;gt; feature-login
Branch 'feature-login' set up to track remote branch 'feature-login' from 'origin'.
[root@ip-192-168-93-115 marketing-service]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;소스코드 개발이 완료되어 remote에 반영하고자 할 경우 위와 같은 과정으로 반영한다. &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;(add &amp;gt; commit &amp;gt; push)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7; font-family: 'Noto Serif KR';&quot;&gt;3) MR(Merge Request) 요청&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Feature 브랜치에 push된 소스코드를 Master Branch에 머지하기 위한 Merge Request를 작성한다. MR 역시 Developer 이상 역할을 요구한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;(Project &amp;gt; Merge requests &amp;gt; New merge request &amp;gt; Create merge request)&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;1895&quot; data-origin-height=&quot;1003&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tPJYS/btraHYMvS3S/IcAADXpLPhlhjSB1mFeyG0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tPJYS/btraHYMvS3S/IcAADXpLPhlhjSB1mFeyG0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tPJYS/btraHYMvS3S/IcAADXpLPhlhjSB1mFeyG0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtPJYS%2FbtraHYMvS3S%2FIcAADXpLPhlhjSB1mFeyG0%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;1895&quot; height=&quot;1003&quot; data-origin-width=&quot;1895&quot; data-origin-height=&quot;1003&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; font-family: 'Noto Serif KR';&quot;&gt;Source Branch는 Feature 브랜치, Target Branch는 Master 브랜치를 구성하고, Compare branches and continue 버튼을 선택한다.&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;1896&quot; data-origin-height=&quot;1001&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bA54G6/btraRxNrvdY/K4BwxcDpiSPHsyxmyjiU10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bA54G6/btraRxNrvdY/K4BwxcDpiSPHsyxmyjiU10/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bA54G6/btraRxNrvdY/K4BwxcDpiSPHsyxmyjiU10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbA54G6%2FbtraRxNrvdY%2FK4BwxcDpiSPHsyxmyjiU10%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;1896&quot; height=&quot;1001&quot; data-origin-width=&quot;1896&quot; data-origin-height=&quot;1001&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; font-family: 'Noto Serif KR';&quot;&gt;Merge Request를 작성하기 위해 Target 브랜치와의 변경된 상태를 확인한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dFg1G6/btraPtkrBmk/L5IoXZQllYgHGpYhpZBiV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dFg1G6/btraPtkrBmk/L5IoXZQllYgHGpYhpZBiV0/img.png&quot; data-origin-width=&quot;1893&quot; data-origin-height=&quot;958&quot; style=&quot;width: 50.515%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dFg1G6/btraPtkrBmk/L5IoXZQllYgHGpYhpZBiV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdFg1G6%2FbtraPtkrBmk%2FL5IoXZQllYgHGpYhpZBiV0%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;1893&quot; height=&quot;958&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QbWBG/btraPuDGzjs/65QGWQzU37rKga66As0YUK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QbWBG/btraPuDGzjs/65QGWQzU37rKga66As0YUK/img.png&quot; data-origin-width=&quot;1894&quot; data-origin-height=&quot;1002&quot; style=&quot;width: 48.3223%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QbWBG/btraPuDGzjs/65QGWQzU37rKga66As0YUK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQbWBG%2FbtraPuDGzjs%2F65QGWQzU37rKga66As0YUK%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;1894&quot; height=&quot;1002&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&amp;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: 'Noto Serif KR'; color: #000000;&quot;&gt;Assignee : 해당 Merge Request에 대한 담당자를 지정한다. MR을 승인하는 대상이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Reviewer : 코드리뷰 도와줄 Member를 지정한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Milestone : 요청한 MR과 관련된 마일스톤을 지정한다.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Labels : &lt;span style=&quot;color: #000000;&quot;&gt;요청한 MR과 관련된&amp;nbsp;&lt;/span&gt;라벨을 지정한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Merge Options&lt;/span&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;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;요청한 머지가 승인될 경우 해당 브랜치를 제거할 것인지 여부&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;MR에 쌓여 있는 여러 커밋 요청들을 하나의 커밋으로 묶어서 머지할지 여부&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: 'Noto Serif KR'; color: #000000;&quot;&gt;Assignee는 머지 승인 권한이 있는 Maintainer, Reviewer는 추가로 코드 리뷰에 참여할 인원, Merge Options는 팀 내에서 결정하되, 첫번째 머지 승인 후 생성한 Feature Branch는 제거하는 옵션은 활성화하고 두번째 옵션은 정책에 따라 결정한다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7; font-family: 'Noto Serif KR';&quot;&gt;4) 리뷰 및 MR(Merge Request) 승인&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Merge Request가 오픈되면 Assignee와 Reviewer에게 알림이 전송된다. 상단에 Assigned to you와 Review request for you에 각각 알림 메시지가 온것을 확인할 수 있다.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cy98C2/btraJnZCg2I/zV37j3i1OWoBP4ggW2ZwX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cy98C2/btraJnZCg2I/zV37j3i1OWoBP4ggW2ZwX0/img.png&quot; data-origin-width=&quot;1893&quot; data-origin-height=&quot;1002&quot; style=&quot;width: 49.3301%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cy98C2/btraJnZCg2I/zV37j3i1OWoBP4ggW2ZwX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcy98C2%2FbtraJnZCg2I%2FzV37j3i1OWoBP4ggW2ZwX0%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;1893&quot; height=&quot;1002&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NM3Up/btraNxAnj0S/cv4RWOEd6kSPRa9jDEEcK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NM3Up/btraNxAnj0S/cv4RWOEd6kSPRa9jDEEcK1/img.png&quot; data-origin-width=&quot;1896&quot; data-origin-height=&quot;1000&quot; style=&quot;width: 49.5071%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NM3Up/btraNxAnj0S/cv4RWOEd6kSPRa9jDEEcK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNM3Up%2FbtraNxAnj0S%2Fcv4RWOEd6kSPRa9jDEEcK1%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;1896&quot; height=&quot;1000&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;먼저 Reviewer가 해야할 역할을 알아보자.&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;1897&quot; data-origin-height=&quot;999&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mq1co/btraInTAozi/ILDnSy9Vzu6tlNLmQHRtJk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mq1co/btraInTAozi/ILDnSy9Vzu6tlNLmQHRtJk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mq1co/btraInTAozi/ILDnSy9Vzu6tlNLmQHRtJk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fmq1co%2FbtraInTAozi%2FILDnSy9Vzu6tlNLmQHRtJk%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;1897&quot; height=&quot;999&quot; data-origin-width=&quot;1897&quot; data-origin-height=&quot;999&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; font-family: 'Noto Serif KR';&quot;&gt;리뷰어는 아래 Assignee와 다르게 승인이나, 머지 권한이 부여되지는 않는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;(Merge Request &amp;gt; Changes &amp;gt; Line Comment &amp;gt; Comment 입력 &amp;gt; Start a review)&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;1138&quot; data-origin-height=&quot;602&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/capA9u/btraRwAX2NW/IywlECOn2fPzsOHFCOm8Wk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/capA9u/btraRwAX2NW/IywlECOn2fPzsOHFCOm8Wk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/capA9u/btraRwAX2NW/IywlECOn2fPzsOHFCOm8Wk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcapA9u%2FbtraRwAX2NW%2FIywlECOn2fPzsOHFCOm8Wk%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;1138&quot; height=&quot;602&quot; data-origin-width=&quot;1138&quot; data-origin-height=&quot;602&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; font-family: 'Noto Serif KR';&quot;&gt;Reviewer와 Assignee의 코드리뷰에 따른 커멘트를 MR을 요청한 코드 수정자는 검토 후 반영 여부 등에 대해 커멘트 추가 및 소스코드 변경 작업을 진행한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;다음으로 Overview 탭의 Approve를 선택한다. 코드 리뷰와 승인을 받는 과정을 통해 모든 마이크로서비스 개발자 간의 커뮤니케이션이 활성화 되고, 서로 더 좋은 아이디어를 공유할 수 있어 이는 매우 중요한 부분이자, 반드시 거쳐야 하는 과정이다.&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;1897&quot; data-origin-height=&quot;1007&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SPAVc/btraMqV4j6Q/gEQlfloU7IlDbi5KWBYnBk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SPAVc/btraMqV4j6Q/gEQlfloU7IlDbi5KWBYnBk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SPAVc/btraMqV4j6Q/gEQlfloU7IlDbi5KWBYnBk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSPAVc%2FbtraMqV4j6Q%2FgEQlfloU7IlDbi5KWBYnBk%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;1897&quot; height=&quot;1007&quot; data-origin-width=&quot;1897&quot; data-origin-height=&quot;1007&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; font-family: 'Noto Serif KR';&quot;&gt;위와 같이 Approve를 선택한 이후 화면이다. MR이 승인되었으니, 이제 Master 브랜치와 Merge만 진행되면 된다.&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;1897&quot; data-origin-height=&quot;1005&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/duqjw1/btraMqBJETL/uX3nuNITmckAWEXYo3w2t1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/duqjw1/btraMqBJETL/uX3nuNITmckAWEXYo3w2t1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/duqjw1/btraMqBJETL/uX3nuNITmckAWEXYo3w2t1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fduqjw1%2FbtraMqBJETL%2FuX3nuNITmckAWEXYo3w2t1%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;1897&quot; height=&quot;1005&quot; data-origin-width=&quot;1897&quot; data-origin-height=&quot;1005&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; font-family: 'Noto Serif KR';&quot;&gt;머지까지 완료된 화면이다. 머지 후 테스트 결과에 따라 Revert 또는 Cherry-pick을 실행할 수 있다. &lt;span style=&quot;color: #000000;&quot;&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;1898&quot; data-origin-height=&quot;1004&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVjMxC/btraQq14fNe/hcW3MacCNKCLS7ZURFmDJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVjMxC/btraQq14fNe/hcW3MacCNKCLS7ZURFmDJ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVjMxC/btraQq14fNe/hcW3MacCNKCLS7ZURFmDJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVjMxC%2FbtraQq14fNe%2FhcW3MacCNKCLS7ZURFmDJ1%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;1898&quot; height=&quot;1004&quot; data-origin-width=&quot;1898&quot; data-origin-height=&quot;1004&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; font-family: 'Noto Serif KR';&quot;&gt;위와 같이 머지 승인 후 생성한 Feature 브랜치는 삭제된 것을 확인할 수 있다. 또한, Master 브랜치에 수정한 파일(Dockerfile)이 함께 반영된 것을 확인할 수 있다. 이때 Webhook을 걸어 CI/CD를 위한 파이프라인이 자동으로 동작하게 할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7; font-family: 'Noto Serif KR';&quot;&gt;# 참조 1&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Maintainer의 머지 승인 시 Source와 Target 간 Conflict가 발생하는 경우가 종종 발생한다. 이 경우 Maintainer는 Conflict를 수정하기 위해 local repository 환경에서 Conflict를 수정하고 직접 반영해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #006dd7; font-family: 'Noto Serif KR';&quot;&gt;# 참조 2&lt;/span&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Markdown 활용&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;GitLab Markdown을 활용하여 Document에 대한 가독성을 높일 수 있다. Markdown을 적용할 수 있는 부분 중 많이 활용되는 부분만 살펴보자면, Issue를 포함하여, Comment, MR 등에 활용된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;[Sample gitlab markdown]&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1642230662657&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 타이틀
타이틀은 30자 이내 간소하게

## 서브타이틀
서브타이틀은 50자 이내 간소하게

### 세부항목
세부항목은 최대한 자세하게

체크박스
- [ ] 본 이슈를 확인하셨습니까?

링크 거는 방법 [gitlab website](https://about.gitlab.com)

리스트
- item 1
- item 2
- item 3
- item 4

정렬
1. 대게
1. 가리비
1. 조개&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 작성하면,&amp;nbsp;&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;960&quot; data-origin-height=&quot;971&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDFgmR/btrqLv9yYKt/Y9RPCDXWVrhXEAkAmFio11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDFgmR/btrqLv9yYKt/Y9RPCDXWVrhXEAkAmFio11/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDFgmR/btrqLv9yYKt/Y9RPCDXWVrhXEAkAmFio11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDFgmR%2FbtrqLv9yYKt%2FY9RPCDXWVrhXEAkAmFio11%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;960&quot; height=&quot;971&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;971&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: 'Noto Serif KR'; color: #000000;&quot;&gt;와 같이 Markdown 형태로 나타난다. 물론 이보다 워낙 많은 Markdown 문법이 있지만, 간단하게 살펴만 보고, 보다 자세한 부분을 확인하고 싶을 경우 아래 URL을 참고한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;a href=&quot;https://docs.gitlab.com/ee/user/markdown.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://docs.gitlab.com/ee/user/markdown.html&lt;/a&gt; &lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1642231042828&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;GitLab Flavored Markdown | GitLab&quot; data-og-description=&quot;Documentation for GitLab Community Edition, GitLab Enterprise Edition, Omnibus GitLab, and GitLab Runner.&quot; data-og-host=&quot;docs.gitlab.com&quot; data-og-source-url=&quot;https://docs.gitlab.com/ee/user/markdown.html&quot; data-og-url=&quot;https://docs.gitlab.com/ee/user/markdown.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.gitlab.com/ee/user/markdown.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.gitlab.com/ee/user/markdown.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&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;GitLab Flavored Markdown | GitLab&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Documentation for GitLab Community Edition, GitLab Enterprise Edition, Omnibus GitLab, and GitLab Runner.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.gitlab.com&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: 'Noto Serif KR'; color: #000000;&quot;&gt;또는&amp;nbsp;폐쇄망 설치 시&amp;nbsp;http://gitlab_ip:gitlab_port/help/user/markdown로 접근 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;결론&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;MSA 환경에서는 민첩한 배포와 빈번한 배포가 발생하기 때문에 가능하면 배포가 간단하고 CI/CD 자동화 구성이 가능한 전략을 선택하는 것이 좋다. 반대로 대형 SI나 모놀리식 아키텍처 방식으로 개발을 진행할 경우 복잡하지만, 체계적인 브랜치 전략을 가져가는 것이 좋다. &lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;결론을 내리기 전에 마지막으로 브랜치 전략을 수립하는 것과 마찬가지로 반드시 지켜야 할 GitHub Flow 브랜치 규칙에 대해 알아보도록 하자.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;Master 브랜치는 직접 PUSH가 불가능하도록 protected 브랜치로 정의한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Feature 브랜치는 Master 브랜치를 기준으로 Clone하여, 신규 브랜치를 생성한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Developer는 Featrue 브랜치에 개발한 소스를 commit하고 push 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Master 브랜치에 반영하기 위해 Merge Request를 생성하여 코드리뷰 및 머지를 요청하며, Maintainer는 검토 후 머지승인을 진행한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Master 브랜치에서 배포를 위해 이력 관리가 효율적으로 이뤄질 수 있도록 tag를 생성하여 관리하는 것이 좋다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;간편한 전략일수록 보다 꼼꼼하게 브랜치를 관리해야 하는데, 이때 TAG를 활용할 수 있다. GitHub Flow의 경우 별도의 Release 브랜치가 존재하지 않기 때문에, Master는 항상 배포되어야 하며, 복구할 수 있어야 한다. 이때, Master 브랜치의 Release 버전을 관리하기 위해 tag를 생성해 두는 것이 좋다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;혹시나 특정 버전으로 revert하여 수정이 필요할 경우 tag를 직접 수정할수는 없지만 local branch로 내려받아 수정 후 remote branch에 반영할 수는 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;tag 활용 방법에 대한 자세한 내용은 다음을 참고한다.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;a href=&quot;https://waspro.tistory.com/670&quot;&gt;Git Branch &amp;amp; Tag를 활용한 프로젝트 배포 전략 마련하기&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;지금까지 GitLab 이슈를 활용한 브랜치 전략 및 개발 절차에 대해 알아보았다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;몇가지 브랜치 전략에 대해 알아보았지만, 어떠한 전략을 수립하는 것이 좋을지에 대해서는 여전히 프로젝트의 전략을 수립하는 아키텍처의 몫으로 남겨져 있다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;</description>
      <category>⑤ 개발, 데이터베이스/ⓒ CI CD</category>
      <category>git</category>
      <category>git flow</category>
      <category>GitLab</category>
      <category>gitlab branch</category>
      <category>gitlab issue</category>
      <category>gitlab mileston</category>
      <category>gitlab 권한</category>
      <category>gitlab 브랜치 전략</category>
      <category>markdown</category>
      <category>코드리뷰</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/710</guid>
      <comments>https://waspro.tistory.com/710#entry710comment</comments>
      <pubDate>Sun, 18 Jul 2021 14:58:49 +0900</pubDate>
    </item>
    <item>
      <title>Jenkins Multibranch Pipeline 활용</title>
      <link>https://waspro.tistory.com/707</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;서론&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Jenkins Job 중 Multibranch Pipeline을 활용하면 여러 Branch를 통합하여 하나의 Job 처럼 관리할 수 있다. 특히 Git flow와 같은 Branch 전략을 활용하기에 적합한 Job이라 할 수 있다. &lt;span style=&quot;color: #000000;&quot;&gt;Feature Branch와 같은 LifeCycle이 짧은 Branch와 Developer/Master와 같은 LifeCycle이 긴 Branch를 하나의 Pipeline으로 통합하여 관리할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;지금부터는 Jenkins에서 Multibranch Pipeline을 활용하여 GitHub Branch를 배포하는 과정에 대해 알아보자.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;MultiBranch Pipeline 구성&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Jenkins 설치 방법은 다음 포스팅을 참고한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7; font-family: 'Noto Serif KR';&quot;&gt;&lt;a style=&quot;color: #006dd7;&quot; href=&quot;https://waspro.tistory.com/551?category=857042&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[Jenkins] Jenkins 설치 가이드 : https://waspro.tistory.com/551?category=857042&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1) Jenkins / GitHub Credential&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Jenkins와 GitHub를 연동하기 위해서는 먼저 GitHub에 Access Token이 생성되어 있어야 한다. 아래의 과정을 통해 Access Token 생성 및 권한을 부여하고, Jenkins Credential에서 Token 기반 인증을 수행한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; Create GitHub Access Token&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; font-family: 'Noto Serif KR';&quot;&gt;GitHub Login&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Settings &amp;gt; Developer settings &amp;gt; Personal access tokens&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Generate new token&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;778&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baQkQB/btq9PTEecT5/LKiplD6bpZpY6k2dkhzzMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baQkQB/btq9PTEecT5/LKiplD6bpZpY6k2dkhzzMk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baQkQB/btq9PTEecT5/LKiplD6bpZpY6k2dkhzzMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaQkQB%2Fbtq9PTEecT5%2FLKiplD6bpZpY6k2dkhzzMk%2Fimg.png&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;778&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Access Token Name(Note) 설정 후 repo 전체 선택&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Generate token&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; Create Jenkins Credential&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: 'Noto Serif KR'; color: #000000;&quot;&gt;Jenkins 관리 &amp;gt; Manage Credentials &amp;gt; Credentials &amp;gt; System &amp;gt; Global credentials&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Add Credentials&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;918&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blcGF2/btq9RfG3k4N/B43v1njBJkPhQ63YzGpt3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blcGF2/btq9RfG3k4N/B43v1njBJkPhQ63YzGpt3k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blcGF2/btq9RfG3k4N/B43v1njBJkPhQ63YzGpt3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblcGF2%2Fbtq9RfG3k4N%2FB43v1njBJkPhQ63YzGpt3k%2Fimg.png&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;918&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Username : GitHub Username / Password : GitHub Access Token / ID : Unique ID&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; 추가된 Credential은 GitHub 인증 용도로 활용&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2) Multibranch Pipeline 생성&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;다음으로 동일 Project 내 여러 Branch를 단일 Job으로 관리하는 Multibranch Pipeline을 생성한다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;새로운 Item&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Multibranch Pipeline &amp;gt; OK&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cq4kTL/btq9LrvD9Vl/Wh6gvmv3lNQfHcWKIkNaf0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cq4kTL/btq9LrvD9Vl/Wh6gvmv3lNQfHcWKIkNaf0/img.png&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;918&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cq4kTL/btq9LrvD9Vl/Wh6gvmv3lNQfHcWKIkNaf0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcq4kTL%2Fbtq9LrvD9Vl%2FWh6gvmv3lNQfHcWKIkNaf0%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;962&quot; height=&quot;918&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cNORTL/btq9MD3HDsz/I9T240mS4k9MW8Qsgphyz1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cNORTL/btq9MD3HDsz/I9T240mS4k9MW8Qsgphyz1/img.png&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;918&quot; style=&quot;width: 49.4186%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cNORTL/btq9MD3HDsz/I9T240mS4k9MW8Qsgphyz1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcNORTL%2Fbtq9MD3HDsz%2FI9T240mS4k9MW8Qsgphyz1%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;962&quot; height=&quot;918&quot;/&gt;&lt;/span&gt;&lt;/div&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;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;General&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;918&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b83qmK/btq9KnmJzeh/KasJsEb64rwIzV6znZqqfk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b83qmK/btq9KnmJzeh/KasJsEb64rwIzV6znZqqfk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b83qmK/btq9KnmJzeh/KasJsEb64rwIzV6znZqqfk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb83qmK%2Fbtq9KnmJzeh%2FKasJsEb64rwIzV6znZqqfk%2Fimg.png&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;918&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; Display Name &amp;amp; Description : 구분 용도 / Pipeline에 영향을 주지 않음&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: 'Noto Serif KR'; color: #000000;&quot;&gt;Branch Sources&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;918&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcDcpo/btq9Ov4VUiW/GCXKuhNo6VWrjhifGKOW61/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcDcpo/btq9Ov4VUiW/GCXKuhNo6VWrjhifGKOW61/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcDcpo/btq9Ov4VUiW/GCXKuhNo6VWrjhifGKOW61/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcDcpo%2Fbtq9Ov4VUiW%2FGCXKuhNo6VWrjhifGKOW61%2Fimg.png&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;918&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; 추가하고자 하는 SCM(Source Code Management)를 선택. 본 포스팅에서는 GitHub 선택&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;692&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cxOp4q/btq9OHDVspu/wAjwHxN4nKr6vDqCL3uVH1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cxOp4q/btq9OHDVspu/wAjwHxN4nKr6vDqCL3uVH1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cxOp4q/btq9OHDVspu/wAjwHxN4nKr6vDqCL3uVH1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcxOp4q%2Fbtq9OHDVspu%2FwAjwHxN4nKr6vDqCL3uVH1%2Fimg.png&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;692&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; Credentials : 앞서 추가한 Credential 추가 / Repository HTTPS URL : GitHub URL&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; Credentials 입력 시 &quot;jenkins&amp;nbsp;invalid&amp;nbsp;credentials:&amp;nbsp;&lt;a href=&quot;https://api.github.com/user&quot;&gt;https://api.github.com/user&lt;/a&gt;&amp;nbsp;~~ &quot;가 나올 경우 상단의 1)&amp;nbsp;&lt;span style=&quot;color: #000000;&quot;&gt;Jenkins / GitHub Credential 과정이 제대로 수행되었는지 다시한번 검토한다. GitHub의 Access Token에 Repo 권한이 부여되어야만 Credential에 승인 받을 수 있으며, User sonnaraon과 같은 형태로 출력이 된다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;gt; Validate 버튼 클릭 시 &quot;Error validating repository information. Credentials ok.&quot; 에러가 발생할 경우 Credential은 통과하였지만, Repository 정보를 확인할 수 없을 경우이다. 이 경우 입력한 GitHub Repository URL을 다시 확인해 봐야 한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;1080&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Dmuin/btq9LqKjtGY/yueJhFf5kL4k1YQBZVQwqK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Dmuin/btq9LqKjtGY/yueJhFf5kL4k1YQBZVQwqK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Dmuin/btq9LqKjtGY/yueJhFf5kL4k1YQBZVQwqK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDmuin%2Fbtq9LqKjtGY%2FyueJhFf5kL4k1YQBZVQwqK%2Fimg.png&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;1080&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;gt; Discover branches Strategy : 탐색한 Branch를 선택하는 전략으로 All Branches / Exclude branches that are also filed as PRs / Only &lt;span style=&quot;color: #000000;&quot;&gt;branches that are also filed as PRs이 있으며, All Branches로 선택하여 테스트한다. 필요시 변경하여 수행한다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;gt; Filter by name (with regular expression) : Discover 전략에 해당되는 Branch 중 정규표현식으로 대상에 포함할 Branch를 재 선별한다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;gt; Filter by name (with wildcards) : Discover 전략에 해당되는 Branch 중 *로 대상에 포함할 Branch를 재 선별한다. Filter by name은 하나만 정해서 구성하는 것이 혼란을 막을 수 있다.&lt;/span&gt;&lt;/span&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: 'Noto Serif KR'; color: #000000;&quot;&gt;Build Configuration&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;956&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ba048w/btq9NRNVqCe/DNMZpmIJi2uoAvpkR53OK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ba048w/btq9NRNVqCe/DNMZpmIJi2uoAvpkR53OK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ba048w/btq9NRNVqCe/DNMZpmIJi2uoAvpkR53OK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fba048w%2Fbtq9NRNVqCe%2FDNMZpmIJi2uoAvpkR53OK0%2Fimg.png&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;956&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; 마지막으로 Build Configuration의 Script Path 즉 Jenkinsfile이 위치하고 있는 파일의 경로와 이름을 지정하고 Save 버튼으로 저장한다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;Scan Repository Log&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;956&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mmbfG/btq9Nw3XBCh/GOYX4DQZlKUpFgExYtsldK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mmbfG/btq9Nw3XBCh/GOYX4DQZlKUpFgExYtsldK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mmbfG/btq9Nw3XBCh/GOYX4DQZlKUpFgExYtsldK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmmbfG%2Fbtq9Nw3XBCh%2FGOYX4DQZlKUpFgExYtsldK%2Fimg.png&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;956&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; 정상적으로 추가되었을 경우 아래와 같이 Scan Repository Log가 출력된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1626505261537&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Started
[Sat Jul 17 06:59:05 UTC 2021] Starting branch indexing...
Connecting to https://api.github.com using nara0617@gmail.com/****** (son.nara)
Examining sonnaraon/multibranch
  Checking branches...
  Getting remote branches...
    Checking branch master
      &amp;lsquo;Jenkinsfile&amp;rsquo; found
    Met criteria
Scheduled build for branch: master
  1 branches were processed
  Checking pull-requests...
  Getting remote pull requests...
  0 pull requests were processed
Finished examining sonnaraon/multibranch
[Sat Jul 17 06:59:07 UTC 2021] Finished branch indexing. Indexing took 1.7 sec
Finished: SUCCESS&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; 위 로그와 같이 GitHub Connecting 성공 / sonnaraon/multibranch Checking 성공 상태 확인&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: 'Noto Serif KR'; color: #000000;&quot;&gt;빌드 기록&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;956&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rPOqe/btq9RdbidZH/u0teLnuenNQVbWk1RE9zI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rPOqe/btq9RdbidZH/u0teLnuenNQVbWk1RE9zI0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rPOqe/btq9RdbidZH/u0teLnuenNQVbWk1RE9zI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrPOqe%2Fbtq9RdbidZH%2Fu0teLnuenNQVbWk1RE9zI0%2Fimg.png&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;956&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 Master Branch의 Pipeline이 동작하는 것을 확인할 수 있다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;블루 오션 열기&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cM1XZE/btq9ReIbH2I/tLHmmhCDfN43hixUNxg98K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cM1XZE/btq9ReIbH2I/tLHmmhCDfN43hixUNxg98K/img.png&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;918&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cM1XZE/btq9ReIbH2I/tLHmmhCDfN43hixUNxg98K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcM1XZE%2Fbtq9ReIbH2I%2FtLHmmhCDfN43hixUNxg98K%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;962&quot; height=&quot;918&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/liPLH/btq9R4SQjbW/EytbRc9VUKkpYMtsGhZK30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/liPLH/btq9R4SQjbW/EytbRc9VUKkpYMtsGhZK30/img.png&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;918&quot; style=&quot;width: 49.4186%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/liPLH/btq9R4SQjbW/EytbRc9VUKkpYMtsGhZK30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FliPLH%2Fbtq9R4SQjbW%2FEytbRc9VUKkpYMtsGhZK30%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;962&quot; height=&quot;918&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; 마지막으로 블루 오션 열기를 선택한다. 파이프라인을 GUI 환경에서 확인 가능하도록 도와주는 플러그인으로 설치되어 있지 않을 경우 Blue Ocean을 검색하여 설치하도록 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; 현재 Master Branch에 문제가 있어 에러로 출력되는 상태이며, 상세 로그도 확인할 수 있다. &lt;span style=&quot;color: #000000;&quot;&gt;로그 확인 후 문제를 수정하고 Commit&amp;amp;Push를 수행해보자.&lt;/span&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: 'Noto Serif KR'; color: #000000;&quot;&gt;Commit &amp;amp; Push&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;에러가 발생한 Jenkinsfile을 수정하고 Commit&amp;amp;Push를 수행하면, 다음과 같이 정상으로 분기되는 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;918&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KA8IB/btq9MEIhQGH/9UCrTUNG0jM9yGh1C5DLxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KA8IB/btq9MEIhQGH/9UCrTUNG0jM9yGh1C5DLxk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KA8IB/btq9MEIhQGH/9UCrTUNG0jM9yGh1C5DLxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKA8IB%2Fbtq9MEIhQGH%2F9UCrTUNG0jM9yGh1C5DLxk%2Fimg.png&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;918&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Multibranch pipeline Webhook (With GitHub)&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Jenkins에서 Multibranch Pipeline의 Webhook을 구현하기 위해서는 먼저 다음 플러그인을 구성해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Jenkins 관리 &amp;gt; Plugin Manager에서 아래 플러그인 리스트가 설치되어 있는지 확인한다. 설치되어 있지 않을 경우 설치를 진행한 후 Pipeline을 구성한다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;Pipeline: Multibranch&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Multibranch Scan Webhook Trigger&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Multibranch Pipeline 설정 시 위 플러그인이 구성되어 있을 경우 다음과 같은 설정을 진행할 수 있다.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&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: 'Noto Serif KR'; color: #000000;&quot;&gt;Scan Multibranch Pipeline Triggers&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;1004&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bU9gjT/btq9R55Tsxa/FxohnUj9KprbAhYdhAXZ7k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bU9gjT/btq9R55Tsxa/FxohnUj9KprbAhYdhAXZ7k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bU9gjT/btq9R55Tsxa/FxohnUj9KprbAhYdhAXZ7k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbU9gjT%2Fbtq9R55Tsxa%2FFxohnUj9KprbAhYdhAXZ7k%2Fimg.png&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;1004&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; Scan Multibranch Pipeline Triggers : Periodically if not otherwise run (pipeline 검증 주기) / Scan by webhook 체크&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Scan Multibranch Pipeline Triggers의 갱신 주기를 통해 Trigger를 탐색한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c6s0X1/btq9OwDoCQB/Bq0nDXAHvz1nqtRDIWJcsK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c6s0X1/btq9OwDoCQB/Bq0nDXAHvz1nqtRDIWJcsK/img.png&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;1004&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c6s0X1/btq9OwDoCQB/Bq0nDXAHvz1nqtRDIWJcsK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc6s0X1%2Fbtq9OwDoCQB%2FBq0nDXAHvz1nqtRDIWJcsK%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;960&quot; height=&quot;1004&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/y09FO/btq9OxoL6Yy/uHWRKmW88Msbp5zVLVWIkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/y09FO/btq9OxoL6Yy/uHWRKmW88Msbp5zVLVWIkk/img.png&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;1004&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; style=&quot;width: 49.4186%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/y09FO/btq9OxoL6Yy/uHWRKmW88Msbp5zVLVWIkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fy09FO%2Fbtq9OxoL6Yy%2FuHWRKmW88Msbp5zVLVWIkk%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;960&quot; height=&quot;1004&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; 위와 같이 &lt;span style=&quot;color: #000000;&quot;&gt;Periodically if not otherwise run 주기 마다 빌드 파이프라인을 검증하고 빌드를 수행할 필요가 있는지 여부를 확인하여 자동으로 빌드를 수행한다. Multibranch Pipeline의 왼쪽 메뉴바를 통해 기능을 검증할 수 있다.&lt;/span&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; font-family: 'Noto Serif KR';&quot;&gt;Scan Repository Now : 즉시 Scan하여 빌드 대상을 탐색한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Scan Repository Log : Scan 결과를 확인한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;빌드 기록 : 빌드 기록을 확인한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;블루 오션 열기 : 파이프라인을 GUI 환경을 확인하기 위해 블루 오션에 접속한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;결론&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;위 기능들을 활용하여 multibranch pipeline 환경에서 다수의 브랜치를 통합하여 관리할 수 있도록 구성할 수 있다. 이 기능을 활용하면 MSA와 같은 복잡한 배포 프로세스 환경을 보다 간결하게 구성할 수 있으며, 다양한 Branch 관리 전략에 대입하여 효과적인 코드 관리 및 배포를 수행할 수 있다.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;다음 포스팅에서는 Multibrach Pipeline을 적용한 Git Branch Strategy에 대해 알아보도록 하자.&lt;/span&gt;&lt;/p&gt;</description>
      <category>⑤ 개발, 데이터베이스/ⓒ CI CD</category>
      <category>branch strategy</category>
      <category>git branch</category>
      <category>jenkins blue ocean</category>
      <category>jenkins multibranch</category>
      <category>jenkins 블루 오션</category>
      <category>multibranch</category>
      <category>multibranch pipeline</category>
      <category>Periodically if not otherwise run</category>
      <category>Scan Multibranch Pipeline Triggers</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/707</guid>
      <comments>https://waspro.tistory.com/707#entry707comment</comments>
      <pubDate>Tue, 6 Jul 2021 23:53:14 +0900</pubDate>
    </item>
    <item>
      <title>Tekton Pipeline 설계</title>
      <link>https://waspro.tistory.com/706</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;개요&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;앞서 살펴본 포스팅을 통해 Tekton에 대해 알아보았다. 사실 오픈소스의 시장 점유율이 높아짐에 따라 CNCF에 공개된 Cloud Native 소프트웨어들은 주목도가 높아지고 있는 것이 사실이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Tekton Previous Posting : &lt;a href=&quot;https://waspro.tistory.com/705&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Tekton Pipeline 작성&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;CNCF : &lt;a href=&quot;https://landscape.cncf.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://landscape.cncf.io/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이와 같은 맥락으로 Continuous Develivery에 대해 관리하는 CDF라는 조직을 통해 현재 Tekton은 물론 CD 진영의 주요 활동에 대해 알아 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;CDF :&lt;/span&gt; &lt;a style=&quot;color: #006dd7;&quot; href=&quot;https://cd.foundation/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://cd.foundation/&lt;/a&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;현재 CD Foundation Project로 등록되어 있는 오픈소스 소프트웨어는 Jenkins, Jenkins X, Spinnaker 그리고 Tekton 4개이다. Incubating 단계의 Project는 Screwdriver, Ortelius가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;사실 앞서 많은 포스팅에서 Jenkins 플러그인 기반으로 대부분의 CD를 구현해 왔지만(일부 Spinnaker 활용에 대한 포스팅이 있긴 했음), Jenkins는 CD보다는 CI에 어울리는 도구로 CD에 특화된 Jenkins X, Spinnaker, Tekton에 대한 활용성을 높여가야 할 필요가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Tekton은 대표적인 CD 도구로 환영받고 있으며, 최근 OpenShift의 CD 도구로 정식 채택되기도 하였다. Tekton의 확장성과 높은 재활용성 그리고 무엇보다 안정적인 성능에 대해 높게 평가받고 있다는 의견이 지배적이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;이번 포스팅에서는 Tekton에 대해 추가적으로 논의해보고, Tekton을 활용한 CI/CD를 설계해 보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Tekton 구조&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;앞선 포스팅에서도 살펴봤듯이 Tekton은 Step, Task, Pipeline으로 구성되어 있다. Step &amp;gt; Task(Steps) &amp;gt; Pipeline(Tasks)라고 표현할 수 있듯 각각의 하위 집합으로 표현될 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Jenkins 포스팅에서는 다음과 같은 집합으로 설계를 진행했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Jenkins Previous Posting : &lt;a href=&quot;https://waspro.tistory.com/573?category=857042&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Kubernetes Jenkins - 자동 배포환경 구성 (1/2)&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Jenkins는 Step, Stage, Pipeline으로 구성되어 있다. Tekton과 마찬가지로 Step &amp;gt; Stage(Steps) &amp;gt; Pipeline(Stages)로 구성되어 있다. 구조 자체만 놓고 보았을때 Tekton과 Jenkins는 크게 차별점이 없다고 볼 수 있다. &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;다만, 재활용성 측면에서 Tekton의 강점을 확인할 수 있으며, 이는 클라우드 네이티브 진형에 어울리는 CD 도구임을 입증한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;Tekton은 Task를 정의하고 이를 Pipeline에서 순서를 정하는 방식으로 활용하기 때문에 한번 정의한 Task는 또 다른 Pipeline에서 활용할 수 있다. 이와 반대로 Jenkins의 경우, Script 또는 Jenkinsfile에 정의하는 방식을 사용하기 때문에 모든 프로젝트 별로 빌드를 위한 파일이 존재해야 한다. 이는 TravisCD 역시 동일하다.(.travis.yml) 이로 인해 Stage의 내용이 중복되더라도 또 다시 복사하여 동일 내용을 정의해야 한다. 이는 사실 번거로움을 떠나, 마이크로서비스 아키텍처와 같이 확장되는 서비스 환경에서 특히 중요한 요소이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;예를 들어, 100개의 마이크로서비스 환경에서 동일하게 사용하는 git clone이라는 동작에 대해 수정사항이 발생했을 경우를 생각해보자. Jenkins나 TravisCD의 경우 프로젝트 별로 생성되어 있는 배포 파일을 수정하여 각각 저장해 주어야 한다. 이는 단순작업을 떠나, 수동으로 동일한 작업을 반복적으로 수행함에 있어, 오류를 발생시킬 가능성이 높아지게 되고, 장애로 이어질 수 있는 포인트가 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;반대로 Tekton은 git clone이라는 동작을 하나의 Task로 정의하고 해당 Task를 재정의함으로써 반영의 효율성을 높일 수 있다. 이는 운영 유지보수 편의성은 물론 Task를 공통으로 정의함으로써 빌드/배포에 대한 표준화를 유도하고, 저장소 통합, 라이프사이클 관리 등을 중앙에서 통제할 수 있도록 관리함으로써, 높은 수준의 DevOps 조직을 구성하고자 하는 조직에 적합한 CD 도구라 할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1258&quot; data-origin-height=&quot;552&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZoVbU/btq8HejUTBE/hGpV6thgXVffFLO98UjHO0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZoVbU/btq8HejUTBE/hGpV6thgXVffFLO98UjHO0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZoVbU/btq8HejUTBE/hGpV6thgXVffFLO98UjHO0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZoVbU%2Fbtq8HejUTBE%2FhGpV6thgXVffFLO98UjHO0%2Fimg.png&quot; data-origin-width=&quot;1258&quot; data-origin-height=&quot;552&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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: 'Noto Serif KR'; color: #000000;&quot;&gt;다음은 Tekton을 활용한 Pipeline 아키텍처 예시이다. Tekton은 Task와 Pipeline을 Kubernetes 오브젝트로 관리하기 때문에 뛰어난 재사용성을 보장한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;재사용성을 높이기 위해서는 다음과 같은 기준을 두고 설계하는 것이 효과적이다. &lt;span style=&quot;color: #000000;&quot;&gt;아래와 같이 정의할 경우 공통 요소에 대한 일괄 반영은 물론 각 서비스 별 특징을 살려 파이프라인을 설계할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;a. Task에서는 모든 서비스에서 공통으로 사용하는 param을 정의한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;b. Pipeline에서는 각 서비스 별로 정의하는 param을 정의한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위 5단계의 배포 과정에 정적분석, Code Inspector, Code Coverage, Image Scan, Health Checker, 승인 프로세스 등을 포함하여 확장된 아키텍처를 설계할 수 있다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>⑤ 개발, 데이터베이스/ⓒ CI CD</category>
      <category>TEKTON</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/706</guid>
      <comments>https://waspro.tistory.com/706#entry706comment</comments>
      <pubDate>Mon, 5 Jul 2021 00:35:34 +0900</pubDate>
    </item>
    <item>
      <title>Tekton pipeline 작성</title>
      <link>https://waspro.tistory.com/705</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Overview&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Tekton은 CI/CD를 위한 클라우드 네이티브 솔루션으로 CSP 3사는 물론, On-premise 환경의 Kubernetes를 모두 지원하며, build, test, deploy를 기능을 제공한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;410&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhcO9D/btq8GDxmOj6/sJ3QXg31x5HcHXvVjTtwdk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhcO9D/btq8GDxmOj6/sJ3QXg31x5HcHXvVjTtwdk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhcO9D/btq8GDxmOj6/sJ3QXg31x5HcHXvVjTtwdk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhcO9D%2Fbtq8GDxmOj6%2FsJ3QXg31x5HcHXvVjTtwdk%2Fimg.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;410&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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: 'Noto Serif KR'; color: #000000;&quot;&gt;Tekton은 언어 및 배포 환경 전반에서 CI / CD 도구 및 프로세스를 표준화한다. 특히 복잡한 MSA 환경에서 배포 환경을 통합하여 구성하기 용이한 구조로 되어 있다. Jenkins, Jenkins X, Spinnker, Skaffold, Knative 등 다양한 CI/CD 도구와 통합할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;728&quot; data-origin-height=&quot;511&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/co6ILD/btq8GQcnFLA/CbzYWvIx5tcabi4MliIZkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/co6ILD/btq8GQcnFLA/CbzYWvIx5tcabi4MliIZkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/co6ILD/btq8GQcnFLA/CbzYWvIx5tcabi4MliIZkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fco6ILD%2Fbtq8GQcnFLA%2FCbzYWvIx5tcabi4MliIZkK%2Fimg.png&quot; data-origin-width=&quot;728&quot; data-origin-height=&quot;511&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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: 'Noto Serif KR'; color: #000000;&quot;&gt;Tekton은 Step, Task, Pipeline, Pipeline Resource로 구성되어 있으며, Task와 Pipeline을 기동하는 TaskRun, PipelineRun 오브젝트가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;- Step : Step&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;은 컴파일, 이미지 생성, 이미지 저장 등 일련의 작업을 실행하는 하위 명령어이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;- Task : Task&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;는 Step의 모음이다. Step은 Kubernetes 환경에서 Pod로 기동되며, Task는 이 Step 들의 그룹이라 볼 수 있다. 예를 들어 Step에 git clone, git push 등의 명령어를 실행한다면, 이들을 묶어 git-clone이라는 Task로 정의한다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;- TaskRun : Task를 실행하는 오브젝트이다. Task에 변수를 할당하거나, input/output을 정의하는 역할을 한다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1625369228751&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[task sample]

apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: build-docker-image-from-git-source
spec:
  params:
    - name: pathToDockerFile
      type: string
      description: The path to the dockerfile to build
      default: $(resources.inputs.docker-source.path)/Dockerfile
    - name: pathToContext
      type: string
      description: |
        The build context used by Kaniko
        (https://github.com/GoogleContainerTools/kaniko#kaniko-build-contexts)
      default: $(resources.inputs.docker-source.path)
  resources:
    inputs:
      - name: docker-source
        type: git
    outputs:
      - name: builtImage
        type: image
  steps:
    - name: build-and-push
      image: gcr.io/kaniko-project/executor:v0.16.0
      # specifying DOCKER_CONFIG is required to allow kaniko to detect docker credential
      env:
        - name: &quot;DOCKER_CONFIG&quot;
          value: &quot;/tekton/home/.docker/&quot;
      command:
        - /kaniko/executor
      args:
        - --dockerfile=$(params.pathToDockerFile)
        - --destination=$(resources.outputs.builtImage.url)
        - --context=$(params.pathToContext)
        
[taskRun sample]
apiVersion: tekton.dev/v1beta1
kind: TaskRun
metadata:
  name: build-docker-image-from-git-source-task-run
spec:
  serviceAccountName: tutorial-service
  taskRef:
    name: build-docker-image-from-git-source
  params:
    - name: pathToDockerFile
      value: Dockerfile
    - name: pathToContext
      value: $(resources.inputs.docker-source.path)/examples/microservices/leeroy-web #configure: may change according to your source
  resources:
    inputs:
      - name: docker-source
        resourceRef:
          name: skaffold-git
    outputs:
      - name: builtImage
        resourceRef:
          name: skaffold-image-leeroy-web&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;- Pipeline : &lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;Pipeline은 Task의 모음이다. Task의 순서를 정의하고, 실행 시점에 파라미터를 정의할 수 있다. 이로 인해 Task는 Template으로써 재사용이 가능한 형태가 된다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1625369166854&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[pipeline sample]

apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
  name: tutorial-pipeline
spec:
  resources:
    - name: source-repo
      type: git
    - name: web-image
      type: image
  tasks:
    - name: build-skaffold-web
      taskRef:
        name: build-docker-image-from-git-source
      params:
        - name: pathToDockerFile
          value: Dockerfile
        - name: pathToContext
          value: /workspace/docker-source/examples/microservices/leeroy-web #configure: may change according to your source
      resources:
        inputs:
          - name: docker-source
            resource: source-repo
        outputs:
          - name: builtImage
            resource: web-image
    - name: deploy-web
      taskRef:
        name: deploy-using-kubectl
      resources:
        inputs:
          - name: source
            resource: source-repo
          - name: image
            resource: web-image
            from:
              - build-skaffold-web
      params:
        - name: path
          value: /workspace/source/examples/microservices/leeroy-web/kubernetes/deployment.yaml #configure: may change according to your source
        - name: yamlPathToImage
          value: &quot;spec.template.spec.containers[0].image&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;- PipelineRun : Pipeline을 실행하는 오브젝트이다. Pipeline도 재활용성을 높이기 위해 PipelineRun에 변수할당 및 input/output을 정의할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;PipelineResource : Pipeline에서 사용하는 리소스로 Git Repository, Image Repository 등이 있다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;실제 논리적인 연관도를 보자면, Step &amp;gt; Task &amp;gt; Pipeline &amp;gt; PipelineRun으로 이어진다고 볼 수 있다. TaskRun의 경우 Task &amp;gt; TaskRun으로 동작한다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;Tekton에서는 RWO모드의 볼륨을 사용하는 경우를 대비하여 Affinity Assistants라는 기능을 제공하고 있다. Affinity Assistants는 Pipeline 내 모든 Task를 같은 Node에 배치하게 하는 역할을 한다. &lt;br /&gt;또한, PodTemplate을 따로 만들어 NodeSelector나 Tolerations를 설정했다고 해도 Affinity Assistant가 그 설정들을 오버라이드한다. 이를 활용하면, task들이 동일한 노드에서 기동되어 볼륨 이슈를 방지할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Tekton 설치&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Tekton을 설치하기 위해서는 먼저 Kubernetes 1.16 이상의 환경이 준비되어 있어야 한다. 이번 포스팅은 Amazon EKS를 통해 테스트를 실행해 보도록 하자.&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1) Tekton Pipeline 설치&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1625273288609&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;kubectl apply --filename https://storage.googleapis.com/tekton-releases/pipeline/latest/release.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2) Tekton Dashboard &amp;amp; Trigger 설치&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1625273392657&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;kubectl apply --filename https://github.com/tektoncd/dashboard/releases/download/v0.6.0/tekton-dashboard-release.yaml
kubectl apply --filename https://storage.googleapis.com/tekton-releases/triggers/latest/release.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;3) Tekton Ingress Dashboard 설치&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1625273613417&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: tekton-dashboard
  namespace: tekton-pipelines
  annotations:
    kubernetes.io/ingress.class: alb
    alb.ingress.kubernetes.io/target-type: ip
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/subnets: subnet-xxxxxxxx,subnet-xxxxxxxx
spec:
  rules:
  - http:
      paths:
      - backend:
          serviceName: tekton-dashboard
          servicePort: 9097&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; 9097 서비스 포트를 사용하는 tekton-dashboard에 접근하기 위한 ingress를 구성한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;4) 설치 확인&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1625273432283&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-71-110 eks]# kubectl get all -n tekton-pipelines
NAME                                               READY   STATUS    RESTARTS   AGE
pod/tekton-dashboard-748fb458c7-9lhpr              1/1     Running   0          8h
pod/tekton-pipelines-controller-558cc574b7-dxqvx   1/1     Running   0          8h
pod/tekton-pipelines-webhook-575b9bcd9f-5srdv      1/1     Running   0          8h

NAME                                  TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                              AGE
service/tekton-dashboard              ClusterIP   10.100.199.143   &amp;lt;none&amp;gt;        9097/TCP                             8h
service/tekton-pipelines-controller   ClusterIP   10.100.105.128   &amp;lt;none&amp;gt;        9090/TCP,8080/TCP                    8h
service/tekton-pipelines-webhook      ClusterIP   10.100.138.201   &amp;lt;none&amp;gt;        9090/TCP,8008/TCP,443/TCP,8080/TCP   8h

NAME                                          READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/tekton-dashboard              1/1     1            1           8h
deployment.apps/tekton-pipelines-controller   1/1     1            1           8h
deployment.apps/tekton-pipelines-webhook      1/1     1            1           8h

NAME                                                     DESIRED   CURRENT   READY   AGE
replicaset.apps/tekton-dashboard-748fb458c7              1         1         1       8h
replicaset.apps/tekton-pipelines-controller-558cc574b7   1         1         1       8h
replicaset.apps/tekton-pipelines-webhook-575b9bcd9f      1         1         1       8h

NAME                                                           REFERENCE                             TARGETS          MINPODS   MAXPODS   REPLICAS   AGE
horizontalpodautoscaler.autoscaling/tekton-pipelines-webhook   Deployment/tekton-pipelines-webhook   &amp;lt;unknown&amp;gt;/100%   1         5         1          8h
[root@ip-192-168-71-110 eks]# &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;5) tkn 설치&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1625274778930&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-71-110 eks]# curl -LO https://github.com/tektoncd/cli/releases/download/v0.8.0/tkn_0.8.0_Linux_x86_64.tar.gz
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   637  100   637    0     0   2242      0 --:--:-- --:--:-- --:--:--  2242
100  9.7M  100  9.7M    0     0  4613k      0  0:00:02  0:00:02 --:--:-- 5965k
[root@ip-192-168-71-110 eks]# sudo tar xvzf tkn_0.8.0_Linux_x86_64.tar.gz -C /usr/local/bin/ tkn
tkn
[root@ip-192-168-71-110 eks]# tkn version
Client version: 0.8.0
Pipeline version: unknown
[root@ip-192-168-71-110 eks]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;6) Dashboard 접속 (http://alb_ip:alb_port)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;950&quot; data-origin-height=&quot;699&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cuUjUt/btq8JjjyB4w/5GaGxpJXH73Re3p4X1SFN0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cuUjUt/btq8JjjyB4w/5GaGxpJXH73Re3p4X1SFN0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cuUjUt/btq8JjjyB4w/5GaGxpJXH73Re3p4X1SFN0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcuUjUt%2Fbtq8JjjyB4w%2F5GaGxpJXH73Re3p4X1SFN0%2Fimg.png&quot; data-origin-width=&quot;950&quot; data-origin-height=&quot;699&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Tekton CLI 구성&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;먼저 tekton pipeline을 구성하기 전 tkn cli를 활용한 배포구성을 진행해 보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1) Task&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;다음은 Ubuntu 이미지를 기반으로 echo &quot;Hello World!&quot;를 출력하는 Task이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1625275685929&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: hello
spec:
  steps:
    - name: hello
      image: ubuntu
      command:
        - echo
      args:
        - &quot;Hello World!&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; task가 작성되면, 다음과 같이 반영하고 확인한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1625277913187&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-71-110 tekton]# kubectl apply -f hello.yaml 
task.tekton.dev/hello created
[root@ip-192-168-71-110 tekton]# kubectl get task --all-namespaces
NAMESPACE   NAME    AGE
default     hello   58m
[root@ip-192-168-71-110 tekton]# &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;) TaskRun&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;앞서 생성한 Task를 실행하기 위해서는 TaskRun을 생성해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1625278479954&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-71-110 tekton]# tkn task start hello --dry-run
apiVersion: tekton.dev/v1alpha1
kind: TaskRun
metadata:
  creationTimestamp: null
  generateName: hello-run-
  namespace: default
spec:
  inputs: {}
  outputs: {}
  serviceAccountName: &quot;&quot;
  taskRef:
    name: hello
  timeout: 1h0m0s
status:
  podName: &quot;&quot;
[root@ip-192-168-71-110 tekton]# tkn task start hello
Taskrun started: hello-run-xkmwc

In order to track the taskrun progress run:
tkn taskrun logs hello-run-xkmwc -f -n default
[root@ip-192-168-71-110 tekton]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; tkn task start [task_name]은 TaskRun을 자동으로 정의하며, task를 실행한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;3) Task log&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1625278705715&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-71-110 tekton]# tkn taskrun logs --last -f 
[hello] Hello World!

[root@ip-192-168-71-110 tekton]# tkn task list
NAME      AGE
goodbye   5 hours ago
hello     7 hours ago
[root@ip-192-168-71-110 tekton]# tkn taskrun list
NAME                                            STARTED       DURATION     STATUS               
hello-goodbye-run-rmrvm-r-2nr7d-goodbye-ljrnn   1 hour ago    10 seconds   Succeeded   
hello-goodbye-run-rmrvm-r-2nr7d-hello-dmz86     1 hour ago    9 seconds    Succeeded   
hello-goodbye-run-rmrvm-goodbye-wq5v4           5 hours ago   8 seconds    Succeeded   
hello-goodbye-run-rmrvm-hello-4lkl2             5 hours ago   8 seconds    Succeeded   
goodbye-run-fz724                               5 hours ago   12 seconds   Succeeded   
hello-run-xkmwc                                 7 hours ago   14 seconds   Succeeded   
[root@ip-192-168-71-110 tekton]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; echo로 출력한 Hello World!가 출력되는 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;4) 대시보드 확인&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lRjBo/btq8IDWVrfE/SPSKg43DQRBKuI9V4fYMz1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lRjBo/btq8IDWVrfE/SPSKg43DQRBKuI9V4fYMz1/img.png&quot; data-origin-width=&quot;949&quot; data-origin-height=&quot;700&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lRjBo/btq8IDWVrfE/SPSKg43DQRBKuI9V4fYMz1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlRjBo%2Fbtq8IDWVrfE%2FSPSKg43DQRBKuI9V4fYMz1%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;949&quot; height=&quot;700&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/clDmr9/btq8HTlDGol/hoglZ77hN1oG8I0vKzMmWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/clDmr9/btq8HTlDGol/hoglZ77hN1oG8I0vKzMmWK/img.png&quot; data-origin-width=&quot;949&quot; data-origin-height=&quot;700&quot; style=&quot;width: 49.4186%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/clDmr9/btq8HTlDGol/hoglZ77hN1oG8I0vKzMmWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FclDmr9%2Fbtq8HTlDGol%2FhoglZ77hN1oG8I0vKzMmWK%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;949&quot; height=&quot;700&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; 대시보드에 작성한 Task와 TaskRun이 등록되어 있는것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Tekton Pipeline 구성&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이번에는 Pipeline을 구성해 보자. Pipeline은 이미지를 생성하고 배포하고 또는 일련의 여러 과정을 파이프라인으로 묶어 하나의 프로세스가 동작하듯 제어하고 관리할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;앞서 생성한 Hello Task와 함께 GoodBye Task를 생성하여 Pipeline으로 묶어 동작하는 것을 확인해 보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1) Task&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;다음은 Ubuntu 이미지를 기반으로 echo &quot;Goodbye World!&quot;를 출력하는 Task이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1625279264938&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: goodbye
spec:
  steps:
    - name: goodbye
      image: ubuntu
      script: |
        #!/bin/bash
        echo &quot;Goodbye World!&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; task가 작성되면, 다음과 같이 반영하고 확인한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1625279414227&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-71-110 tekton]# kubectl apply -f goodbye.yaml 
task.tekton.dev/goodbye created
[root@ip-192-168-71-110 tekton]# kubectl get task --all-namespaces
NAMESPACE   NAME      AGE
default     goodbye   37s
default     hello     83m
[root@ip-192-168-71-110 tekton]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;) TaskRun&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;앞서 생성한 Task를 실행하기 위해서는 TaskRun을 생성해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1625279414228&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-71-110 tekton]# tkn task start goodbye
Taskrun started: goodbye-run-fz724

In order to track the taskrun progress run:
tkn taskrun logs goodbye-run-fz724 -f -n default
[root@ip-192-168-71-110 tekton]# &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; tkn task start [task_name]은 TaskRun을 자동으로 정의하며, task를 실행한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;3) Task log&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1625279414228&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-71-110 tekton]# tkn taskrun logs --last -f 
[goodbye] Goodbye World!

[root@ip-192-168-71-110 tekton]# tkn task list
NAME      AGE
goodbye   5 hours ago
hello     7 hours ago
[root@ip-192-168-71-110 tekton]# tkn taskrun list
NAME                                            STARTED       DURATION     STATUS               
hello-goodbye-run-rmrvm-r-2nr7d-goodbye-ljrnn   1 hour ago    10 seconds   Succeeded   
hello-goodbye-run-rmrvm-r-2nr7d-hello-dmz86     1 hour ago    9 seconds    Succeeded   
hello-goodbye-run-rmrvm-goodbye-wq5v4           5 hours ago   8 seconds    Succeeded   
hello-goodbye-run-rmrvm-hello-4lkl2             5 hours ago   8 seconds    Succeeded   
goodbye-run-fz724                               5 hours ago   12 seconds   Succeeded   
hello-run-xkmwc                                 7 hours ago   14 seconds   Succeeded   
[root@ip-192-168-71-110 tekton]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;4) 대시보드 확인&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dKXRZY/btq8HS77gHo/77OZ9o4UmXhPksXqWnK88K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dKXRZY/btq8HS77gHo/77OZ9o4UmXhPksXqWnK88K/img.png&quot; data-origin-width=&quot;949&quot; data-origin-height=&quot;700&quot; style=&quot;width: 49.4799%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dKXRZY/btq8HS77gHo/77OZ9o4UmXhPksXqWnK88K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdKXRZY%2Fbtq8HS77gHo%2F77OZ9o4UmXhPksXqWnK88K%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;949&quot; height=&quot;700&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Kisxl/btq8GnuwvAj/7vkIu5iMB4d7o6ploKNjW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Kisxl/btq8GnuwvAj/7vkIu5iMB4d7o6ploKNjW1/img.png&quot; data-origin-width=&quot;948&quot; data-origin-height=&quot;701&quot; style=&quot;width: 49.3573%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Kisxl/btq8GnuwvAj/7vkIu5iMB4d7o6ploKNjW1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKisxl%2Fbtq8GnuwvAj%2F7vkIu5iMB4d7o6ploKNjW1%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;948&quot; height=&quot;701&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; 대시보드에 작성한 Task와 TaskRun이 등록되어 있는것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;5) Pipeline&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1625279673203&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
  name: hello-goodbye
spec:
  tasks:
  - name: hello
    taskRef:
      name: hello
  - name: goodbye
    runAfter:
     - hello
    taskRef:
      name: goodbye&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; 위와 같이 taskRef/runAfter를 활용하여 task 실행 순서를 정의한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1625279909898&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-71-110 tekton]# kubectl apply -f hello-goodbye.yaml 
pipeline.tekton.dev/hello-goodbye created
[root@ip-192-168-71-110 tekton]# kubectl get pipeline 
NAME            AGE
hello-goodbye   53s
[root@ip-192-168-71-110 tekton]# &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; 위와 같이 Pipeline 오브젝트가 생성된것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;6) PipelineRun&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; Pipeline을 실행하기 위해서는 PipelineRun을 생성해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1625280035266&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-71-110 tekton]# tkn pipeline start hello-goodbye --dry-run
apiVersion: tekton.dev/v1alpha1
kind: PipelineRun
metadata:
  creationTimestamp: null
  generateName: hello-goodbye-run-
  namespace: default
spec:
  pipelineRef:
    name: hello-goodbye
  timeout: 1h0m0s
status: {}
[root@ip-192-168-71-110 tekton]# tkn pipeline start hello-goodbye
Pipelinerun started: hello-goodbye-run-rmrvm

In order to track the pipelinerun progress run:
tkn pipelinerun logs hello-goodbye-run-rmrvm -f -n default
[root@ip-192-168-71-110 tekton]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;tkn pipeline start [pipeline_name]은 PipelineRun을 자동으로 정의하며, Pipeline을 실행한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;7) Pipeline log&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1625280118456&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-71-110 tekton]# tkn pipelinerun logs --last -f 
[hello : hello] Hello World!

[goodbye : goodbye] Goodbye World!

[root@ip-192-168-71-110 tekton]# tkn pipeline list
NAME            AGE           LAST RUN                          STARTED      DURATION     STATUS
hello-goodbye   5 hours ago   hello-goodbye-run-rmrvm-r-2nr7d   1 hour ago   19 seconds   Succeeded
[root@ip-192-168-71-110 tekton]# tkn pipelinerun list
NAME                              STARTED       DURATION     STATUS               
hello-goodbye-run-rmrvm-r-2nr7d   1 hour ago    19 seconds   Succeeded   
hello-goodbye-run-rmrvm           5 hours ago   16 seconds   Succeeded   
[root@ip-192-168-71-110 tekton]# &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; 위와 같이 순차적으로 Hello World!와 Goodbye World!가 출력되는 것을 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;8) 대시보드 확인&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FCOWe/btq8Gng4n8E/wIK8QgqjeRmBOZAYYNTZq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FCOWe/btq8Gng4n8E/wIK8QgqjeRmBOZAYYNTZq1/img.png&quot; data-origin-width=&quot;950&quot; data-origin-height=&quot;700&quot; style=&quot;width: 49.4707%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FCOWe/btq8Gng4n8E/wIK8QgqjeRmBOZAYYNTZq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFCOWe%2Fbtq8Gng4n8E%2FwIK8QgqjeRmBOZAYYNTZq1%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;950&quot; height=&quot;700&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EAs1q/btq8KbFFxr0/qsQyIWmp53HlEwut5QWiK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EAs1q/btq8KbFFxr0/qsQyIWmp53HlEwut5QWiK1/img.png&quot; data-origin-width=&quot;948&quot; data-origin-height=&quot;700&quot; style=&quot;width: 49.3665%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EAs1q/btq8KbFFxr0/qsQyIWmp53HlEwut5QWiK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEAs1q%2Fbtq8KbFFxr0%2FqsQyIWmp53HlEwut5QWiK1%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;948&quot; height=&quot;700&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;9) Pipeline과 Task 간 파라미터 공유하기&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;hello.yaml과 hello-goodbye.yaml을 수정하여 다음과 같이 파라미터를 세팅할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;[hello-goodbye.yaml]&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1625303191085&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
  name: hello-goodbye
spec:
  tasks:
  - name: hello
    taskRef:
      name: hello
    params:
      - name: hello-greeting
        value: &quot;hello nara!&quot;
  - name: goodbye
    runAfter:
     - hello
    taskRef:
      name: goodbye&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; 적용하고자 하는 task 하위에 params를 추가한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;[hello.yaml]&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1625303151892&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: hello
spec:
  params:
    - name: hello-greeting
      type: string
      description: hello 
      default: hello my friend
  steps:
    - name: hello
      image: ubuntu
      command:
        - echo
      args:
        - &quot;$(params.hello-greeting)&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; task에 params를 정의(name, type, description, default)하고, steps.args에 &quot;$(params.[PARAM_NAME])&quot; 형태로 정의하여 pipeline의 변수를 받아 올 수 있다.&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1625303645208&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-71-110 tekton]# kubectl apply -f hello.yaml 
task.tekton.dev/hello configured
[root@ip-192-168-71-110 tekton]# kubectl apply -f hello-goodbye.yaml 
pipeline.tekton.dev/hello-goodbye configured
[root@ip-192-168-71-110 tekton]# tkn pipelinerun logs --last -f 
[hello : hello] hello nara!

[goodbye : goodbye] Goodbye World!

[root@ip-192-168-71-110 tekton]#&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Tekton Hub 활용&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Tekton Hub는 DockerHub와 같이 Tekton에서 사용하는 Task를 정의해 둔 라이브러리 저장소라고 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Tekton Hub : &lt;a href=&quot;https://hub.tekton.dev/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://hub.tekton.dev/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;951&quot; data-origin-height=&quot;687&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SaAx4/btq8HdxUGl7/mnDA9KqBvQUEq4ojcOdf70/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SaAx4/btq8HdxUGl7/mnDA9KqBvQUEq4ojcOdf70/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SaAx4/btq8HdxUGl7/mnDA9KqBvQUEq4ojcOdf70/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSaAx4%2Fbtq8HdxUGl7%2FmnDA9KqBvQUEq4ojcOdf70%2Fimg.png&quot; data-origin-width=&quot;951&quot; data-origin-height=&quot;687&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; 초기에 Task를 커스터마이징하기 위한 Template 자료로 활용할 수 있다. 예를 들어 Git Clone에 대한 Task를 알아보고 싶다면,&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1361&quot; data-origin-height=&quot;700&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qcP3x/btq8GCrGGvp/ePrrMJsoGEJ9KL8tkWv701/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qcP3x/btq8GCrGGvp/ePrrMJsoGEJ9KL8tkWv701/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qcP3x/btq8GCrGGvp/ePrrMJsoGEJ9KL8tkWv701/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqcP3x%2Fbtq8GCrGGvp%2FePrrMJsoGEJ9KL8tkWv701%2Fimg.png&quot; data-origin-width=&quot;1361&quot; data-origin-height=&quot;700&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; 위와 같이 Git을 검색하고, git clone을 선택한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1359&quot; data-origin-height=&quot;866&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yXByn/btq8G51uQuB/ACLToMCofom9fMALmJ9Oz1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yXByn/btq8G51uQuB/ACLToMCofom9fMALmJ9Oz1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yXByn/btq8G51uQuB/ACLToMCofom9fMALmJ9Oz1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyXByn%2Fbtq8G51uQuB%2FACLToMCofom9fMALmJ9Oz1%2Fimg.png&quot; data-origin-width=&quot;1359&quot; data-origin-height=&quot;866&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; 커스터마이징 가능한 YAML 파일과 주요 설정 정보에 대한 Description 그리고 Task 반영을 위한 Install 방법이 제공된다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1359&quot; data-origin-height=&quot;866&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c72STQ/btq8GCkSNNA/1PxQwZe08lX9AzbZ09zkMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c72STQ/btq8GCkSNNA/1PxQwZe08lX9AzbZ09zkMk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c72STQ/btq8GCkSNNA/1PxQwZe08lX9AzbZ09zkMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc72STQ%2Fbtq8GCkSNNA%2F1PxQwZe08lX9AzbZ09zkMk%2Fimg.png&quot; data-origin-width=&quot;1359&quot; data-origin-height=&quot;866&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; kubectl과 tkn을 사용하여 적용하는 방법이 각각 제시된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1625306202749&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-71-110 tekton]# kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/git-clone/0.4/git-clone.yaml
task.tekton.dev/git-clone created
[root@ip-192-168-71-110 tekton]# &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; 아래와 같이 task가 적용된 것을 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;949&quot; data-origin-height=&quot;701&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/crcttk/btq8HT0wmza/jB0d7dVGRcz7xr8oRWckg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/crcttk/btq8HT0wmza/jB0d7dVGRcz7xr8oRWckg1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/crcttk/btq8HT0wmza/jB0d7dVGRcz7xr8oRWckg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcrcttk%2Fbtq8HT0wmza%2FjB0d7dVGRcz7xr8oRWckg1%2Fimg.png&quot; data-origin-width=&quot;949&quot; data-origin-height=&quot;701&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; Task를 기반으로 Pipeline, PipelineRun 또는 TaskRun을 구현하여 배포하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;결론&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;지금까지 간단하게 Tekton을 활용하여 Pipeline을 구성하는 방법에 대해 알아보았다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1) tkn task start [TASK_NAME]&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2) tkn&amp;nbsp;taskrun&amp;nbsp;logs&amp;nbsp;--last&amp;nbsp;-f&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;3) tkn task list&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;4) tkn taskrun list&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;5) tkn pipeline start [PIPELINE_NAME]&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;6) tkn pipelinerun &lt;span style=&quot;color: #000000;&quot;&gt;logs&amp;nbsp;--last&amp;nbsp;-f&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;7) tkn pipeline list&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;8) tkn pipelinerun list&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Tekton은 task, pipeline으로 구성된 단순하면서도 확장성과 재활용성이 높은 클라우드 네이티브 오픈소스 플랫폼이라고 할 수 있다.&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;대표적인 CI/CD Tool들과 견주어 최근 많은 플랫폼에서 선택되고 있으며, 특히 기존 사용하던 플랫폼과의 호환성이 뛰어나 초기 적용에 많은 강점을 갖고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이번 포스팅에서는 Tekton을 활용한 배포 프로세스를 이해해 보았으며, 다음 포스팅에서는 보다 상세하게 Task와 Pipeline에 대해 알아보고, 활용 방법에 대해 살펴보도록 하자.&lt;/span&gt;&lt;/p&gt;</description>
      <category>⑤ 개발, 데이터베이스/ⓒ CI CD</category>
      <category>Affinity Assistant</category>
      <category>TEKTON</category>
      <category>Tekton Hub</category>
      <category>tekton k8s</category>
      <category>tekton kubernetes</category>
      <category>tekton pipeline</category>
      <category>tekton task</category>
      <category>tekton taskrun</category>
      <category>TektonHub</category>
      <category>tkn</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/705</guid>
      <comments>https://waspro.tistory.com/705#entry705comment</comments>
      <pubDate>Sat, 3 Jul 2021 11:25:34 +0900</pubDate>
    </item>
    <item>
      <title>Redis 운영관리 (Redisinsight &amp;amp; RMA)</title>
      <link>https://waspro.tistory.com/704</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;오픈소스 계열의 소프트웨어들의 특징은 바로 모니터링 환경을 별도로 제공하지 않는 다는 점이다. 대부분 기능적인 측면에 국한되어 있고, 운영 관점에서 여러 기능들을 구현하여 판매하는 것이 오픈소스 소프트웨어들의 특징이다. 대표적으로 ElasticSearch, Kafka, Netflix Zuul 등이 있으며, 다양한 분야에서 오픈소스를 상용화한 제품들이 등장하고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;지금부터 살펴볼 Redis 역시 대표적인 오픈소스이며, Redis Labs에서 만든 Redisinsight에 대해 알아보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Redisinsight&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Redisinsight는 바이너리 형태로 구축하거나, 도커이미지로 손쉽게 기동할 수 있다. 아래는 도커이미지를 활용하여 Redisinsight를 기동하는 과정이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1) docker image 기동&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1625153122299&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-71-110 ~]# sudo yum install -y docker
Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
Resolving Dependencies
--&amp;gt; Running transaction check
---&amp;gt; Package docker.x86_64 0:20.10.4-1.amzn2 will be installed
--&amp;gt; Processing Dependency: runc &amp;gt;= 1.0.0 for package: docker-20.10.4-1.amzn2.x86_64
--&amp;gt; Processing Dependency: libcgroup &amp;gt;= 0.40.rc1-5.15 for package: docker-20.10.4-1.amzn2.x86_64
--&amp;gt; Processing Dependency: containerd &amp;gt;= 1.3.2 for package: docker-20.10.4-1.amzn2.x86_64
--&amp;gt; Processing Dependency: pigz for package: docker-20.10.4-1.amzn2.x86_64
--&amp;gt; Running transaction check
---&amp;gt; Package containerd.x86_64 0:1.4.4-1.amzn2 will be installed
---&amp;gt; Package libcgroup.x86_64 0:0.41-21.amzn2 will be installed
---&amp;gt; Package pigz.x86_64 0:2.3.4-1.amzn2.0.1 will be installed
---&amp;gt; Package runc.x86_64 0:1.0.0-0.3.20210225.git12644e6.amzn2 will be installed
--&amp;gt; Finished Dependency Resolution

Dependencies Resolved

============================================================================================================================================================================================================================================
 Package                                           Arch                                          Version                                                                     Repository                                                Size
============================================================================================================================================================================================================================================
Installing:
 docker                                            x86_64                                        20.10.4-1.amzn2                                                             amzn2extra-docker                                         32 M
Installing for dependencies:
 containerd                                        x86_64                                        1.4.4-1.amzn2                                                               amzn2extra-docker                                         24 M
 libcgroup                                         x86_64                                        0.41-21.amzn2                                                               amzn2-core                                                66 k
 pigz                                              x86_64                                        2.3.4-1.amzn2.0.1                                                           amzn2-core                                                81 k
 runc                                              x86_64                                        1.0.0-0.3.20210225.git12644e6.amzn2                                         amzn2extra-docker                                        3.2 M

Transaction Summary
============================================================================================================================================================================================================================================
Install  1 Package (+4 Dependent packages)

Total download size: 59 M
Installed size: 243 M
Downloading packages:
(1/5): libcgroup-0.41-21.amzn2.x86_64.rpm                                                                                                                                                                            |  66 kB  00:00:00     
(2/5): pigz-2.3.4-1.amzn2.0.1.x86_64.rpm                                                                                                                                                                             |  81 kB  00:00:00     
(3/5): containerd-1.4.4-1.amzn2.x86_64.rpm                                                                                                                                                                           |  24 MB  00:00:01     
(4/5): docker-20.10.4-1.amzn2.x86_64.rpm                                                                                                                                                                             |  32 MB  00:00:01     
(5/5): runc-1.0.0-0.3.20210225.git12644e6.amzn2.x86_64.rpm                                                                                                                                                           | 3.2 MB  00:00:00     
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Total                                                                                                                                                                                                        47 MB/s |  59 MB  00:00:01     
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  Installing : runc-1.0.0-0.3.20210225.git12644e6.amzn2.x86_64                                                                                                                                                                          1/5 
  Installing : containerd-1.4.4-1.amzn2.x86_64                                                                                                                                                                                          2/5 
  Installing : libcgroup-0.41-21.amzn2.x86_64                                                                                                                                                                                           3/5 
  Installing : pigz-2.3.4-1.amzn2.0.1.x86_64                                                                                                                                                                                            4/5 
  Installing : docker-20.10.4-1.amzn2.x86_64                                                                                                                                                                                            5/5 
  Verifying  : containerd-1.4.4-1.amzn2.x86_64                                                                                                                                                                                          1/5 
  Verifying  : docker-20.10.4-1.amzn2.x86_64                                                                                                                                                                                            2/5 
  Verifying  : pigz-2.3.4-1.amzn2.0.1.x86_64                                                                                                                                                                                            3/5 
  Verifying  : runc-1.0.0-0.3.20210225.git12644e6.amzn2.x86_64                                                                                                                                                                          4/5 
  Verifying  : libcgroup-0.41-21.amzn2.x86_64                                                                                                                                                                                           5/5 

Installed:
  docker.x86_64 0:20.10.4-1.amzn2                                                                                                                                                                                                           

Dependency Installed:
  containerd.x86_64 0:1.4.4-1.amzn2                      libcgroup.x86_64 0:0.41-21.amzn2                      pigz.x86_64 0:2.3.4-1.amzn2.0.1                      runc.x86_64 0:1.0.0-0.3.20210225.git12644e6.amzn2                     

Complete!
[root@ip-192-168-71-110 ~]# sudo service docker start
Redirecting to /bin/systemctl start docker.service
[root@ip-192-168-71-110 ~]# docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
[root@ip-192-168-71-110 ~]# docker run -v redisinsight:/db -p 8001:8001 redislabs/redisinsight
Unable to find image 'redislabs/redisinsight:latest' locally
latest: Pulling from redislabs/redisinsight
bd8f6a7501cc: Pull complete 
44718e6d535d: Pull complete 
efe9738af0cb: Pull complete 
f37aabde37b8: Pull complete 
3923d444ed05: Pull complete 
a389cd00f6ac: Pull complete 
635fef62bb79: Pull complete 
d620e4e17484: Pull complete 
e2ee94785e13: Pull complete 
48b3e278075c: Pull complete 
100ed91c31ae: Pull complete 
55c329231ae6: Pull complete 
96d8432c61ad: Pull complete 
1ed83d76beb2: Pull complete 
b9f7ffeff2f8: Pull complete 
Digest: sha256:fd4bff16761308521952e802e1ac1fcafb0d78088c508cf3762754aa954c7009
Status: Downloaded newer image for redislabs/redisinsight:latest
&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;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;(Docker Install &amp;gt; Docker Run &amp;gt; Redisinsight Download &amp;amp; Run)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;2) Redisinsight dashboard (http://ip:8001)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;948&quot; data-origin-height=&quot;701&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/30hsH/btq8xK4jI6z/59ErOxHU2f98KExfX6xkhk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/30hsH/btq8xK4jI6z/59ErOxHU2f98KExfX6xkhk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/30hsH/btq8xK4jI6z/59ErOxHU2f98KExfX6xkhk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F30hsH%2Fbtq8xK4jI6z%2F59ErOxHU2f98KExfX6xkhk%2Fimg.png&quot; data-origin-width=&quot;948&quot; data-origin-height=&quot;701&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; Redisinsight는 기본 8001 포트 사용&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; EULA AND PRIVACY SETTINGS 동의&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;3) Redis 연결&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGlFZE/btq8BDQNZyW/3NKkKUrUEkTf4bkb42RIj0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGlFZE/btq8BDQNZyW/3NKkKUrUEkTf4bkb42RIj0/img.png&quot; style=&quot;width: 49.4447%; margin-right: 10px;&quot; data-origin-width=&quot;949&quot; data-origin-height=&quot;701&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGlFZE/btq8BDQNZyW/3NKkKUrUEkTf4bkb42RIj0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGlFZE%2Fbtq8BDQNZyW%2F3NKkKUrUEkTf4bkb42RIj0%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;949&quot; height=&quot;701&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WyYrQ/btq8AqEh0v2/xkLNAKQFjeiatLbTnNKtDk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WyYrQ/btq8AqEh0v2/xkLNAKQFjeiatLbTnNKtDk/img.png&quot; style=&quot;width: 49.39255372620172%;&quot; data-origin-width=&quot;948&quot; data-origin-height=&quot;701&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WyYrQ/btq8AqEh0v2/xkLNAKQFjeiatLbTnNKtDk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWyYrQ%2Fbtq8AqEh0v2%2FxkLNAKQFjeiatLbTnNKtDk%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;948&quot; height=&quot;701&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b55Z0g/btq8BHL3ImI/G8LJsIRezza0VbS8zlZpsK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b55Z0g/btq8BHL3ImI/G8LJsIRezza0VbS8zlZpsK/img.png&quot; style=&quot;width: 49.4539%; margin-right: 10px;&quot; data-origin-width=&quot;950&quot; data-origin-height=&quot;700&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b55Z0g/btq8BHL3ImI/G8LJsIRezza0VbS8zlZpsK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb55Z0g%2Fbtq8BHL3ImI%2FG8LJsIRezza0VbS8zlZpsK%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;950&quot; height=&quot;700&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLO3Cr/btq8A9Qcde3/sgK1SkeSwLYenF8iZZALL0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLO3Cr/btq8A9Qcde3/sgK1SkeSwLYenF8iZZALL0/img.png&quot; style=&quot;width: 49.3833308434175%;&quot; data-origin-width=&quot;950&quot; data-origin-height=&quot;701&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLO3Cr/btq8A9Qcde3/sgK1SkeSwLYenF8iZZALL0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLO3Cr%2Fbtq8A9Qcde3%2FsgK1SkeSwLYenF8iZZALL0%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;950&quot; height=&quot;701&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; I already have a database 선택&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; Connect to Redis Database 선택&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; Redis ip/port/name 입력 후 ADD (필요 시 ID/PASSWORD 입력)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;948&quot; data-origin-height=&quot;701&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/du2mVW/btq8C1J1X54/mVRz39AyuAf3UzwYRZRcl0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/du2mVW/btq8C1J1X54/mVRz39AyuAf3UzwYRZRcl0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/du2mVW/btq8C1J1X54/mVRz39AyuAf3UzwYRZRcl0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdu2mVW%2Fbtq8C1J1X54%2FmVRz39AyuAf3UzwYRZRcl0%2Fimg.png&quot; data-origin-width=&quot;948&quot; data-origin-height=&quot;701&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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; font-family: 'Noto Serif KR';&quot;&gt;4) Redisinsight 기능&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; OVERWIEW (Redis 통합 모니터링)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; 주요 지표 : Key, Memory, Network 등&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1912&quot; data-origin-height=&quot;844&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmktZ6/btq8BkRt4uG/vHJY1REpCjuFMAWtaDzKS1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmktZ6/btq8BkRt4uG/vHJY1REpCjuFMAWtaDzKS1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmktZ6/btq8BkRt4uG/vHJY1REpCjuFMAWtaDzKS1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbmktZ6%2Fbtq8BkRt4uG%2FvHJY1REpCjuFMAWtaDzKS1%2Fimg.png&quot; data-origin-width=&quot;1912&quot; data-origin-height=&quot;844&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; Key 정보 확인 (타입, 사이즈 등)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1913&quot; data-origin-height=&quot;766&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0PkyW/btq8CtUiUI4/ueUXELIDG4U0MLUW0Jtu20/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0PkyW/btq8CtUiUI4/ueUXELIDG4U0MLUW0Jtu20/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0PkyW/btq8CtUiUI4/ueUXELIDG4U0MLUW0Jtu20/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0PkyW%2Fbtq8CtUiUI4%2FueUXELIDG4U0MLUW0Jtu20%2Fimg.png&quot; data-origin-width=&quot;1913&quot; data-origin-height=&quot;766&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; CLI 지원&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; SINGLE NODE, ALL NODES, ALL MASTERS, ALL REPLICAS 대상 지정 후 명령어 수행&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1909&quot; data-origin-height=&quot;871&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfG43P/btq8CKu7TDX/othqLlRhMynjXcJseyPMd0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfG43P/btq8CKu7TDX/othqLlRhMynjXcJseyPMd0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfG43P/btq8CKu7TDX/othqLlRhMynjXcJseyPMd0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfG43P%2Fbtq8CKu7TDX%2FothqLlRhMynjXcJseyPMd0%2Fimg.png&quot; data-origin-width=&quot;1909&quot; data-origin-height=&quot;871&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; 명령어 메뉴얼 기능 제공&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1910&quot; data-origin-height=&quot;846&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CBf83/btq8A9bDqHU/XPRzOEk2yfLpuCVvTRTSFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CBf83/btq8A9bDqHU/XPRzOEk2yfLpuCVvTRTSFK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CBf83/btq8A9bDqHU/XPRzOEk2yfLpuCVvTRTSFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCBf83%2Fbtq8A9bDqHU%2FXPRzOEk2yfLpuCVvTRTSFK%2Fimg.png&quot; data-origin-width=&quot;1910&quot; data-origin-height=&quot;846&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; 설정 동적 반영 지원&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LzT18/btq8z7yxCec/uANPgkkEzGDuE9g9Hdptx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LzT18/btq8z7yxCec/uANPgkkEzGDuE9g9Hdptx1/img.png&quot; style=&quot;width: 49.3203%; margin-right: 10px;&quot; data-origin-width=&quot;1901&quot; data-origin-height=&quot;1007&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LzT18/btq8z7yxCec/uANPgkkEzGDuE9g9Hdptx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLzT18%2Fbtq8z7yxCec%2FuANPgkkEzGDuE9g9Hdptx1%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;1901&quot; height=&quot;1007&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZMX64/btq8DQn559R/3k0oonzpkVR97FBv0kgcf0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZMX64/btq8DQn559R/3k0oonzpkVR97FBv0kgcf0/img.png&quot; style=&quot;width: 49.51695013305565%;&quot; data-origin-width=&quot;1901&quot; data-origin-height=&quot;1003&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZMX64/btq8DQn559R/3k0oonzpkVR97FBv0kgcf0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZMX64%2Fbtq8DQn559R%2F3k0oonzpkVR97FBv0kgcf0%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;1901&quot; height=&quot;1003&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; Cluster Management&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; Rebalance Cluster / Manual ReSharding&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; Visualize Filter / Showing&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; Client List&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAaY0W/btq8Ar4iS5k/yMhaQ9pwoa5aetuJUQ6Ckk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAaY0W/btq8Ar4iS5k/yMhaQ9pwoa5aetuJUQ6Ckk/img.png&quot; style=&quot;width: 50.7581%; margin-right: 10px;&quot; data-origin-width=&quot;1902&quot; data-origin-height=&quot;682&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAaY0W/btq8Ar4iS5k/yMhaQ9pwoa5aetuJUQ6Ckk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAaY0W%2Fbtq8Ar4iS5k%2FyMhaQ9pwoa5aetuJUQ6Ckk%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;1902&quot; height=&quot;682&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b9YDy0/btq8Ch020hk/RE6qUhZCDsjbM381nYB3K1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b9YDy0/btq8Ch020hk/RE6qUhZCDsjbM381nYB3K1/img.png&quot; style=&quot;width: 48.079156022957235%;&quot; data-origin-width=&quot;1902&quot; data-origin-height=&quot;720&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b9YDy0/btq8Ch020hk/RE6qUhZCDsjbM381nYB3K1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb9YDy0%2Fbtq8Ch020hk%2FRE6qUhZCDsjbM381nYB3K1%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;1902&quot; height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;그 밖에 RedisStreams, RedisGraph, RedisGears, RedisTimeSeries, RedisSearch 등을 통합 관리할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;RMA (Redis Memory Analyzer)&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Redis 메모리 분석기 (RMA)는 Redis에서 사용할 수 있는 가장 포괄적인 메모리 분석기 중 하나이다. 세 가지 수준의 세부 정보를 지원합니다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;global - 메모리 사용량 정보&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;scanner - key type 기반 메모리 사용량 정보&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;ram - key type 별 메모리 사용량 정보&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1) 설치&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1625156699837&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-71-110 ~]# pip3 install rma
WARNING: Running pip install with root privileges is generally not a good idea. Try `pip3 install --user` instead.
Collecting rma
  Downloading rma-0.2.1-py3-none-any.whl (29 kB)
Collecting redis
  Downloading redis-3.5.3-py2.py3-none-any.whl (72 kB)
     |--------------------------------------------------------------| 72 kB 691 kB/s 
Collecting msgpack-python
  Downloading msgpack-python-0.5.6.tar.gz (138 kB)
     |--------------------------------------------------------------| 138 kB 8.8 MB/s 
Collecting tqdm
  Downloading tqdm-4.61.1-py2.py3-none-any.whl (75 kB)
     |--------------------------------------------------------------| 75 kB 4.9 MB/s 
Collecting tabulate
  Downloading tabulate-0.8.9-py3-none-any.whl (25 kB)
Using legacy 'setup.py install' for msgpack-python, since package 'wheel' is not installed.
Installing collected packages: redis, msgpack-python, tqdm, tabulate, rma
    Running setup.py install for msgpack-python ... done
Successfully installed msgpack-python-0.5.6 redis-3.5.3 rma-0.2.1 tabulate-0.8.9 tqdm-4.61.1
[root@ip-192-168-71-110 ~]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2) RMA - global mode&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1625156744877&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-71-110 ~]# rma -p 6379 -b global
Match *: 100%|-----------------------------------------| 1/1 [00:00&amp;lt;00:00, 1001.03it/s]

Aggregating keys by pattern and type

Apply rules

Nodes

| Stat                               | Value          |
|:-----------------------------------|:---------------|
| info used_memory                   | 1581128        |
| info used_memory_human             | 1.51M          |
| info used_memory_rss               | 4919296        |
| info used_memory_rss_human         | 4.69M          |
| info used_memory_peak              | 1662416        |
| info used_memory_peak_human        | 1.59M          |
| info used_memory_peak_perc         | 95.11%         |
| info used_memory_overhead          | 1539904        |
| info used_memory_startup           | 1455016        |
| info used_memory_dataset           | 41224          |
| info used_memory_dataset_perc      | 32.69%         |
| info allocator_allocated           | 1593680        |
| info allocator_active              | 1822720        |
| info allocator_resident            | 4313088        |
| info total_system_memory           | 1031057408     |
| info total_system_memory_human     | 983.29M        |
| info used_memory_lua               | 43008          |
| info used_memory_lua_human         | 42.00K         |
| info used_memory_scripts           | 488            |
| info used_memory_scripts_human     | 488B           |
| info number_of_cached_scripts      | 1              |
| info maxmemory                     | 0              |
| info maxmemory_human               | 0B             |
| info maxmemory_policy              | noeviction     |
| info allocator_frag_ratio          | 1.14           |
| info allocator_frag_bytes          | 229040         |
| info allocator_rss_ratio           | 2.37           |
| info allocator_rss_bytes           | 2490368        |
| info rss_overhead_ratio            | 1.14           |
| info rss_overhead_bytes            | 606208         |
| info mem_fragmentation_ratio       | 3.24           |
| info mem_fragmentation_bytes       | 3401536        |
| info mem_not_counted_for_evict     | 790            |
| info mem_replication_backlog       | 0              |
| info mem_clients_slaves            | 0              |
| info mem_clients_normal            | 83538          |
| info mem_aof_buffer                | 790            |
| info mem_allocator                 | jemalloc-5.1.0 |
| info active_defrag_running         | 0              |
| info lazyfree_pending_objects      | 0              |
| used proto-max-bulk-len            | 536870912      |
| used active-defrag-max-scan-fields | 1000           |
| used hash-max-ziplist-entries      | 512            |
| used hash-max-ziplist-value        | 64             |
| used list-max-ziplist-size         | -2             |
| used set-max-intset-entries        | 512            |
| used zset-max-ziplist-entries      | 128            |
| used zset-max-ziplist-value        | 64             |
| totalKeys                          | 1              |
| redisKeySpaceOverhead              | 96             |

Done in 0.02804775000004156 seconds[root@ip-192-168-71-110 ~]# 
[root@ip-192-168-71-110 ~]# &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;글로벌 모드에서 RMA는 key count, 시스템 메모리, allocation 크기 등과 같은 통계를 제공한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;3) RMA - scanner mode&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1625157030333&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-71-110 ~]# rma -p 6379 -b scanner
Match *: 100%|--------------------------------| 1/1 [00:00&amp;lt;00:00, 1860.00it/s]

Aggregating keys by pattern and type

Apply rules

Keys by types

| name   |   count | type   | percent   |
|:-------|--------:|:-------|:----------|
| b      |       1 | string | 100.00%   |

Done in 0.014729796999745304 seconds
[root@ip-192-168-71-110 ~]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;스캐너 모드에서는 keyspace의 개요를 볼 수 있다. 항목의 유형 및 해당 네임 스페이스가 사용하는 메모리 비율과 함께 네임 스페이스를 제공한다. 이 정보로 기반으로 네임 스페이스 패턴과 결합된 &quot;RAM&quot;동작을 사용하여 자세한 분석을 수행하는 것이 유용하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;4) RMA &amp;mdash; RAM mode&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1625157244093&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;root@ip-192-168-71-110 ~]# rma -p 6379 -b ram
Match *: 100%|----------------------| 1/1 [00:00&amp;lt;00:00, 2092.97it/s]

Aggregating keys by pattern and type

Apply rules
                                                                                                                                                                                                                                            
Keys statistic

Stat by &amp;lt;string&amp;gt;

| Match   |   Count |   Useful |   Free |   Real |   Ratio | Encoding        |   Min |   Max |   Avg |   TTL Min |   TTL Max |   TTL Avg |
|:--------|--------:|---------:|-------:|-------:|--------:|:----------------|------:|------:|------:|----------:|----------:|----------:|
| b       |       1 |        1 |      0 |     48 |   48.00 | embstr [100.0%] |     1 |     1 |     1 |        -1 |        -1 |     -1.00 |
| Total:  |       1 |        1 |      0 |     48 |    0.00 |                 |     0 |     0 |     0 |        -1 |        -1 |    nan    |

Done in 0.016523048999260936 seconds
[root@ip-192-168-71-110 ~]# &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;RAM 모드에서는 대부분의 다른 메모리 분석기에서 제공하는 keyspace 수준 메모리 소비를 얻습니다. 사용된 메모리, 실제 데이터 크기, 오버 헤드, 인코딩, TTL 등의 자세한 정보를 얻을 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;RMA 장점 :&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: 'Noto Serif KR'; color: #000000;&quot;&gt;실시간 작동&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;scan 명령을 사용하여 데이터베이스를 살펴보므로 성능 영향이 제한되고 분석이 매우 정확함&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;문서화 되어 있고, 적용사례를 쉽게 찾을 수 있음&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;특정 데이터 유형만 분석하거나 특정 패턴과 일치하는 키만 고려하는 등 사용자 지정 및 필터링 옵션 지원&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;네임 스페이스, 키 또는 전역 값과 같은 다양한 수준에서 세부 정보 제공&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;데이터 구조 오버 헤드 (즉, 목록 데이터 유형에 대한 포인터와 같은 내부 Redis 정보를 저장하는 데 사용되는 메모리 양)를 표시&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;RMA 단점 :&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: 'Noto Serif KR'; color: #000000;&quot;&gt;데이터베이스를 스캔하는 것은 큰 데이터베이스의 경우 매우 느릴 수 있음. 성능 향상을 위해 특정 개수의 키가 반환되면 검색을 중지하는 옵션 적용 필요&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;결론&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;하나의 도구로 모든 요구 사항을 충족하지 못할 수도 있지만 Redisinsight / RMA 등을 조합하여 활용하면 Redis의 운영관점에서의 부족한 부분을 보완할 수 있을 것이다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>⑦ Open Source Software</category>
      <category>Redis</category>
      <category>Redis Memory Analyzer</category>
      <category>redis 모니터링</category>
      <category>redisinsight</category>
      <category>RMA</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/704</guid>
      <comments>https://waspro.tistory.com/704#entry704comment</comments>
      <pubDate>Fri, 2 Jul 2021 01:42:38 +0900</pubDate>
    </item>
    <item>
      <title>Redis5 vs Memcached 선택기준</title>
      <link>https://waspro.tistory.com/699</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;개요&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;어플리케이션의 성능 향상은 모든 시스템의 궁극적인 가치이자 목표이다. 좀 더 빠르게 고객에게 서비스하기 위해 새로운 시스템을 오픈하거나, 시스템 고도화 작업을 진행한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;성능을 향상시키는 방법은 다양하다. 새롭게 시스템을 개선하여 오픈하는 차세대급 프로젝트를 진행하거나, 지속적인 서비스 모니터링을 통해 유지보수해 나가거나, 특정 소프트웨어를 대체하거나, 언어를 변경하거나 때로는 코딩 한줄로도 성능이 개선되는 경우가 있다. 성능 향상의 목표치에 따라 비용과 시간이 소요될 수 있으며, 상황에 적합한 방식을 적용하여 성능 개선을 지속적으로 수행해 나가는 것은 프로젝트를 진행하는 모든 사람들의 궁극적인 목적이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Redis와 Memcached로 대표되는 캐싱 서버는 바로 성능을 향상시키는 대표적인 방법 중 하나이다. &lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;지금부터 Redis와 Memcached의 공통점과 차이점을 살펴보고 어떠한 상황에 적합한 캐싱서버를 선택할 수 있는지 알아보도록 하자.&lt;/span&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;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;공통점&lt;/span&gt;&lt;/h2&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 140px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style8&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 100%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Feature&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 100%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;key-value 데이터 저장소&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 100%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;데이터 파티셔닝 지원&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 100%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;밀리 초 미만의 지연 시간&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 100%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;NoSQL 제품군&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 100%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;오픈 소스&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 100%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;다수의 프로그래밍 언어 및 클라우드 제공 업체에서 지원&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;차이점&lt;/span&gt;&lt;/h2&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 264px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style8&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 19.3798%; height: 21px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Feature&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 39.9612%; height: 21px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Redis&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 40.6589%; height: 21px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Memcached&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 42px;&quot;&gt;
&lt;td style=&quot;width: 19.3798%; height: 42px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;데이터 유형&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 39.9612%; height: 42px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;다양한 데이터 유형 지원&lt;/span&gt;&lt;br /&gt;(String, List, Set, Sorted Set, Hash, Hash List, Array, Json)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 40.6589%; height: 42px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;String&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 19.3798%; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;메모리 관리&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 39.9612%; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;메모리가 가득찰 경우 디스크를 활용하여 데이터를 저장할 수 있음&lt;br /&gt;디스크에서 최근에 사용된 Key-Value를 메모리로 스왑하는 기능 제공&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 40.6589%; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;기본 메모리에만 저장이 가능하지만, extstore를 활용하면 메모리에도 저장이 가능함&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 19.3798%; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;데이터 사이즈&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 39.9612%; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #ee2323;&quot;&gt;512MB&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 40.6589%; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #ee2323;&quot;&gt;1MB&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 19.3798%; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;데이터 지속성&lt;br /&gt;및 복구&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 39.9612%; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;RDB 스냅샷과 AOF 로그를 통해 데이터의 지속성을 지원&lt;br /&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;데이터 복구에 유리&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 40.6589%; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;지원하지 않음&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 19.3798%; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;클러스터&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 39.9612%; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;지원 (분산 캐시)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 40.6589%; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;지원하지 않음&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 19.3798%; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;멀티 Thread&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 39.9612%; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;지원하지 않음 (&lt;span style=&quot;color: #ee2323;&quot;&gt;싱글쓰레드를 지원&lt;/span&gt;하여 서버 당 다중 레디스 구성이 효율)&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;클라우드 상에서 Scale Out에 유리&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 40.6589%; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;지원 (&lt;span style=&quot;color: #ee2323;&quot;&gt;멀티쓰레드를 지원&lt;/span&gt;하여 서버 당 단일 레디스 구성이 효율)&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;클라우드 상에서 Scale Up에 유리&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 19.3798%; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;스케일링&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 39.9612%; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;수평확장 지원&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 40.6589%; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;수직확장 지원&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 19.3798%; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;데이터 복제&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 39.9612%; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;데이터 가용성을 보장하기 위한 마스터/슬레이브 노드 구성&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 40.6589%; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;지원하지 않음&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 19.3798%; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;데이터 제거&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 39.9612%; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;다양한 형태의 제거 정책 지원&lt;/span&gt;&lt;br /&gt;# 참조&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://waspro.tistory.com/697&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://waspro.tistory.com/697&lt;/a&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 40.6589%; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;LRU (최근에 사용된 키)만 지원&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 19.3798%; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;트랜잭션&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 39.9612%; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #ee2323;&quot;&gt;지원&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 40.6589%; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;지원하지 않음&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 19.3798%; height: 21px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;pub/sub&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 39.9612%; height: 21px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;지원&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 40.6589%; height: 21px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;지원하지 않음&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;선택 기준&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Memcached는 더 작고 정적인 데이터를 다룰 때 권장한다. 큰 데이터를 처리 할 때 Memcached는 캐시에서 저장 및 검색하는 동안 데이터를 직렬화 및 역직렬화 해야하며 이를 저장하는데 더 많은 공간이 필요하다. 소규모 프로젝트를 다룰 때는 멀티 스레딩 특성과 수직 확장성으로 인해 Memcached를 사용하는 것이 좋다. 클러스터링은 인프라를 구성하는데 상당한 노력이 필요하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Redis는 다양한 데이터 유형을 지원한다. 클러스터링 및 데이터 지속성을 지원하여 대규모 애플리케이션에 적합하다. Pub/Sub 및 트랜잭션과 같은 추가 기능을 통해 데이터 저장소 이상의 기능을 수행 할 수 있다.&lt;/span&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;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;결론&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;프로젝트 중 변경 및 마이그레이션을 피하기 위해 시작 단계부터 적합한 캐시 유형을 선택하는 것이 중요하다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>⑦ Open Source Software</category>
      <category>memcached</category>
      <category>Redis</category>
      <category>캐시</category>
      <category>캐시서버</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/699</guid>
      <comments>https://waspro.tistory.com/699#entry699comment</comments>
      <pubDate>Fri, 18 Jun 2021 00:26:15 +0900</pubDate>
    </item>
    <item>
      <title>Redis5 설계하기 총정리</title>
      <link>https://waspro.tistory.com/697</link>
      <description>&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;개요&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이번 포스팅에서는 Redis를 효과적으로 구축/운영하기 위한 설계방법에 대해 알아보도록 하자. &lt;/span&gt;Redis는 대표적인 In-memory DB로 세션, 캐시, 큐 등으로 활용된다. 단일 환경으로 가볍게 구성이 가능하지만, 고 가용성을 위한 클러스터 환경이나 Replication 환경을 구성할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;캐시 설계&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;먼저 살펴볼 내용은 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;캐시 서버를 설계하기 위한 공통적인 지침사항이다. 총 5가지의 설계 지침을 제시하며, 각각은 정답이 아닌 고려사항임을 유념하고 포스팅을 읽어 주셨으면 한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;1) Cache &amp;amp; Data Store 배치 전략&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;대표적인 Cache Server 배치 전략으로는 Cache Aside 패턴과 Write Back 패턴이 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;a. Cache Aside 패턴&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;753&quot; data-origin-height=&quot;353&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cLo6n6/btq5fUBCHDo/PGPKpvEaURM2W0GmL5FRPk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cLo6n6/btq5fUBCHDo/PGPKpvEaURM2W0GmL5FRPk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cLo6n6/btq5fUBCHDo/PGPKpvEaURM2W0GmL5FRPk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcLo6n6%2Fbtq5fUBCHDo%2FPGPKpvEaURM2W0GmL5FRPk%2Fimg.png&quot; data-origin-width=&quot;753&quot; data-origin-height=&quot;353&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #ee2323;&quot;&gt;특징 : 읽기에 적합. 캐시 장애 대비 구성. 정합성 문제 발생. 반복적인 호출에 적합&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Cache Asdie 패턴은 캐시로 부터 빠르게 데이터를 조회해 올 수 있도록 설계하는 방식이다. 읽기가 많은 경우 적합하며, 가용성 측면에서 Cache 서버에 장애가 발생해도 Data Store를 통해 지속 서비스를 할 수 있다. 다만, Cache Store와 Data Store간 정합성 유지 문제가 발생할 수 있으며, 초기 조회 시 무조건 Data Store를 호출 해야 하므로 단건 호출 빈도가 높은 서비스에 적합하지 않다. 반복적으로 동일 쿼리를 수행하는 서비스에 적합한 아키텍처이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;b. Write Back 패턴&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;745&quot; data-origin-height=&quot;350&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/N5oC3/btq5hjOeV4A/ZXlvv252ROJ6TYuw72qdl1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/N5oC3/btq5hjOeV4A/ZXlvv252ROJ6TYuw72qdl1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/N5oC3/btq5hjOeV4A/ZXlvv252ROJ6TYuw72qdl1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FN5oC3%2Fbtq5hjOeV4A%2FZXlvv252ROJ6TYuw72qdl1%2Fimg.png&quot; data-origin-width=&quot;745&quot; data-origin-height=&quot;350&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #ee2323;&quot;&gt;특징 : 큐 역할. 쓰기에 적합. 캐시 장애 시 데이터 유실. 정합성 확보. 불필요한 리소스 저장&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Write Back의 경우 Cache Store가 데이터 저장소 역할을 하면서 동시에 Data Store에 Write 부하를 줄이기 위한 Queue 역할을 겸하게 된다. 이로인해 Database의 부하를 경감시킬 수 있다는 장점이 있다. 대체로 쓰기 작업이 많은 경우 적용을 권고하며, Cache Store에서 Data Store로 데이터를 전송하기 전에 장애가 발생할 경우 데이터 분실이 발생할 수 있다.&lt;/span&gt;&lt;br /&gt;장점으로는&lt;span style=&quot;color: #000000;&quot;&gt; 데이터베이스의 일시적인 다운타임을 허용하거나, 장애에 대응할 수 있으며, Cache Store와 Data Store 간의 데이터 정합성을 유지하기에도 유용하다. 반면에 사용되지 않는 데이터가 저장되어 리소스 낭비와 Write 작업에 부하가 발생할 수 있다. 이를 해결하기 위해 TTL을 꼭 사용하여 사용되지 않는 데이터를 반드시 삭제해야 한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Cache Aside와 Write Back 이외에도 몇가지 추가적인 패턴이 존재한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;c. Read Through&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;755&quot; data-origin-height=&quot;354&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ciHyTw/btq5tFEu1Ft/hO4ZTd4sm0mpMVkDkB6aX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ciHyTw/btq5tFEu1Ft/hO4ZTd4sm0mpMVkDkB6aX0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ciHyTw/btq5tFEu1Ft/hO4ZTd4sm0mpMVkDkB6aX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FciHyTw%2Fbtq5tFEu1Ft%2FhO4ZTd4sm0mpMVkDkB6aX0%2Fimg.png&quot; data-origin-width=&quot;755&quot; data-origin-height=&quot;354&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Read Through 방식은 Cache Aside 방식과 비슷하지만, Cache Store에 저장하는 주체가 Server이냐 또는 Data Store 자체이냐에서 차이점이 있다. 초&lt;/span&gt;기 데이터는 cache miss가 항상 발생한다는 단점을 커버할 수 있도록 애플리케이션 측면에서 캐시 대상을 판단하여 Data Store 저장(Commit) 시 Cache Store에 Query를 동일하게 수행해 주는 것도 한가지 방안이 될 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;d. Write Through&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;757&quot; data-origin-height=&quot;351&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Tlmg1/btq5APyT6Ef/CotdCanF3AKQZ6vNMnsda1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Tlmg1/btq5APyT6Ef/CotdCanF3AKQZ6vNMnsda1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Tlmg1/btq5APyT6Ef/CotdCanF3AKQZ6vNMnsda1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTlmg1%2Fbtq5APyT6Ef%2FCotdCanF3AKQZ6vNMnsda1%2Fimg.png&quot; data-origin-width=&quot;757&quot; data-origin-height=&quot;351&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Write Back의 경우 Queue의 역할을 하여 여러 요청을 Cache Store에서 조절하면서 Data Store에 Write 하는 작업을 관리하지만, Wrtie Through의 경우 Cache Store에도 반영하고 Data Store에도 반영하는 방식을 의미한다.&lt;br /&gt;이는 항상 동기화가 되어 있다는 장점이 있지만, 캐시에 저장할 필요가 없는 데이터까지 Cache Store에 저장되어 리소스 낭비 및 Write 시간이 오래 걸린다는 문제가 있다. 다만 사용되지 않는 데이터가 저장되어 리소스 낭비와 Write 작업에 부하가 발생할 수 있다. 이를 해결하기 위해 TTL을 꼭 사용하여 사용되지 않는 데이터를 반드시 삭제해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;2) 캐시 검색 방식&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;캐싱은 성능, 확장성 및 가용성을 크게 향상할 수 있는 유용한 아키텍처 설계 방식이다. 특히 분산 애플리케이션 환경에서 보다 그 효과를 발휘할 수 있도록 설계되어 있다. 전통적인 데이터 저장 방식은 데이터베이스와 디스크와 같은 비 휘발성 Persistent Volume을 사용해 왔으나, 보다 많은 사용자가 동시에 접근하는 환경을 구성하기를 원하고, 더 많은 데이터를 동시에 처리하기 원하는 디지털 시대의 흐름에 따라 기존 영구 저장소는 경합 문제가 발생하고, 성능 저하 현상이 발생하면서 이를 대체하는 환경이 요구되어져 왔다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;캐시 솔루션은 자주 사용되면서 자주 변경되지 않는 데이터의 경우 캐시 서버에 적용하여 반영할 경우 높은 성능 향상을 이뤄낼 수 있다. 이를 Cache Hit Rating이라고 한다. &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;일반적으로 캐시는 메모리에 저장되는 형태를 선호한다. 디스크에 저장되는 방식은 기존 PV와 크게 다르지 않기 때문에 메모리에 저장하여 성능 향상을 극단적으로 뽑아내는 환경을 구성하기를 원한다. 대표적으로 Redis와 MemCached가 있다. 이와 같은 IMDG 솔루션은 메모리를 1차 저장소로 사용하기 때문에 디스크와 달리 제약적인 저장 공간을 사용하게 된다. 많아야 수십기가 정도의 저장소를 보유하게 되며, 이는 결국 자주 사용되는 데이터를 어떻게 뽑아 캐시에 저장하고 자주 사용하지 않는 데이터를 어떻게 제거해 나갈 것이냐를 지속적으로 고민해야 한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;따라서 &lt;span style=&quot;color: #ee2323;&quot;&gt;캐시를 저장하는 시점은 자주 사용되며 자주 변경되지 않는 데이터를 기준으로 &lt;/span&gt;하는 것이 좋다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;또한 한가지 고민해야 할 사항은 캐시 솔루션은 언제든지 데이터가 날라갈 수 있는 휘발성을 기본으로 한다는 점이다. 이는 데이터를 주기적으로 디스크에 저장할 수는 있지만, 실시간으로 모든 데이터를 디스크에 저장할 경우 성능 저하를 일으킬 수 있어 어느 정도 데이터 수집과 저장 주기를 갖게 된다. 즉 데이터의 유실 또는 정합성이 일정 부분 깨질 수 있다는 점을 항상 고려해야 한다. 따라서 &lt;span style=&quot;color: #ee2323;&quot;&gt;캐시에 저장되는 데이터는 중요한 정보, 민감 정보 등은 저장하지 않는 것&lt;/span&gt;이 좋으며, 캐시 솔루션이 장애가 발생했을 경우 적절한 대응방안을 모색해 두는 것이 바람직하다. (TimeOut, 데이터베이스 조회 병행 등)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;3) 캐시 제거&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;캐시 데이터의 경우 캐시 서버에만 단독으로 저장되는 경우도 있지만, 대부분 영구 저장소에 저장된 데이터의 복사본으로 동작하는 경우가 많다. 이는 2차 저장소(영구 저장소)에 저장되어 있는 데이터와 캐시 솔루션의 데이터를 동기화 하는 작업이 반드시 필요함을 의미하며, 개발 과정에 고려사항이 늘어난다는 점을 반드시 기억해야 한다. 예를 들어 캐시 서버와 데이터베이스에 저장되는 데이터의 커밋 시점에 대한 고려 등이 예가 될 수 있다. &lt;span style=&quot;color: #000000;&quot;&gt;캐시의 만료 정책이 제대로 구현되지 않은 경우 클라이언트는 데이터가 변경되었음에도 캐시된 오래된 정보를 사용할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;캐시를 구성할 때 기본 만료 정책을 설정&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;할 수 있다. &lt;/span&gt;캐시된 데이터가 만료 되면 캐시에서 제거 되고 응용 프로그램은 원래 데이터 저장소에서 데이터를 검색 해야 한다. 캐시 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;만료 주기가 너무 짧으면 데이터는 너무 빨리 제거되고 캐시를 사용하는 이점은 줄어든다. 반대로 너무 기간이 길면 데이터가 변경될 가능성과 메모리 부족 현상이 발생하거나, 자주 사용되어야 하는 데이터가 제거되는 등의 역효과를 나타낼 수도 있다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;캐시 서비스는 LRU 알고리즘 기반으로 데이터를 제거하지만 일반적으로 이 정책을 재정의하고 항목을 제거하지 않도록 방지할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;4) 캐시 공유&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;캐시는 애플리케이션의 여러 인스턴스에서 공유하도록 설계된다. 각 애플리케이션 인스턴스가 캐시에서 데이터를 읽고 수정할 수 있다. 따라서 모든 공유 데이터 저장소와 함께 발생하는 &lt;span style=&quot;color: #ee2323;&quot;&gt;동일한 동시성 문제는 캐시에도 적용&lt;/span&gt;된다. 애플리케이션이 캐시에 보유하는 데이터를 수정해야 하는 경우 애플리케이션의 한 인스턴스가 만드는 업데이트가 다른 인스턴스가 만든 변경을 덮어쓰지 않도록 해야 한다.&lt;br /&gt;데이터의 충돌을 방지하기 위해 다음과 같은 어플리케이션 개발 방식을 취해야 한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;먼저, 캐시 데이터를 변경하기 직전에 데이터가 검색된 이후 변경되지 않았는지 확인하는 방법이다. 변경되지 않았다면 즉시 업데이트하고 변경되었다면 업데이트 여부를 애플리케이션 레벨에서 결정하도록 수정해야 한다. 이와 같은 방식은 업데이트가 드물고 충돌이 발생하지 않는 상황에 적용하기 용이하다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;두번째로, 캐시 데이터를 업데이트 하기 전에 Lock을 잡는 방식이다. 이와 같은 경우 조회성 업무를 처리하는 서비스에 Lock으로 인한 대기현상이 발생한다. 이와 같은 방식은 데이터의 사이즈가 작아 빠르게 업데이트가 가능한 업무와 빈번한 업데이트가 발생하는 상황에 적용하기 용이하다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;5) 가용성 및 성능 확보&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&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;span style=&quot;color: #ee2323;&quot;&gt;캐시 서버가 장애로 부터 복구되는 동안 성능상의 지연은 발생할 수 있지만, 서비스가 불가능한 상태가 되지 않도록 고려&lt;/span&gt;해야 한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Redis 설계&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Redis는 NoSQL 데이터베이스로 대부분 유휴 상태인 대량 데이터를 저장하지 않도록(즉, 자주 변경되고, 이동되는 데이터가 저장되도록) 설계되었다. 또한 &lt;span style=&quot;color: #000000;&quot;&gt;Redis 데이터베이스는 설치 공간이 작고 최소한의 리소스로도 엄청난 처리량을 제공 할 수 있다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;마이크로서비스 아키텍처에서 각 서비스는 비즈니스의 모든 것을 실행하는 것이 아니라 서비스별 특정 용도에 맞게 설계되어있다. &lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;즉, Redis 데이터베이스는 NoSQL 데이터베이스로 비용효율적으로 동작하여 마이크로 서비스 환경에서 적합하게 활용할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;각 서비스는 비즈니스 프로세스 측면에서 독립된 역할을 수행하도록 설계되었으므로 데이터는 비 관계형이며 NoSQL 데이터 모델에 적합하다. Redis는 마이크로서비스 아키텍처에 저장된 데이터에 대해 모든 측면에서 적합하지는 않지만, 많은 요구사항에 부합한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;기존 마이크로 서비스 환경에서 서비스 간 통신은 REST 또는 유사한 규칙을 사용하는 HTTP 엔드 포인트를 적용해 왔다.&amp;nbsp; &lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이때 Redis는 &lt;span style=&quot;color: #000000;&quot;&gt;스트림(Stream)처리를 지원하는 Redis Stream을 적용할 수 있다. Redis Stream은 스트림 데이터 또는 &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;로그 데이터를 처리하기 위해서 5.0에서 새로 도입된 데이터 타입이다. &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;대부분의 프로젝트에서는 데이터가 지속적으로 누적되어 쌓이는 경우가 발생할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;스트림(Stream) 또는 로그(Log)는 사람이 아니고 기계(machine)가 발생시키며 연속적이고 대량이라는 특징이 있다. 또한 기존 데이터를 수정하지 않고 오직 추가로 발생한다는 점이다. &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이 경우 Redis Streams는 모든 서비스가 해당 스트림에서 이벤트를 알리고 관심있는 서비스에 속하는 스트림만 수신하는 완전 비동기 패턴을 허용한다.이 시점에서 양방향 통신은 서로의 스트림을 관찰하는 두 서비스에 의해 달성된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;또한 &lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Redis는 항상 데이터베이스에서 직접 데이터를 검색해야하는 것은 아닌 Redis에서 훨씬 더 빠르게 데이터를 가져올 수 있는 캐시 역할을 한다. &lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;마찬가지로 API를 통해 액세스 해야 하는 외부 데이터 서비스도 너무 느릴 수 있으며 여기에서 Redis를 사용하여 불필요하고 긴 호출이 시스템의 전체 성능에 영향을 미치는 것을 방지 할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;지금부터는 Redis 관련 세부 설계 요소를 살펴보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;1) 단일 쓰레드 환경&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Redis는 단일 쓰레드로 동작하는 인메모리 DB라는 특징을 갖고 있다. 단일 쓰레드로 동작한다는 의미는 한번에 1개의 명령어만 실행할 수 있다는 의미이며, 이와 같은 특성에 의해 개발 및 구성 시 고려해야 할 부분들이 있다. (물론 Async로 동작하는 Background 프로세스가 있지만, 서비스를 처리하는 동작은 기본 1 Redis 1 Worker를 기준으로 동작한다.)&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;a. Long Time Query 처리&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;단일 쓰레드로 동작하는 Redis는 오래 걸리는 명령어를 사용할 경우 해당 시간동안 다른 명령어 또는 서비스를 처리할 수 없다. 따라서 운영 환경에서는 다음과 같은 경우를 주의하여 처리해야 한다.&lt;/span&gt;&lt;br /&gt;- &lt;span style=&quot;color: #000000;&quot;&gt;keys * 명령어&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;keys는 해당 노드에 저장된 모든 키를 보여주는 명령어이다. 대량 데이터가 저장되어 있는 시스템의 경우 keys를 수행하는데 수초 또는 수분의 조회 시간이 발생할 수 있어, 운영환경에서 사용하는 것은 권고하지 않는다. 운영 환경에서 keys를 조회하고자 할 경우에는 &lt;span style=&quot;color: #ee2323;&quot;&gt;keys 명령어 대신 scan 명령어를 사용하는 것을 권고&lt;/span&gt;한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;[keys]&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;html xml&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;[root@ip-192-168-106-237 utils]# redis-cli -c -p 8000 127.0.0.1:8000&amp;gt; keys pattern ====================================================== 127.0.0.1:8000&amp;gt; keys * 1) &quot;test4&quot; 2) &quot;11&quot; 3) &quot;7&quot; 4) &quot;j&quot; 5) &quot;ee&quot; 6) &quot;3&quot; 7) &quot;s&quot; 8) &quot;f&quot; 9) &quot;test5&quot; 10) &quot;10&quot; 11) &quot;b&quot; 12) &quot;n&quot; 127.0.0.1:8000&amp;gt; &lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;[scan]&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;key 수가 많을 수록 처리시간이 증가하는 keys 명령어를 대체하기 위해 scan 명령어를 활용할 수 있다.&lt;br /&gt;keys는 한번에 모든 key를 full scan하여 조회하는 반면, scan은 한번에 약 10개씩 정도씩 key를 조회한다. &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;key가 많으면 다음 커서를 지정해서 반복해서 조회한다. 모두 조회했을 경우 next cursor가 0이 된다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;html xml&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;[root@ip-192-168-106-237 utils]# redis-cli -c -p 8000 127.0.0.1:8000&amp;gt; scan cursor [MATCH pattern] [COUNT count] ====================================================== 127.0.0.1:8000&amp;gt; scan 0 1) &quot;15&quot; 2) 1) &quot;7&quot; 2) &quot;test4&quot; 3) &quot;test5&quot; 4) &quot;10&quot; 5) &quot;f&quot; 6) &quot;j&quot; 7) &quot;b&quot; 8) &quot;11&quot; 9) &quot;ee&quot; 10) &quot;3&quot; 11) &quot;s&quot; 127.0.0.1:8000&amp;gt; scan 0 count 5 1) &quot;5&quot; 2) 1) &quot;7&quot; 2) &quot;test4&quot; 3) &quot;test5&quot; 4) &quot;10&quot; 5) &quot;f&quot; 127.0.0.1:8000&amp;gt; scan 5 count 5 1) &quot;15&quot; 2) 1) &quot;j&quot; 2) &quot;b&quot; 3) &quot;11&quot; 4) &quot;ee&quot; 5) &quot;3&quot; 6) &quot;s&quot; 127.0.0.1:8000&amp;gt; scan 15 count 5 1) &quot;0&quot; 2) 1) &quot;n&quot; 127.0.0.1:8000&amp;gt; scan 0 count 5 match test* 1) &quot;5&quot; 2) 1) &quot;test4&quot; 2) &quot;test5&quot; 127.0.0.1:8000&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;scan의 count는 조회 대상 key의 수이다. 기본으로 10개를 조회하지만, default 값 또는 지정한 수가 정확히 조회되지는 않는다. 조회되는 수는 처리 시간을 고려하여 Redis에서 자동으로 산정한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;또한 match는 조회 대상 key들의 패턴을 검색 조건으로 지정하는 방법이다. 이와 같이 scan 명령어를 사용하면 keys의 전체 조회에 따른 성능 저하 현상을 방지할 수 있다.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;- &lt;span style=&quot;color: #000000;&quot;&gt;flushall 명령어&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;flushall은 현재 지정된 Master Node의 key와 data를 모두 제거하는 명령어이다. 대량 데이터가 저장되어 있는 환경에서 flushall을 사용할 경우 심각한 성능 지연 현상을 초래할 수 있다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;따라서 &lt;span style=&quot;color: #ee2323;&quot;&gt;flushall은 가급적 운영환경에서 사용하는 것은 권고하지 않는다. 다만, 부득이하게 사용해야 할 경우 async 옵션을 적용하여 반영&lt;/span&gt;한다. Redis Server 4부터 async 옵션을 사용할 수 있으며, flushall 수행 시 별도의 쓰레드를 생성하여 background로 삭제하기 때문에 응답 속도가 매우 빠르고, 지연을 방지할 수 있다. 측정된 데이터를 기준으로 String key 백만개를 flush할 경우 Sync는 약 1초, Async는 1ms 미만이내에 명령이 수행된다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이와같이 두 명령어는 개발/테스트 환경이나 소량의 데이터를 관리하는 환경에서는 적극 활용할 수 있으나, 실행 대상을 전수처리하기 때문에 데이터가 누적되는 시스템 또는 대량 데이터를 저장하는 시스템의 경우 운영에 영향을 줄 정도로 속도가 느려질 수 있다. 따라서 운영환경에서 해당 명령어를 적용하기 위해서는 반드시 유의사항에 따라 옵션을 검토해 보는 것이 좋다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;# 참조&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Redis Server 4 이상에서 지원하는 &lt;span style=&quot;color: #ee2323;&quot;&gt;Lazy Freeing 기능을 활용하여 UNLINK 옵션을 적용할 경우 비동기로 처리&lt;/span&gt;할 수 있다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그 밖에 flushdb, collection 관련 삭제, 조회 등의 명령어는 가급적 운영환경에서 사용하지 않는 것을 권고한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;b. Collection 활용&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;단일 쓰레드 환경에서 Long Time Query는 서비스 지연의 원인이 된다. Redis와 같은 캐시 솔루션은 단일 데이터 조회시 hash key를 기반으로 조회하기 때문에 대부분 조회 성능은 빠르게 처리된다. 다만, Redis에는 Memcached와 달리 Collection Type을 제공한다. Collection은 대량 데이터 조회에 보다 유용하게 활용될 수 있지만, 단일 Collection에 데이터 100만건을 넣으면 10초, 1천만건을 넣으면 100초씩 걸리는 식으로 시간이 늘어나기 때문에 &lt;span style=&quot;color: #ee2323;&quot;&gt;Collection 당 저장해야 하는 데이터 사이즈는 1만건 미만으로 관리&lt;/span&gt;하는 것이 좋다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;또한, Hash, Sorted Set, Set과 같은 Collection은 메모리를 많이 사용점유하므로 필요에 의한 적용이 필요하다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;c. Multi Instance 구성&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Redis는 데이터 저장 및 조회에 단일 쓰레드를 사용한다. 따라서 멀티코어 시스템에서 성능을 최대한 끌어내기 위해서는 인스턴스 여러 개를 실행하여 성능을 향상시킬 수 있다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;대체로 &lt;span style=&quot;color: #ee2323;&quot;&gt;멀티코어 환경에서는 전체 코어의 절반이하의 Redis 인스턴스를 기동하여 운영하는 것이 적당&lt;/span&gt;하다. (ex - 4Core System은 max 2개의 Instance, 8Core System은 max 4개까지 인스턴스 기동을 권고한다.)&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;물론 코어만 충분하다고 해서 여러개의 인스턴스를 늘려 나갈 수 있는 것은 아니다. 바로 메모리 대여폭에 대한 임계점 문제가 발생할 수 있다. 메모리 임계점에 대한 내용은 하단을 참고한다. Memory 대여폭이 충분하다는 가정하여 위와 같은 기준치를 세우고 구성해 나가는 것이 바람직하다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Multi Instance 환경에서 특히 고려해야 할 부분은 SMS나 APM 모니터링 환경 구성시 노드 전체 사용률을 기반으로 모니터링을 해서는 안된다는 점이다. 단일 쓰레드로 처리되기 때문에 하나의 Redis는 하나의 Core를 점유하게 되고, 하나의 Core만 100%를 차지하게 된다. 즉, 4Core VM 환경을 가정할 경우 Redis Server 하나가 100% CPU를 점유할 경우 노드 기준으로는 25%만 사용중이라는 의미이다. 따라서, SMS 알람을 노드 기준 75% 수준으로 지정하는 것은 바람직한 모니터링 구성이 아닐 수 있다. 이때는 &lt;span style=&quot;color: #ee2323;&quot;&gt;노드 기준의 모니터링이 아닌 프로세스 기준으로 모니터링을 실행&lt;/span&gt;해야 한다.&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;2) 리소스 활용&lt;/span&gt;&lt;/h2&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;a. Memory 구성 고려사항&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Redis는 데이터를 메모리에 저장하는 대표적인 인메모리 DB이다. 따라서 Redis가 사용할 메모리 크기를 지정하는 것은 성능과 가장 밀접한 관계가 있다.&lt;/span&gt;&lt;br /&gt;- &lt;span style=&quot;color: #000000;&quot;&gt;memory 사이즈&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;별도로 Redis의 설정파일인 redis.conf의 maxmemory 설정을 하지 않을 경우 0으로 구성되며, OS에서 사용 가능한 Max Memory까지 확장하여 사용하게 된다. 이는 특정 인스턴스의 장애가 동일 노드의 다른 Redis 인스턴스로의 전파를 일으킬 수 있다. 특히 물리 메모리를 모두 사용하는 상황이 발생할 경우 스왑 메모리 영역을 사용하게 되는데 이때 Redis의 성능은 상황에 따라 수백배까지 느려질 수 있다. 따라서 반드시 &lt;span style=&quot;color: #ee2323;&quot;&gt;maxmemory를 설정&lt;/span&gt;하여 메모리 사용계획과 저장되는 데이터 LifeCycle을 관리하는 정책을 세워야 한다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;- &lt;span style=&quot;color: #000000;&quot;&gt;메모리 대여폭&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;메모리 대여폭은 동작 속도를 의미하며, 대여폭이 높을 수록 빠르다고 볼 수 있다. (물론 대여폭이 높다고 항상 성능이 좋아지는 것은 아니다. 일정 수준의 대여폭이 확보되면 이후에는 대여폭의 영향은 성능에 영향을 거의 주지 않는다.) 메모리의 속도는 메모리 자체 속도와 CPU와의 데이터 전송폭을 모두 고려한다. &lt;span style=&quot;color: #ee2323;&quot;&gt;메모리 대여폭은 &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;초당 바이트 전송률이라 볼 수 있으며, 흔히 &amp;lsquo;Bandwidth&amp;rsquo;&lt;/span&gt;이라고 한다.&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Redis에서 동일 노드에 여러 개의 인스턴스를 운영시 메모리 대여폭의 임계점에 문제가 발생할 수 있다. 여러 개의 인스턴스들이 동시에 명령을 처리할 경우 Redis는 명령 처리를 위해 메모리에 접근하고 조회된 데이터는 메모리 대여폭을 사용하여 코어로 전송한다. 즉 Redis 인스턴스가 메모리 대여폭을 나누어 사용하므로 병목현상이 발생할 수 있다. 따라서 충분한 메모리 대여폭이 확보된 상태에서 멀티 인스턴스를 구성하는 것을 고려해야 한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;b. Network 임계점 고려&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Master와 Slave 간 데이터 전송과 동기화로 인해 네트워크에 부하가 발생할 수 있다. Master Node에 Write가 발생하면 연결된 Slave Node에 Redis 프로토콜을 사용하여 데이터를 전송한다. Key와 데이터의 크기에 해당하는 네트워크 대여폭을 사용하게 된다. 따라서 각 &lt;span style=&quot;color: #ee2323;&quot;&gt;마스터는 Write가 발생할 때마다 복제를 위한 Slave 갯수 만큼의 추가 트래픽이 발생&lt;/span&gt;하게 된다. 가용성만을 중시하는 아키텍처는 네트워크 부하를 발생시킬 수 있음을 인지해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;c. Persistence 볼륨 관리&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Redis는 인메모리 DB와 디스크 활용 측면에서 검토가 필요하다. Redis의 인메모리 DB는 빠른 속도가 강점이지만 큰 용량의 데이터를 담기엔 사이즈 제약이 크다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;따라서 &lt;span style=&quot;color: #ee2323;&quot;&gt;실시간 처리는 인메모리, 자주 사용되지 않는 데이터의 저장 관리는 디스크 기반 스토리지로 하는 구조가 성능과 효율&lt;/span&gt;을 함께 달성할 수 있다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;먼저 &lt;span style=&quot;color: #ee2323;&quot;&gt;메모리 상태를 그대로 &lt;span style=&quot;color: #ee2323;&quot;&gt;디스크에 &lt;/span&gt;저장하는&lt;/span&gt; &lt;span style=&quot;color: #ee2323;&quot;&gt;RDB(Snapshot) 기능이 있다. 이 기능은 Redis 서버 장애 요인의 대부분을 차지&lt;/span&gt;하기도 한다. 따라서 해당 기능은 반드시 필요한 경우를 제외하고 꺼두거나 구성을 민감하게 관리하는 것이 좋다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Redis의 SnapShot은 매우 짧은 시간에 매우 많은 디스크 입출력이 발생하는데, 외부 저장장치는 로컬 디스크에 비하여 스냅샷 파일을 기록하는데 많은 시간이 소요된다. 이와 같은 이유로 스냅샷이 완료되기 전까지 Redis의 전체적인 성능도 같이 떨어지게 된다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Master/Slave 복제 구성에서 Master Node의 스냅샷 설정이 꺼져 있더라도, 새로운 슬레이브 노드가 마스터에 추가되면 마스터 노드는 스냅샷을 생성한다. redis.conf의 client-output-buffer-limit은 Redis 복제를 위해 스냅샷 데이터를 전송할 버퍼를 생성하는데, 이 버퍼의 크기가 지정된 크기보다 커지면 슬레이브의 연결을 강제로 끊게 된다. 이때 슬레이브는 마스터 노드와 연결이 끊어졌으므로 다시 Master Node로 접속을 시도하고, 접속 후에는 Master Node의 스냅샷이 생성되는 현상이 반복되게 된다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;대략 60GB 메모리 서버의 스냅샷을 만드는데 대략 10분 정도가 소요된다. Redis의 싱글쓰레드 문제를 겪지 않기 위해 Fork()를 사용하여 분기 처리할 수 있지만, 이 경우 메모리를 2배로 잡아 먹어 리소스가 부족현상을 발생시킬 수 있다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;다음으로 메모리 상의 정보를 디스크에 저장한다는 점은 RDB와 비슷하나, &lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;Redis 프로토콜로 통신한 내용들을 명령어, 키, 이름 등 형식 그대로 저장하는 &lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;AOF&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 기능이 있다. RDB 사용시 주의사항은 AOF에도 동일하게 적용된다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;RDB와 AOF 방식의 장단점을 상쇄하기 위해서 두가지 방식을 혼용해서 사용하는 것이 바람직하다. &lt;span style=&quot;color: #ee2323;&quot;&gt;주기적으로 RDB(SnapShot)으로 백업하고, 다음 스냅샷 생성 전까지의 저장은 AOF 방식으로 수행&lt;/span&gt;한다. 이렇게 하면 서버가 Restart 될때 백업된 스냅샷을 Reload하고, 소량의 AOF 로그만 Replace하면 되기 때문에, Restart 시간을 절약하고 데이터 유실을 방지할 수 있다.&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;3) 복제&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Master/Slave Replication이란, &lt;span style=&quot;color: #ee2323;&quot;&gt;Redis의 Master Node에 Write 된 내용을 Slave Node에 복제하는 것&lt;/span&gt;을 의미한다. 1개의 Master Node는 N개의 Slave Node를 가질 수 있으며, 각 Slave Node도 그에 대한 Slave Node를 또 가질 수 있다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이 노드 간 복제는 Non-Blocking 상태로 이루어진다. 즉 Master Node에서 Write나 Query 연산을 하고 있을 때도 Background로 Slave Node에 데이터를 복사하고 있다는 이야기이며, 이는 순간적으로 Master/Slave가 데이터 불일치성을 유발할 수도 있다는 이야기이기도 하다. 즉 Master Node에 Write한 데이터가 Slave Node에 복제 중이라면 Slave Node에서는 이전의 데이터가 조회될 수 있다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Redis 시스템에서 Slave는 이름처럼 마스터의 데이터 저장을 보조한다. 마스터가 죽었다가 되살아날 때 자신의 정보를 모두 없애고 그 데이터를 그대로 복제한다. 별도 조치 없이 아무 데이터가 없는 Master를 시스템에 연결하면 Slave에 남은 데이터를 Master로 되살릴 수 없다. 이를 피하기위해서는 복구할 데이터를 가진 시스템에 &quot;Slave of no one(슬레이브오브노원)&quot;이라는 명령어를 줘서 Slave를 Master로 승격시켜야 한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;또한 Redis의 복제를 구성할 때 하나의 Master에 너무 많은 Slave를 구성하지 않도록 한다. 너무 많은 Slave는 가용성을 높이지만 데이터를 복제하기 위한 네트워크 사용률이 데이터 서비스를 위한 네트워크 사용률보다 커지게 되어 매우 느린 응답시간을 보이게 된다. 이를 위해 복제를 위한 별도의 네트워크 카드를 설정하는 방법과 복제를 위한 별도의 스위치 허브를 구성하는 방법을 고려할 수 있다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Master/Slave간 동시접속자수나 처리 속도를 높이기 위해 &lt;span style=&quot;color: #ee2323;&quot;&gt;Query Off Loading이라는 기법을 사용하는데 Master는 Write Only, Slave는 Read Only로 사용하는 방법&lt;/span&gt;이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;a. Redis SENTINEL&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;장애시 복구를 위한 복제 작업을 Redis SENTINEL이라는 기술로 자동화할 수 있다. Redis SENTINEL은 Redis 시스템에서 마스터가 죽었다고 판단 시 다른 슬레이브를 마스터로 승격하고 사용자측에 마스터가 바뀌었다는 알림을 보내는 도구이다.&lt;br /&gt;Redis SENTINEL을 사용해 Redis 환경에서 마스터와 슬레이브를 지정하는 방식, 우선순위 결정 원리, 실제 서비스 운영환경에서 Fail-over를 수행하기 위한 적정 설정값, 레디스 프로젝트에서 진행되고 있는 Redis SENTINEL 기술에 대한 개선 작업 현황 등을 함께 고려해야 한다.&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;4) 확장성 및 고 가용성&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Redis는 확장성과 고 가용성을 달성하기 위한 다양한 방법을 제공한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;데이터를 여러 Redis 노드로 분할하여 Redis Sharding을 사용하여 수평 확장 구성 할 수 있다.&amp;nbsp;Sharding은 단일 인스턴스의 부담을 덜어주고 멀티 코어환경에서 이점을 누릴 수 있다.&amp;nbsp;그러나 Multi Key 작업 및 트랜잭션을 지원할 수 없기 때문에 샤딩의 한계를 알고 있어야한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;복제를 사용하여 고 가용성을 얻을 수 있다.&amp;nbsp;마스터 노드는 동기식으로 복제되며 노드 장애, 데이터 센터 장애 및 Redis 프로세스 장애로부터 보호되도록 구성할 수 있다.&amp;nbsp;마스터가 실패하면 복제본이 대신 마스터를 수행한다.&amp;nbsp;다른 AZ에 복제본이있을 수도 있다.&amp;nbsp;이렇게하면 전체 AZ가 실패하는 일부 치명적인 이벤트로부터 보호될 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;# 참조&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;a href=&quot;https://medium.com/@octoz/high-availability-and-scalability-with-redis-enterprise-54a48edcce17&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://medium.com/@octoz/high-availability-and-scalability-with-redis-enterprise-54a48edcce17&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;5) 기타&lt;/span&gt;&lt;/h2&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;a. Fork 활용&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Redis는 &lt;span style=&quot;color: #ee2323;&quot;&gt;AOF와 RDB(SnapShot)을 위해서 fork() 함수와 COW(Copy On Write : 서로 다른 프로세스 간의 리소스 공유)를 사용하여 백그라운드 저장 프로세스를 생성&lt;/span&gt;한다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;b. 저장 만료 주기 관리&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;max-memory만큼 메모리를 사용하게 되면, 메모리 정책에 따라 과거에 만들어진 키들이 삭제&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;된다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Redis 서버는 In-Memory 기반의 데이터 저장 관리기술을 제공하지만 시스템 메모리 크기는 제한적일 수 밖에 없고 상대적으로 사용자 데이터는 이보다 훨씬 더 클 수 밖에 없기 때문에 모든 데이터를 100% 메모리에서 저장 관리할 수는 없다. 이와 같은 문제점을 개선하기 위해 Redis 서버는 4.0 버전부터 LRU(Least Recently Used: 가장 최근에 사용되지 않은 것) 알고리즘과 LFU(Least-Frequently-Used: 가장 적게 사용된 것) 알고리즘을 제공하고 있다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Redis가 Export 된 데이터를 삭제하는 정책은 내부적으로 active와 passive 두가지 방법을 사용한다. &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;active는 요청된 key가 호출된 시점에 expired 여부를 검증하여 삭제하는 방법이며, &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;passive는 random으로 key 100개만 반복적으로 스캔해서 지우는 방식이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;expired time이 지난 후 클라이언트에 의해서 접근되지 않는 데이터는 active 방식으로 인해서 지워지지 않고 passive 방식으로 지워져야 하는데, 마찬가지로 전체를 scan하는 것이 아니기 때문에 Redis에는 항상 Expired 되었으나 지워지지 않는 Garbage 데이터가 존재할 수 있다는 점을 명심해야 한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;html xml&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;[root@ip-192-168-106-237 ~]# redis-cli -c -p 8000 127.0.0.1:8000&amp;gt; set a 100 -&amp;gt; Redirected to slot [15495] located at 127.0.0.1:8002 OK 127.0.0.1:8002&amp;gt; expire a 100 (integer) 1 127.0.0.1:8002&amp;gt; ttl a (integer) 97 127.0.0.1:8002&amp;gt; ttl a (integer) 93 127.0.0.1:8002&amp;gt; ttl a (integer) 60 127.0.0.1:8002&amp;gt; ttl a (integer) -2 127.0.0.1:8002&amp;gt; get a (nil) 127.0.0.1:8002&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Redis는 결국 메모리에 저장되는 데이터 구조를 갖고 있기에 메모리를 어떻게 관리할 것인지가 성능과 가용성에 큰 영향을 끼치게 된다. &lt;span style=&quot;color: #000000;&quot;&gt;Redis가 Max Memory에 도달할 경우 다음 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Policy 중에서 선택하여 키와 데이터를 관리할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100.0%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%; text-align: justify;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;i&gt;&lt;span style=&quot;color: #000000;&quot;&gt;a. noeviction&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;캐시를 지우지 않는 정책이다. 메모리가 maxmemory 이상을 사용하게 되면 error를 발생시킨다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;b. allkey&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;각 정책에 따라 모든 키를 대상으로 정리한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;allkeys-lru&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;LRU 알고리즘 기반으로 키를 삭제한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;allkey-random&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;랜덤하게 키를 삭제한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;allkeys-lfu&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;LFU 알고리즘 기반으로 키를 삭제한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;c. volatile&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;각 정책에 따라 EXPIRE SET에 있는 키들을 대상으로 정리한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;volatile-lru&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;LRU 알고리즘 기반으로 키를 삭제한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;volatile-random&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;랜덤하게 키를 삭제한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;volatile-ttl&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;TTL이 짧은 순으로 삭제한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;volatile-lfu&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;LFU 알고리즘 기반으로 키를 삭제한다.&lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;# LRU는 가장 최근에 사용한 것을 의미&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;# LFU는 가장 적게 사용됨을 의미&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;# LRU, LFU 및 최소 TTL 알고리즘은 정밀한 알고리즘이 아니라 근사치&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;c. Memory Fragment&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;maxmemory 대비 사용된 메모리 비율이 낮더라도 메모리 조각화로 인해 Redis 인스턴스의 메모리가 부족해질 수 있다. 메모리 조각화는 운영체제가 반복적인 쓰기 및 삭제 작업 후 Redis가 완전히 활용할 수 없는 메모리 페이지를 할당할 때 발생한다. 이러한 페이지가 누적되면 시스템 메모리가 부족해져 Redis 서버가 다운될 수 있다.&lt;br /&gt;Redis 버전 4.0 이상에서는 activedefrag 구성을 제공한다. &lt;span style=&quot;color: #ee2323;&quot;&gt;activedefrag를 yes로 설정하면 CPU 사용량이 증가하지만 메모리 조각화를 완화하여 메모리 부족 문제를 해결&lt;/span&gt;할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;결론&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Redis와 같은 인메모리 DB는 마이크로서비스와 같이 확대되는 분산 아키텍처 구조에서 유용하게 활용되고 있다. 단순히 세션 서버의 용도를 벗어나 자주 사용되는 데이터 캐시 용도, 때로는 데이터 전송을 위한 Queue 용도로도 활용할 수 있다. 이와 같은 IMDG의 경우 또 하나의 SPOF가 될 수도 있기 때문에 반드시 각 설계 요소들을 검토하고, 보다 주의 깊게 설정을 검토하는 것이 반드시 필요할 것이다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>⑦ Open Source Software</category>
      <category>activedefrag</category>
      <category>allkey</category>
      <category>AOF</category>
      <category>cache aside</category>
      <category>noeviction</category>
      <category>Redis</category>
      <category>sentinel</category>
      <category>volatile</category>
      <category>Write Back</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/697</guid>
      <comments>https://waspro.tistory.com/697#entry697comment</comments>
      <pubDate>Sat, 15 May 2021 21:27:12 +0900</pubDate>
    </item>
    <item>
      <title>Redis5 Cluster 구성하기</title>
      <link>https://waspro.tistory.com/696</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;지난 포스팅에서는 Redis에 대해 알아보고 설치하는 과정에 대해 살펴보았다. 이번 포스팅에서는 Redis의 가용성을 높여주기 위한 Cluster 환경을 구성하는 방법에 대해 살펴보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;지난 포스팅은 다음을 참고한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;a href=&quot;https://waspro.tistory.com/477?category=871040&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[Redis&amp;nbsp;5.x]&amp;nbsp;오픈소스&amp;nbsp;기반&amp;nbsp;비관계형&amp;nbsp;데이터베이스&amp;nbsp;관리&amp;nbsp;시스템&lt;/a&gt; &lt;br /&gt;&lt;a href=&quot;https://waspro.tistory.com/478?category=871040&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[Redis&amp;nbsp;5.x]&amp;nbsp;설치&amp;nbsp;및&amp;nbsp;CLI&amp;nbsp;활용&amp;nbsp;가이드&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Master Cluster 구성&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;798&quot; data-origin-height=&quot;334&quot; width=&quot;500&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4kkrE/btq4cNXDdyH/ecfUoBKDKjQABfsExsqTPK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4kkrE/btq4cNXDdyH/ecfUoBKDKjQABfsExsqTPK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4kkrE/btq4cNXDdyH/ecfUoBKDKjQABfsExsqTPK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4kkrE%2Fbtq4cNXDdyH%2FecfUoBKDKjQABfsExsqTPK%2Fimg.png&quot; data-origin-width=&quot;798&quot; data-origin-height=&quot;334&quot; width=&quot;500&quot; data-ke-mobilestyle=&quot;widthContent&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;/&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: 'Noto Serif KR'; color: #000000;&quot;&gt;1. Redis Master Server Add (sh install_server.sh)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;먼저 Cluster에 추가할 서버를 설치한다. (localhost:6379, &lt;span style=&quot;color: #000000;&quot;&gt;localhost:6479, &lt;span style=&quot;color: #000000;&quot;&gt;localhost:6579&lt;/span&gt;&lt;/span&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1620198068331&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;##### install_server.sh 위치 #####
[root@ip-192-168-73-84 redis-5.0.5]# cd utils/
[root@ip-192-168-73-84 utils]# ls
build-static-symbols.tcl  corrupt_rdb.c   generate-command-help.rb  hashtable    install_server.sh  redis-copy.rb      redis_init_script.tpl  releasetools          whatisdoing.sh
cluster_fail_time.tcl     create-cluster  graphs                    hyperloglog  lru                redis_init_script  redis-sha1.rb          speed-regression.tcl

##### 6379 server add  #####
[root@ip-192-168-73-84 utils]# sh install_server.sh 
Welcome to the redis service installer
This script will help you easily set up a running redis server

Please select the redis port for this instance: [6379] 
Selecting default: 6379
Please select the redis config file name [/etc/redis/6379.conf] 
Selected default - /etc/redis/6379.conf
Please select the redis log file name [/var/log/redis_6379.log] 
Selected default - /var/log/redis_6379.log
Please select the data directory for this instance [/var/lib/redis/6379] 
Selected default - /var/lib/redis/6379
Please select the redis executable path [/usr/local/bin/redis-server] 
Selected config:
Port           : 6379
Config file    : /etc/redis/6379.conf
Log file       : /var/log/redis_6379.log
Data dir       : /var/lib/redis/6379
Executable     : /usr/local/bin/redis-server
Cli Executable : /usr/local/bin/redis-cli
Is this ok? Then press ENTER to go on or Ctrl-C to abort.
Copied /tmp/6379.conf =&amp;gt; /etc/init.d/redis_6379
Installing service...
Successfully added to chkconfig!
Successfully added to runlevels 345!
Starting Redis server...
Installation successful!
[root@ip-192-168-73-84 utils]#

##### 6479 server add  #####
Please select the redis port for this instance: [6379] 6479       
Please select the redis config file name [/etc/redis/6479.conf] 
Selected default - /etc/redis/6479.conf
Please select the redis log file name [/var/log/redis_6479.log] 
Selected default - /var/log/redis_6479.log
Please select the data directory for this instance [/var/lib/redis/6479] 
Selected default - /var/lib/redis/6479
Please select the redis executable path [/usr/local/bin/redis-server] 
Selected config:
Port           : 6479
Config file    : /etc/redis/6479.conf
Log file       : /var/log/redis_6479.log
Data dir       : /var/lib/redis/6479
Executable     : /usr/local/bin/redis-server
Cli Executable : /usr/local/bin/redis-cli
Is this ok? Then press ENTER to go on or Ctrl-C to abort.
Copied /tmp/6479.conf =&amp;gt; /etc/init.d/redis_6479
Installing service...

Successfully added to chkconfig!
Successfully added to runlevels 345!
Starting Redis server...
Installation successful!

##### 6579 server add  #####
[root@ip-192-168-73-84 utils]# sh install_server.sh 
Welcome to the redis service installer
This script will help you easily set up a running redis server

Please select the redis port for this instance: [6379] 6579
Please select the redis config file name [/etc/redis/6579.conf] 
Selected default - /etc/redis/6579.conf
Please select the redis log file name [/var/log/redis_6579.log] 
Selected default - /var/log/redis_6579.log
Please select the data directory for this instance [/var/lib/redis/6579] 
Selected default - /var/lib/redis/6579
Please select the redis executable path [/usr/local/bin/redis-server] 
Selected config:
Port           : 6579
Config file    : /etc/redis/6579.conf
Log file       : /var/log/redis_6579.log
Data dir       : /var/lib/redis/6579
Executable     : /usr/local/bin/redis-server
Cli Executable : /usr/local/bin/redis-cli
Is this ok? Then press ENTER to go on or Ctrl-C to abort.
Copied /tmp/6579.conf =&amp;gt; /etc/init.d/redis_6579
Installing service...
Successfully added to chkconfig!
Successfully added to runlevels 345!
Starting Redis server...
Installation successful!
[root@ip-192-168-73-84 utils]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2. Redis Master Config Modify (vi /etc/redis/6379.conf)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1620203419242&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-73-84 utils]# cd /etc/redis/
[root@ip-192-168-73-84 redis]# ls
6379.conf  6479.conf  6579.conf
[root@ip-192-168-73-84 redis]# vi *
3 files to edit
...
...
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 15000
...
appendonly yes
...
...
[root@ip-192-168-73-84 redis]# &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;6379.conf, 6479.conf, 6579.conf 각각 위와 같이 설정파일을 수정하고 저장한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;3. Redis Master Server Restart (service redis_6379 restart)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1620203546599&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-73-84 redis]# service redis_6379 restart
Stopping ...
Redis stopped
Starting Redis server...
[root@ip-192-168-73-84 redis]# service redis_6479 restart
Stopping ...
Redis stopped
Starting Redis server...
[root@ip-192-168-73-84 redis]# service redis_6579 restart
Stopping ...
Redis stopped
Starting Redis server...
[root@ip-192-168-73-84 redis]# ps -ef | grep redis
root      8432     1  0 22:47 ?        00:00:00 /usr/local/bin/redis-server 127.0.0.1:6379 [cluster]
root      8449     1  0 22:47 ?        00:00:00 /usr/local/bin/redis-server 127.0.0.1:6479 [cluster]
root      8466     1  0 22:47 ?        00:00:00 /usr/local/bin/redis-server 127.0.0.1:6579 [cluster]
root      8471  7923  0 22:47 pts/1    00:00:00 grep --color=auto redis
[root@ip-192-168-73-84 redis]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Redis Cluster는 ruby로 구성되어 있어 아래와 같이 package 설치를 진행한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1620203635007&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;yum install ruby ruby-devel rubygems rpm-build&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;gem install redis 명령어로 Redis Cluster 설치시 다음과 같은 문제가 발생했을 경우 ruby 버전을 다음과 같이 업그레이드 한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1621378324297&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-106-237 utils]# gem install redis
Fetching: redis-4.2.5.gem (100%)
ERROR:  Error installing redis:
        redis requires Ruby version &amp;gt;= 2.3.0.
[root@ip-192-168-106-237 utils]# yum install curl gpg gcc gcc-c++ make patch autoconf automake bison libffi-devel libtool patch readline-devel sqlite-devel zlib-devel openssl-devel
Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
Package curl-7.61.1-12.amzn2.0.2.x86_64 already installed and latest version
Package gnupg2-2.0.22-5.amzn2.0.4.x86_64 already installed and latest version
Package gcc-7.3.1-12.amzn2.x86_64 already installed and latest version
Package 1:make-3.82-24.amzn2.x86_64 already installed and latest version
Package patch-2.7.1-12.amzn2.0.2.x86_64 already installed and latest version
Package patch-2.7.1-12.amzn2.0.2.x86_64 already installed and latest version
Resolving Dependencies
...
...
[root@ip-192-168-106-237 utils]# gpg2 --keyserver hkp://pool.sks-keyservers.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
gpg: directory `/root/.gnupg' created
gpg: new configuration file `/root/.gnupg/gpg.conf' created
gpg: WARNING: options in `/root/.gnupg/gpg.conf' are not yet active during this run
gpg: keyring `/root/.gnupg/secring.gpg' created
gpg: keyring `/root/.gnupg/pubring.gpg' created
gpg: requesting key D39DC0E3 from hkp server pool.sks-keyservers.net
gpg: requesting key 39499BDB from hkp server pool.sks-keyservers.net
gpg: /root/.gnupg/trustdb.gpg: trustdb created
gpg: key D39DC0E3: public key &quot;Michal Papis (RVM signing) &amp;lt;mpapis@gmail.com&amp;gt;&quot; imported
gpg: key 39499BDB: public key &quot;Piotr Kuczynski &amp;lt;piotr.kuczynski@gmail.com&amp;gt;&quot; imported
gpg: no ultimately trusted keys found
gpg: Total number processed: 2
gpg:               imported: 2  (RSA: 2)
[root@ip-192-168-106-237 utils]# curl -sSL https://get.rvm.io | bash -s stable
Downloading https://github.com/rvm/rvm/archive/1.29.12.tar.gz
Downloading https://github.com/rvm/rvm/releases/download/1.29.12/1.29.12.tar.gz.asc
gpg: Signature made Fri 15 Jan 2021 06:46:22 PM UTC using RSA key ID 39499BDB
gpg: Good signature from &quot;Piotr Kuczynski &amp;lt;piotr.kuczynski@gmail.com&amp;gt;&quot;
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: 7D2B AF1C F37B 13E2 069D  6956 105B D0E7 3949 9BDB
GPG verified '/usr/local/rvm/archives/rvm-1.29.12.tgz'
Creating group 'rvm'
Installing RVM to /usr/local/rvm/
Installation of RVM in /usr/local/rvm/ is almost complete:

  * First you need to add all users that will be using rvm to 'rvm' group,
    and logout - login again, anyone using rvm will be operating with `umask u=rwx,g=rwx,o=rx`.

  * To start using RVM you need to run `source /etc/profile.d/rvm.sh`
    in all your open shell windows, in rare cases you need to reopen all shell windows.
  * Please do NOT forget to add your users to the rvm group.
     The installer no longer auto-adds root or users to the rvm group. Admins must do this.
     Also, please note that group memberships are ONLY evaluated at login time.
     This means that users must log out then back in before group membership takes effect!
Thanks for installing RVM 솋
Please consider donating to our open collective to help us maintain RVM.

몛  Donate: https://opencollective.com/rvm/donate


[root@ip-192-168-106-237 utils]# source /usr/local/rvm/scripts/rvm
[root@ip-192-168-106-237 utils]# rvm install 2.5.1
Searching for binary rubies, this might take some time.
Found remote file https://rvm_io.global.ssl.fastly.net/binaries/amazon/2/x86_64/ruby-2.5.1.tar.bz2
Checking requirements for amazon.
Installing requirements for amazon.
Installing required packages: libyaml-devel....
Requirements installation successful.
ruby-2.5.1 - #configure
ruby-2.5.1 - #download
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 17.5M  100 17.5M    0     0  3830k      0  0:00:04  0:00:04 --:--:-- 3830k
ruby-2.5.1 - #validate archive
ruby-2.5.1 - #extract
ruby-2.5.1 - #validate binary
ruby-2.5.1 - #setup
ruby-2.5.1 - #gemset created /usr/local/rvm/gems/ruby-2.5.1@global
ruby-2.5.1 - #importing gemset /usr/local/rvm/gemsets/global.gems..................................
ruby-2.5.1 - #generating global wrappers........
ruby-2.5.1 - #gemset created /usr/local/rvm/gems/ruby-2.5.1
ruby-2.5.1 - #importing gemsetfile /usr/local/rvm/gemsets/default.gems evaluated to empty gem list
ruby-2.5.1 - #generating default wrappers........
[root@ip-192-168-106-237 utils]# rvm use 2.5.1 --default
Using /usr/local/rvm/gems/ruby-2.5.1
[root@ip-192-168-106-237 utils]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;4. Redis Master Cluster Join (redis-cli --cluster create)&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1620203669377&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-73-84 redis]# redis-cli --cluster create 127.0.0.1:6379 127.0.0.1:6479 127.0.0.1:6579
&amp;gt;&amp;gt;&amp;gt; Performing hash slots allocation on 3 nodes...
Master[0] -&amp;gt; Slots 0 - 5460
Master[1] -&amp;gt; Slots 5461 - 10922
Master[2] -&amp;gt; Slots 10923 - 16383
M: 4d778457522d238b0613b96e656c611b0405f2a3 127.0.0.1:6379
   slots:[0-5460] (5461 slots) master
M: 10022df5d01fddeb7a12e483ae971784bcbd72ba 127.0.0.1:6479
   slots:[5461-10922] (5462 slots) master
M: cde730ed40c71395be543dffd3e893c66357d04e 127.0.0.1:6579
   slots:[10923-16383] (5461 slots) master
Can I set the above configuration? (type 'yes' to accept): yes
&amp;gt;&amp;gt;&amp;gt; Nodes configuration updated
&amp;gt;&amp;gt;&amp;gt; Assign a different config epoch to each node
&amp;gt;&amp;gt;&amp;gt; Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
..
&amp;gt;&amp;gt;&amp;gt; Performing Cluster Check (using node 127.0.0.1:6379)
M: 4d778457522d238b0613b96e656c611b0405f2a3 127.0.0.1:6379
   slots:[0-5460] (5461 slots) master
M: 10022df5d01fddeb7a12e483ae971784bcbd72ba 127.0.0.1:6479
   slots:[5461-10922] (5462 slots) master
M: cde730ed40c71395be543dffd3e893c66357d04e 127.0.0.1:6579
   slots:[10923-16383] (5461 slots) master
[OK] All nodes agree about slots configuration.
&amp;gt;&amp;gt;&amp;gt; Check for open slots...
&amp;gt;&amp;gt;&amp;gt; Check slots coverage...
[OK] All 16384 slots covered.
[root@ip-192-168-73-84 redis]# redis-cli -p 6379
127.0.0.1:6379&amp;gt; flushall
OK
127.0.0.1:6379&amp;gt; exit
[root@ip-192-168-73-84 redis]# redis-cli -c -p 6379
127.0.0.1:6379&amp;gt; cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:3
cluster_size:3
cluster_current_epoch:3
cluster_my_epoch:1
cluster_stats_messages_ping_sent:49
cluster_stats_messages_pong_sent:50
cluster_stats_messages_sent:99
cluster_stats_messages_ping_received:48
cluster_stats_messages_pong_received:49
cluster_stats_messages_meet_received:2
cluster_stats_messages_received:99
127.0.0.1:6379&amp;gt; cluster nodes
10022df5d01fddeb7a12e483ae971784bcbd72ba 127.0.0.1:6479@16479 master - 0 1620169482529 2 connected 5461-10922
4d778457522d238b0613b96e656c611b0405f2a3 127.0.0.1:6379@16379 myself,master - 0 1620169480000 1 connected 0-5460
cde730ed40c71395be543dffd3e893c66357d04e 127.0.0.1:6579@16579 master - 0 1620169481527 3 connected 10923-16383
127.0.0.1:6379&amp;gt; set a a
-&amp;gt; Redirected to slot [15495] located at 127.0.0.1:6579
OK
127.0.0.1:6579&amp;gt; set b b
-&amp;gt; Redirected to slot [3300] located at 127.0.0.1:6379
OK
127.0.0.1:6379&amp;gt; set c c
-&amp;gt; Redirected to slot [7365] located at 127.0.0.1:6479
OK
127.0.0.1:6479&amp;gt; set d d
-&amp;gt; Redirected to slot [11298] located at 127.0.0.1:6579
OK
127.0.0.1:6579&amp;gt; set e e
OK
127.0.0.1:6579&amp;gt; exit
[root@ip-192-168-73-84 redis]#&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Slave Server 구성&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;801&quot; data-origin-height=&quot;640&quot; width=&quot;500&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/U5tYg/btq4gaRSDnc/O1vQM7N1f4kxKFHzQzbyK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/U5tYg/btq4gaRSDnc/O1vQM7N1f4kxKFHzQzbyK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/U5tYg/btq4gaRSDnc/O1vQM7N1f4kxKFHzQzbyK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FU5tYg%2Fbtq4gaRSDnc%2FO1vQM7N1f4kxKFHzQzbyK0%2Fimg.png&quot; data-origin-width=&quot;801&quot; data-origin-height=&quot;640&quot; width=&quot;500&quot; data-ke-mobilestyle=&quot;widthContent&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;/&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; font-family: 'Noto Serif KR';&quot;&gt;Master Node만 구성하여 Redis를 설계할 경우 가용성에 문제가 발생할 수 있다. 데이터 유실 방지 등을 위해 각 Redis Master Node는 Slave Node를 갖도록 구성하는 것이 좋다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;다음은 Redis Slave Node를 구성하는 과정이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;1. Redis Slave Server Create (sh install_server.sh)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;먼저 Cluster에 추가할 서버를 설치한다. (localhost:7379,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;localhost:7479,&amp;nbsp;&lt;span style=&quot;color: #000000;&quot;&gt;localhost:7579&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1620203841510&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-73-84 utils]# sh install_server.sh 
Welcome to the redis service installer
This script will help you easily set up a running redis server

Please select the redis port for this instance: [6379] 7379
Please select the redis config file name [/etc/redis/7379.conf] 
Selected default - /etc/redis/7379.conf
Please select the redis log file name [/var/log/redis_7379.log] 
Selected default - /var/log/redis_7379.log
Please select the data directory for this instance [/var/lib/redis/7379] 
Selected default - /var/lib/redis/7379
Please select the redis executable path [/usr/local/bin/redis-server] 
Selected config:
Port           : 7379
Config file    : /etc/redis/7379.conf
Log file       : /var/log/redis_7379.log
Data dir       : /var/lib/redis/7379
Executable     : /usr/local/bin/redis-server
Cli Executable : /usr/local/bin/redis-cli
Is this ok? Then press ENTER to go on or Ctrl-C to abort.
Copied /tmp/7379.conf =&amp;gt; /etc/init.d/redis_7379
Installing service...
Successfully added to chkconfig!
Successfully added to runlevels 345!
Starting Redis server...
Installation successful!
[root@ip-192-168-73-84 utils]# sh install_server.sh 
Welcome to the redis service installer
This script will help you easily set up a running redis server

Please select the redis port for this instance: [6379] 7479
Please select the redis config file name [/etc/redis/7479.conf] 
Selected default - /etc/redis/7479.conf
Please select the redis log file name [/var/log/redis_7479.log] 
Selected default - /var/log/redis_7479.log
Please select the data directory for this instance [/var/lib/redis/7479] 
Selected default - /var/lib/redis/7479
Please select the redis executable path [/usr/local/bin/redis-server] 
Selected config:
Port           : 7479
Config file    : /etc/redis/7479.conf
Log file       : /var/log/redis_7479.log
Data dir       : /var/lib/redis/7479
Executable     : /usr/local/bin/redis-server
Cli Executable : /usr/local/bin/redis-cli
Is this ok? Then press ENTER to go on or Ctrl-C to abort.
Copied /tmp/7479.conf =&amp;gt; /etc/init.d/redis_7479
Installing service...
Successfully added to chkconfig!
Successfully added to runlevels 345!
Starting Redis server...
Installation successful!
[root@ip-192-168-73-84 utils]# sh install_server.sh 
Welcome to the redis service installer
This script will help you easily set up a running redis server

Please select the redis port for this instance: [6379] 7579
Please select the redis config file name [/etc/redis/7579.conf] 
Selected default - /etc/redis/7579.conf
Please select the redis log file name [/var/log/redis_7579.log] 
Selected default - /var/log/redis_7579.log
Please select the data directory for this instance [/var/lib/redis/7579] 
Selected default - /var/lib/redis/7579
Please select the redis executable path [/usr/local/bin/redis-server] 
Selected config:
Port           : 7579
Config file    : /etc/redis/7579.conf
Log file       : /var/log/redis_7579.log
Data dir       : /var/lib/redis/7579
Executable     : /usr/local/bin/redis-server
Cli Executable : /usr/local/bin/redis-cli
Is this ok? Then press ENTER to go on or Ctrl-C to abort.
Copied /tmp/7579.conf =&amp;gt; /etc/init.d/redis_7579
Installing service...
Successfully added to chkconfig!
Successfully added to runlevels 345!
Starting Redis server...
Installation successful!
[root@ip-192-168-73-84 utils]# ps -ef | grep redis
root      5267     1  0 23:34 ?        00:00:00 /usr/local/bin/redis-server 127.0.0.1:7379
root      5340     1  0 23:34 ?        00:00:00 /usr/local/bin/redis-server 127.0.0.1:7479
root      5414     1  0 23:35 ?        00:00:00 /usr/local/bin/redis-server 127.0.0.1:7579
root      5422  7923  0 23:38 pts/1    00:00:00 grep --color=auto redis
root      8432     1  0 22:47 ?        00:00:02 /usr/local/bin/redis-server 127.0.0.1:6379 [cluster]
root      8449     1  0 22:47 ?        00:00:02 /usr/local/bin/redis-server 127.0.0.1:6479 [cluster]
root      8466     1  0 22:47 ?        00:00:02 /usr/local/bin/redis-server 127.0.0.1:6579 [cluster]
[root@ip-192-168-73-84 utils]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2. Redis Slave Config Modify (vi /etc/redis/7379.conf)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1620203904361&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-73-84 utils]# cd /etc/redis/
[root@ip-192-168-73-84 redis]# ls 7*
7379.conf  7479.conf  7579.conf
[root@ip-192-168-73-84 redis]# vi 7*
3 files to edit
...
...
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 15000
...
appendonly yes
...
...
[root@ip-192-168-73-84 redis]# &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;7379.conf, 7479.conf, 7579.conf 각각 위와 같이 설정파일을 수정하고 저장한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;3. Redis Master Server Restart (service redis_7379 restart)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1620203993501&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-73-84 redis]# service redis_7379 restart
Stopping ...
Redis stopped
Starting Redis server...
[root@ip-192-168-73-84 redis]# service redis_7479 restart
Stopping ...
Redis stopped
Starting Redis server...
[root@ip-192-168-73-84 redis]# service redis_7579 restart
Stopping ...
Redis stopped
Starting Redis server...
[root@ip-192-168-73-84 utils]# ps -ef | grep redis
root      5554     1  0 23:41 ?        00:00:00 /usr/local/bin/redis-server 127.0.0.1:7379 [cluster]
root      5571     1  0 23:42 ?        00:00:00 /usr/local/bin/redis-server 127.0.0.1:7479 [cluster]
root      5589     1  0 23:42 ?        00:00:00 /usr/local/bin/redis-server 127.0.0.1:7579 [cluster]
root      5598  7923  0 23:45 pts/1    00:00:00 grep --color=auto redis
root      8432     1  0 22:47 ?        00:00:03 /usr/local/bin/redis-server 127.0.0.1:6379 [cluster]
root      8449     1  0 22:47 ?        00:00:03 /usr/local/bin/redis-server 127.0.0.1:6479 [cluster]
root      8466     1  0 22:47 ?        00:00:03 /usr/local/bin/redis-server 127.0.0.1:6579 [cluster]
[root@ip-192-168-73-84 utils]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;4. Redis Slave Server Join (redis-cli --cluster add-node --cluster-slave)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1620204048167&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-73-84 utils]# redis-cli --cluster add-node 127.0.0.1:7379 127.0.0.1:6379 --cluster-slave
&amp;gt;&amp;gt;&amp;gt; Adding node 127.0.0.1:7379 to cluster 127.0.0.1:6379
&amp;gt;&amp;gt;&amp;gt; Performing Cluster Check (using node 127.0.0.1:6379)
M: 4d778457522d238b0613b96e656c611b0405f2a3 127.0.0.1:6379
   slots:[0-5460] (5461 slots) master
M: 10022df5d01fddeb7a12e483ae971784bcbd72ba 127.0.0.1:6479
   slots:[5461-10922] (5462 slots) master
M: cde730ed40c71395be543dffd3e893c66357d04e 127.0.0.1:6579
   slots:[10923-16383] (5461 slots) master
[OK] All nodes agree about slots configuration.
&amp;gt;&amp;gt;&amp;gt; Check for open slots...
&amp;gt;&amp;gt;&amp;gt; Check slots coverage...
[OK] All 16384 slots covered.
Automatically selected master 127.0.0.1:6379
&amp;gt;&amp;gt;&amp;gt; Send CLUSTER MEET to node 127.0.0.1:7379 to make it join the cluster.
Waiting for the cluster to join

&amp;gt;&amp;gt;&amp;gt; Configure node as replica of 127.0.0.1:6379.
[OK] New node added correctly.
[root@ip-192-168-73-84 utils]# redis-cli --cluster add-node 127.0.0.1:7479 127.0.0.1:6479 --cluster-slave
&amp;gt;&amp;gt;&amp;gt; Adding node 127.0.0.1:7479 to cluster 127.0.0.1:6479
&amp;gt;&amp;gt;&amp;gt; Performing Cluster Check (using node 127.0.0.1:6479)
M: 10022df5d01fddeb7a12e483ae971784bcbd72ba 127.0.0.1:6479
   slots:[5461-10922] (5462 slots) master
M: 4d778457522d238b0613b96e656c611b0405f2a3 127.0.0.1:6379
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
S: 6d559070ff6dbef46431d985397fbdd2ab0c6842 127.0.0.1:7379
   slots: (0 slots) slave
   replicates 4d778457522d238b0613b96e656c611b0405f2a3
M: cde730ed40c71395be543dffd3e893c66357d04e 127.0.0.1:6579
   slots:[10923-16383] (5461 slots) master
[OK] All nodes agree about slots configuration.
&amp;gt;&amp;gt;&amp;gt; Check for open slots...
&amp;gt;&amp;gt;&amp;gt; Check slots coverage...
[OK] All 16384 slots covered.
Automatically selected master 127.0.0.1:6479
&amp;gt;&amp;gt;&amp;gt; Send CLUSTER MEET to node 127.0.0.1:7479 to make it join the cluster.
Waiting for the cluster to join

&amp;gt;&amp;gt;&amp;gt; Configure node as replica of 127.0.0.1:6479.
[OK] New node added correctly.
[root@ip-192-168-73-84 utils]# redis-cli --cluster add-node 127.0.0.1:7579 127.0.0.1:6579 --cluster-slave
&amp;gt;&amp;gt;&amp;gt; Adding node 127.0.0.1:7579 to cluster 127.0.0.1:6579
&amp;gt;&amp;gt;&amp;gt; Performing Cluster Check (using node 127.0.0.1:6579)
M: cde730ed40c71395be543dffd3e893c66357d04e 127.0.0.1:6579
   slots:[10923-16383] (5461 slots) master
S: d47e315c1bab0bfa9a7b4dc663cea391c1d90def 127.0.0.1:7479
   slots: (0 slots) slave
   replicates 10022df5d01fddeb7a12e483ae971784bcbd72ba
S: 6d559070ff6dbef46431d985397fbdd2ab0c6842 127.0.0.1:7379
   slots: (0 slots) slave
   replicates 4d778457522d238b0613b96e656c611b0405f2a3
M: 4d778457522d238b0613b96e656c611b0405f2a3 127.0.0.1:6379
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
M: 10022df5d01fddeb7a12e483ae971784bcbd72ba 127.0.0.1:6479
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
[OK] All nodes agree about slots configuration.
&amp;gt;&amp;gt;&amp;gt; Check for open slots...
&amp;gt;&amp;gt;&amp;gt; Check slots coverage...
[OK] All 16384 slots covered.
Automatically selected master 127.0.0.1:6579
&amp;gt;&amp;gt;&amp;gt; Send CLUSTER MEET to node 127.0.0.1:7579 to make it join the cluster.
Waiting for the cluster to join

&amp;gt;&amp;gt;&amp;gt; Configure node as replica of 127.0.0.1:6579.
[OK] New node added correctly.
[root@ip-192-168-73-84 utils]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;5. Redis Cluster Info&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1620204070879&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-73-84 utils]# redis-cli --cluster info 127.0.0.1:6379
127.0.0.1:6379 (4d778457...) -&amp;gt; 1 keys | 5461 slots | 1 slaves.
127.0.0.1:6479 (10022df5...) -&amp;gt; 1 keys | 5462 slots | 1 slaves.
127.0.0.1:6579 (cde730ed...) -&amp;gt; 3 keys | 5461 slots | 1 slaves.
[OK] 5 keys in 3 masters.
0.00 keys per slot on average.
[root@ip-192-168-73-84 utils]# redis-cli -p 6379
127.0.0.1:6379&amp;gt; cluster nodes
4d778457522d238b0613b96e656c611b0405f2a3 127.0.0.1:6379@16379 myself,master - 0 1620172101000 1 connected 0-5460
10022df5d01fddeb7a12e483ae971784bcbd72ba 127.0.0.1:6479@16479 master - 0 1620172100000 2 connected 5461-10922
579851e6d3a9a8db16b2fec5ef5418dfd9f7a7f3 127.0.0.1:7579@17579 slave cde730ed40c71395be543dffd3e893c66357d04e 0 1620172100000 3 connected
6d559070ff6dbef46431d985397fbdd2ab0c6842 127.0.0.1:7379@17379 slave 4d778457522d238b0613b96e656c611b0405f2a3 0 1620172099000 1 connected
cde730ed40c71395be543dffd3e893c66357d04e 127.0.0.1:6579@16579 master - 0 1620172100671 3 connected 10923-16383
d47e315c1bab0bfa9a7b4dc663cea391c1d90def 127.0.0.1:7479@17479 slave 10022df5d01fddeb7a12e483ae971784bcbd72ba 0 1620172101673 2 connected
127.0.0.1:6379&amp;gt; exit
[root@ip-192-168-73-84 utils]# redis-cli --cluster check 127.0.0.1:6379
127.0.0.1:6379 (4d778457...) -&amp;gt; 1 keys | 5461 slots | 1 slaves.
127.0.0.1:6479 (10022df5...) -&amp;gt; 1 keys | 5462 slots | 1 slaves.
127.0.0.1:6579 (cde730ed...) -&amp;gt; 3 keys | 5461 slots | 1 slaves.
[OK] 5 keys in 3 masters.
0.00 keys per slot on average.
&amp;gt;&amp;gt;&amp;gt; Performing Cluster Check (using node 127.0.0.1:6379)
M: 4d778457522d238b0613b96e656c611b0405f2a3 127.0.0.1:6379
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
M: 10022df5d01fddeb7a12e483ae971784bcbd72ba 127.0.0.1:6479
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
S: 579851e6d3a9a8db16b2fec5ef5418dfd9f7a7f3 127.0.0.1:7579
   slots: (0 slots) slave
   replicates cde730ed40c71395be543dffd3e893c66357d04e
S: 6d559070ff6dbef46431d985397fbdd2ab0c6842 127.0.0.1:7379
   slots: (0 slots) slave
   replicates 4d778457522d238b0613b96e656c611b0405f2a3
M: cde730ed40c71395be543dffd3e893c66357d04e 127.0.0.1:6579
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
S: d47e315c1bab0bfa9a7b4dc663cea391c1d90def 127.0.0.1:7479
   slots: (0 slots) slave
   replicates 10022df5d01fddeb7a12e483ae971784bcbd72ba
[OK] All nodes agree about slots configuration.
&amp;gt;&amp;gt;&amp;gt; Check for open slots...
&amp;gt;&amp;gt;&amp;gt; Check slots coverage...
[OK] All 16384 slots covered.
[root@ip-192-168-73-84 utils]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Master &amp;amp; Slave Node 구성이 완료되면 위와 같이 확인이 가능하다.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Redis 구성 및 동작 방식 확인&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;총 6개의 Redis Server가 구성되어 있으며, 3개의 Master와 3개의 Slave로 구성된다.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1620206909577&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-73-84 6379]# redis-cli -c -p 6379
127.0.0.1:6379&amp;gt; set a a
-&amp;gt; Redirected to slot [15495] located at 127.0.0.1:6579
OK
127.0.0.1:6579&amp;gt; set b b
-&amp;gt; Redirected to slot [3300] located at 127.0.0.1:6379
OK
127.0.0.1:6379&amp;gt; set c c
-&amp;gt; Redirected to slot [7365] located at 127.0.0.1:6479
OK
127.0.0.1:6479&amp;gt; set d d
-&amp;gt; Redirected to slot [11298] located at 127.0.0.1:6579
OK
127.0.0.1:6579&amp;gt; set e e
OK
127.0.0.1:6579&amp;gt; set f f
-&amp;gt; Redirected to slot [3168] located at 127.0.0.1:6379
OK
127.0.0.1:6379&amp;gt; cluster nodes
4d778457522d238b0613b96e656c611b0405f2a3 127.0.0.1:6379@16379 myself,master - 0 1620206875000 1 connected 0-5460
10022df5d01fddeb7a12e483ae971784bcbd72ba 127.0.0.1:6479@16479 master - 0 1620206876000 2 connected 5461-10922
579851e6d3a9a8db16b2fec5ef5418dfd9f7a7f3 127.0.0.1:7579@17579 slave cde730ed40c71395be543dffd3e893c66357d04e 0 1620206877407 3 connected
6d559070ff6dbef46431d985397fbdd2ab0c6842 127.0.0.1:7379@17379 slave 4d778457522d238b0613b96e656c611b0405f2a3 0 1620206875401 1 connected
cde730ed40c71395be543dffd3e893c66357d04e 127.0.0.1:6579@16579 master - 0 1620206876405 3 connected 10923-16383
d47e315c1bab0bfa9a7b4dc663cea391c1d90def 127.0.0.1:7479@17479 slave 10022df5d01fddeb7a12e483ae971784bcbd72ba 0 1620206875000 2 connected
127.0.0.1:6379&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;위와 같이 데이터는 Master Node 3대에만 저장되는 것을 확인할 수 있다. &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1621379274250&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-106-237 utils]# redis-cli -c -p 6379
127.0.0.1:6379&amp;gt; set a a
-&amp;gt; Redirected to slot [15495] located at 127.0.0.1:6579
OK
127.0.0.1:6579&amp;gt; set b b
-&amp;gt; Redirected to slot [3300] located at 127.0.0.1:6379
OK
127.0.0.1:6379&amp;gt; set c c
-&amp;gt; Redirected to slot [7365] located at 127.0.0.1:6479
OK
127.0.0.1:6479&amp;gt; set e e 
-&amp;gt; Redirected to slot [15363] located at 127.0.0.1:6579
OK
127.0.0.1:6579&amp;gt; set f f
-&amp;gt; Redirected to slot [3168] located at 127.0.0.1:6379
OK
127.0.0.1:6379&amp;gt; set g g
-&amp;gt; Redirected to slot [7233] located at 127.0.0.1:6479
OK
127.0.0.1:6479&amp;gt; keys *
1) &quot;c&quot;
2) &quot;g&quot;
127.0.0.1:6479&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;특히 Cluster에 포함되어 있는 Master Node 들에 각자 저장된 key와 data는 각 노드에 저장된 값만 확인이 가능하여 반드시 Slave를 구성하여 Master 데이터를 백업할 수 있도록 구성해야 한다. 위와 같이 6479 node에 저장된 c와 g의 key만 조회되는 것을 확인할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;여기서 Master Node 중 한대를 다운시켜보도록 하자.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1620207069657&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-73-84 6379]# service redis_6379 stop
Stopping ...
Redis stopped
[root@ip-192-168-73-84 6379]# redis-cli -c -p 6479
127.0.0.1:6479&amp;gt; cluster nodes
d47e315c1bab0bfa9a7b4dc663cea391c1d90def 127.0.0.1:7479@17479 slave 10022df5d01fddeb7a12e483ae971784bcbd72ba 0 1620206975167 2 connected
6d559070ff6dbef46431d985397fbdd2ab0c6842 127.0.0.1:7379@17379 slave 4d778457522d238b0613b96e656c611b0405f2a3 0 1620206976171 1 connected
cde730ed40c71395be543dffd3e893c66357d04e 127.0.0.1:6579@16579 master - 0 1620206973000 3 connected 10923-16383
579851e6d3a9a8db16b2fec5ef5418dfd9f7a7f3 127.0.0.1:7579@17579 slave cde730ed40c71395be543dffd3e893c66357d04e 0 1620206974163 3 connected
4d778457522d238b0613b96e656c611b0405f2a3 127.0.0.1:6379@16379 master - 1620206963732 1620206962130 1 disconnected 0-5460
10022df5d01fddeb7a12e483ae971784bcbd72ba 127.0.0.1:6479@16479 myself,master - 0 1620206974000 2 connected 5461-10922
127.0.0.1:6479&amp;gt; set a a
-&amp;gt; Redirected to slot [15495] located at 127.0.0.1:6579
OK
127.0.0.1:6579&amp;gt; set b b
-&amp;gt; Redirected to slot [3300] located at 127.0.0.1:7379
OK
127.0.0.1:7379&amp;gt; set c c
-&amp;gt; Redirected to slot [7365] located at 127.0.0.1:6479
OK
127.0.0.1:6479&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;위와 같이 Master Node의 Slave가 존재하기 때문에 기존 6379에 저장되어 있던 b라는 key는 7379에서 관리되는 것을 확인할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;물론 7379 서버까지 다운된 경우에는 데이터를 조회할 수 없다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1620207235776&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-73-84 6379]# service redis_7379 stop
Stopping ...
Redis stopped
[root@ip-192-168-73-84 6379]# redis-cli -c -p 6479
127.0.0.1:6479&amp;gt; get a
-&amp;gt; Redirected to slot [15495] located at 127.0.0.1:6579
&quot;a&quot;
127.0.0.1:6579&amp;gt; get b
-&amp;gt; Redirected to slot [3300] located at 127.0.0.1:7379
Could not connect to Redis at 127.0.0.1:7379: Connection refused
Could not connect to Redis at 127.0.0.1:7379: Connection refused
not connected&amp;gt; &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;물론 서버 장애가 해결되어 기동이 완료될 경우 해당 데이터는 복구된다. (Redis 저장 방식에 따라 유실될 수도 있다. RDB vs AOF)&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;마지막으로 장애 복구 과정에 대해 살펴보자.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1620207802185&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-73-84 6379]# service redis_7379 start
Starting Redis server...
[root@ip-192-168-73-84 6379]# redis-cli -c -p 6479
127.0.0.1:6479&amp;gt; cluster nodes
d47e315c1bab0bfa9a7b4dc663cea391c1d90def 127.0.0.1:7479@17479 slave 10022df5d01fddeb7a12e483ae971784bcbd72ba 0 1620207331000 2 connected
6d559070ff6dbef46431d985397fbdd2ab0c6842 127.0.0.1:7379@17379 master - 0 1620207331352 4 connected 0-5460
cde730ed40c71395be543dffd3e893c66357d04e 127.0.0.1:6579@16579 master - 0 1620207332356 3 connected 10923-16383
579851e6d3a9a8db16b2fec5ef5418dfd9f7a7f3 127.0.0.1:7579@17579 slave cde730ed40c71395be543dffd3e893c66357d04e 0 1620207329347 3 connected
4d778457522d238b0613b96e656c611b0405f2a3 127.0.0.1:6379@16379 master,fail - 1620206963732 1620206962130 1 disconnected
10022df5d01fddeb7a12e483ae971784bcbd72ba 127.0.0.1:6479@16479 myself,master - 0 1620207327000 2 connected 5461-10922
127.0.0.1:6479&amp;gt; &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;먼저 Slave Server 였던 7379 server를 기동한 후 cluster 정보를 확인해 보면 다음과 같다. 6379 서버는 master, fail 상태이며, 7379 server가 master server로 승격되어 있는 것을 확인할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1620207954088&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-73-84 6379]# redis-cli -c -p 6379
127.0.0.1:6379&amp;gt; cluster nodes
d47e315c1bab0bfa9a7b4dc663cea391c1d90def 127.0.0.1:7479@17479 slave 10022df5d01fddeb7a12e483ae971784bcbd72ba 0 1620207895000 2 connected
cde730ed40c71395be543dffd3e893c66357d04e 127.0.0.1:6579@16579 master - 0 1620207895588 3 connected 10923-16383
579851e6d3a9a8db16b2fec5ef5418dfd9f7a7f3 127.0.0.1:7579@17579 slave cde730ed40c71395be543dffd3e893c66357d04e 0 1620207894000 3 connected
6d559070ff6dbef46431d985397fbdd2ab0c6842 127.0.0.1:7379@17379 master - 0 1620207892000 4 connected 0-5460
4d778457522d238b0613b96e656c611b0405f2a3 127.0.0.1:6379@16379 myself,slave 6d559070ff6dbef46431d985397fbdd2ab0c6842 0 1620207892000 1 connected
10022df5d01fddeb7a12e483ae971784bcbd72ba 127.0.0.1:6479@16479 master - 0 1620207893583 2 connected 5461-10922
127.0.0.1:6379&amp;gt; set a a
-&amp;gt; Redirected to slot [15495] located at 127.0.0.1:6579
OK
127.0.0.1:6579&amp;gt; set b b
-&amp;gt; Redirected to slot [3300] located at 127.0.0.1:7379
OK
127.0.0.1:7379&amp;gt; set c c
-&amp;gt; Redirected to slot [7365] located at 127.0.0.1:6479
OK
127.0.0.1:6479&amp;gt; &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;다음으로 Master Server 였던 6379 server를 기동한 후 cluster 정보를 확인해 보면 다음과 같다. 6379 서버는 master에서 slave 서버로 변경되었으며, 7379 server가 master 서버의 상태를 유지하는 것을 알 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;803&quot; data-origin-height=&quot;649&quot; width=&quot;500&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/47nR9/btq4bCW6z5w/rgvB2GyckL8LCjXWtDHpV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/47nR9/btq4bCW6z5w/rgvB2GyckL8LCjXWtDHpV0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/47nR9/btq4bCW6z5w/rgvB2GyckL8LCjXWtDHpV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F47nR9%2Fbtq4bCW6z5w%2FrgvB2GyckL8LCjXWtDHpV0%2Fimg.png&quot; data-origin-width=&quot;803&quot; data-origin-height=&quot;649&quot; width=&quot;500&quot; data-ke-mobilestyle=&quot;widthContent&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;/&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: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;# 참고&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Redis 환경 정보&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;a. 기동/종료 : /etc/init.d/redis_6379 활용 (service redis_6379 stop / start / restart)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;b. 설정파일 : /etc/redis/6379.conf&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;c. nodes.conf : /var/lib/redis/6379/nodes.conf&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;d. 로그파일 : /var/lib/redis_6379.log&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>⑦ Open Source Software</category>
      <category>cluster info</category>
      <category>cluster node</category>
      <category>redis cluster</category>
      <category>Redis Master</category>
      <category>Redis Slave</category>
      <category>redis 장애 복구</category>
      <category>redis-cli</category>
      <category>레디스</category>
      <category>레디스 클러스터</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/696</guid>
      <comments>https://waspro.tistory.com/696#entry696comment</comments>
      <pubDate>Wed, 5 May 2021 19:00:39 +0900</pubDate>
    </item>
    <item>
      <title>성공적인 DevSecOps 구현하기</title>
      <link>https://waspro.tistory.com/693</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;서론&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;DevSecOps란 개발, 보안, 운영이라는 세가지 중요한 측면을 원활하게 수행하기 위한 방식 또는 조직을 의미한다. DevOps에서 확장된 개념이라 볼 수 있다. 이는 전체 어플리케이션 라이프 사이클을 공동 책임으로 관리한다는 조직관리 관점에서 확장된 것이지만, 사실 확장이라는 개념에 어울리지 않게, 그간 우리는 보안이라는 요소를 기술의 Sub System 정도로 취급해 왔던 것이 사실이다. 특히 컨테이너 기술에 대한 이해가 높지 않은 상황에서 보안을 논의하기 보다는 기술의 완성도를 높이는데에만 집중해 오지 않았나 싶다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;최근 프로젝트에서 DevSecOps가 논의된 적이 있다. 당시 마이크로서비스를 설계하는 아키텍처 입장에서 나부터 보안에 대한 고려가 깊지 않았다는 생각을 하게 됐다. 이제는 그 생각의 전환이 필요한 시점이 아닌가 싶다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;보안이라는 진입점이 때로는 굉장히 높아 보인다는 문제가 있지만 컨테이너 보안은 더 이상 괄시하고 넘어갈 수 없는 상황이 되었다. 보안 침해 사고로부터 안전한 소프트웨어와 어플리케이션을 만들기 위해 많은 기업들이 여전히 고민하고 노력해 오고 있지만, 끊임없이 보안 사고는 발생하고 있으며, 그 파장은 엄청나다는 것을 알고 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;어플리케이션의 라이프사이클을 공통 책임으로 함께 관리해 나가기 위해서는 조직, 문화, 프로세스에 대한 변화와 자동화 체계 그리고 이를 뒷받침하는 플랫폼 설계에 대한 또 다른 사고방식으로 접근해야 할 필요가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Gartner 정의&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;아래 이미지는 Gartner 리서치 기관에서 정의한 DevSecOps의 연관 관계도이다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이를 먼저 번역해 보면서 DevSecOps에 대해 고찰을 진행해 보자.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;725&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RMsnK/btq0pwly2H4/E01FzZskCPUDxOjrjzsIY0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RMsnK/btq0pwly2H4/E01FzZskCPUDxOjrjzsIY0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RMsnK/btq0pwly2H4/E01FzZskCPUDxOjrjzsIY0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRMsnK%2Fbtq0pwly2H4%2FE01FzZskCPUDxOjrjzsIY0%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;725&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;725&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: 'Noto Serif KR'; color: #000000;&quot;&gt;1) Plan : 보안을 담당하는 부서, DevSec Metrics 관리 방안, 보안 위협 모델링 수립, 보안 관련 플랫폼 교육 등의 보안 관련 문제를 해결해 나가기 위한 계획 수립&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;2) Create :&lt;/span&gt; 통합 개발환경에 보안 관련 요소 적용&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;3) Verify :&lt;/span&gt; SAST(Static Application Security Testing - 정적 어플리케이션 보안 테스트)/DAST(Dynamic Application Security Testing - 동적 어플리케이션 보안 테스트)/IAST(Interactive Application Security Testing - 상호작용 어플리케이션 보안테스트)/SCA(Software Composition Analysis - 원점 분석 / 소프트웨어 구성 분석)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;4) Preprod :&lt;/span&gt; Chaos Monkey(카오스 몽키 테스트 - 발생 가능한 장애를 발생 시켜 정상 상태와 비교하는 테스트), Input Fuzzing(퍼징 테스트 - 예상치 않은 또는 무작위 데이터를 입력하여 결과를 확인하는 테스트), Integration Test(통합테스트 - 단위 테스트 결과를 기반으로 모듈 단위를 묶어 테스트를 진행하는 통합테스트) 또는&amp;nbsp;서비스를 가속화하고, 실행 중인 컨테이너에 자동화된 penetration bots을 배치하여 실제 어떻게 동작되는지 확인하는 과정을 거침&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;5) Release : 적용되는 소프트웨어 또는 어플리케이션에 대한 서명 진행&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;6) Prevent : 서명에 대한 확인, Checksum 등 무결성 검사, 심층 방어 조치 수립&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;7) Detect : RASP(Runtime Application Self-Protection - 런타임 어플리케이션 자가 보안, 실행중인 소프트웨어 내부의 정보를 활용하여 보안 공격을 탐지하고 차단하는 기술), UEBA(User Behavior Analytics - 사용자 행동 분석, 내부 위협, 표적 공격 및 금융 사기 탐지)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;8) Respond : 보안 요건 재검토 및 조정, RASP/WAF(Web application Firewall) 등 런타임 환경에서의 보안 위협 차단&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;9) Predict : IoC(Indicator of Compromise - 네트워크 또는 운영체제에서 관찰된 침입 흔적), TI(Threat Intelligence - 사이버 공간에서 유해한 이벤트를 완화하는데 도움이 되는 위협 및 위협 행위자에 대한 정보), STIX(Structured Thread Information Expression - 사이버 위협 정보 표현 규격), TAXII(Trusted Automated Exchange of Intelligence Information - 사이버위협 정보 전송 규격) 등 예상 가능한 위협 정보 등을 예측&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;10) Adapt : 보안을 담당하는 부서, 보안 위협에 대해 대응&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;DevSecOps 적용 범위&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;DevOps 과정에 적용되는 요건은 이렇게 다양하게 적용할 수 있다. 물론 위와 같이 굉장히 복잡해 보이는 보안 요소 특히 하나하나는 각 분야의 전문가의 도움 없이는 사실 적용 자체가 어려운 요건들이 많이 있다. 어떤 요소는 국가 단위, 어떤 요소는 대기업 수준의 보안 침해 대응팀에서나 다룰 수 있는 전문 분야 요건들이 많기에 우리는 이 모든 부분을 반영할 수는 없을 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;따라서 우리가 초점을 맞춰야 하는 부분은 바로 &lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #ee2323;&quot;&gt;2) Create, 3) Verify, 4) Preprod&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이다. 통합 개발환경에 적용한다는 점은 코드 기반 보안성 검토가 이뤄지는 코드를 개발하고, 정적/동적/상호/원점 분석이 가능한 검증도구를 CI/CD 파이프라인에 적용하며, 침해를 가정한 대응 테스트를 진행하는 것이 바로 DevSecOps 조직의 Srcutiry가 담당하는 역할이라 정의할 수 있을 것이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;마이크로서비스를 구현하는 조직에 보안 전문가가 배치되는 것은 굉장히 중요한 일이다. 하지만, 보안 전문가는 급격한 컨테이너 기술의 성장과 맞물려 그 수요가 부족하여 모든 조직에 배치되는 것은 굉장히 어려운 일이다. 특히 보안 전문가 양성까지의 시간이 많이 걸리고, 새로운 보안 침해 사고들이 지속적으로 발생하는 현 시점에 보안 전문 회사가 아닌 이상 이러한 전문가가 모든 조직에 포함되기에는 사실상 불가능한 상황이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이는 근본적으로 해소가 불가능한 일이며, 따라서 DevSecOps 조직에서는 보안 침해로부터 보안 위협을 해결해 나가는 것 보다는 보안 위협이 발생했을때 얼마나 빠르게 보안 전문가에게 이를 전달해 줄 수 있는지를 고려해야 할 것이다. 보안 전문가는 때로는 사람이 될수 있겠지만, 대부분 보안을 해결해 주는 플랫폼이 될 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;파이프라이닝&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;지금부터는 이를 기준으로 효과적인 DevSecOps를 적용하는 방법에 대해 알아보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;DevSecOps를 구현함에 있어 가장 중요한 요소는 바로 &lt;span style=&quot;color: #ee2323;&quot;&gt;자동화&lt;/span&gt;이다. 보안에 대한 프로세스 역시 DevOps를 수행하는 조직과 마찬가지로 하나의 파이프라인 안에서 수행하도록 구현하는 것이 바람직하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&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;1515&quot; data-origin-height=&quot;134&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dhQIZk/btrGnir4t96/HdkdlGCKO5Uh2X6Xl5K0Yk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dhQIZk/btrGnir4t96/HdkdlGCKO5Uh2X6Xl5K0Yk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dhQIZk/btrGnir4t96/HdkdlGCKO5Uh2X6Xl5K0Yk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdhQIZk%2FbtrGnir4t96%2FHdkdlGCKO5Uh2X6Xl5K0Yk%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;1515&quot; height=&quot;134&quot; data-origin-width=&quot;1515&quot; data-origin-height=&quot;134&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: 'Noto Serif KR'; color: #000000;&quot;&gt;각 영역은 보안을 위한 주요 Stage를 포함한다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;1) 설계&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&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;764&quot; data-origin-height=&quot;295&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c7ueoW/btrGnW99Mzi/kd0PpyeHPSOyrkKiatKnjk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c7ueoW/btrGnW99Mzi/kd0PpyeHPSOyrkKiatKnjk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c7ueoW/btrGnW99Mzi/kd0PpyeHPSOyrkKiatKnjk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc7ueoW%2FbtrGnW99Mzi%2Fkd0PpyeHPSOyrkKiatKnjk%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;764&quot; height=&quot;295&quot; data-origin-width=&quot;764&quot; data-origin-height=&quot;295&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: 'Noto Serif KR'; color: #000000;&quot;&gt;a. 공격 루트 최소화&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;실행 중인 코드양 최소화&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;신뢰할 수 없는 사용자가 접근할 수 있는 진입점 최소화 (ex - bastion 서버를 통해 접근하도록 하고, 모든 서버는 Private Subnet에 위치하여 접근을 차단)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;상대적으로 소수의 사용자가 요청한 서비스 제거&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;b. 권한 설계&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;IAM(ID and Access Management)은 개별 사용자, 그룹 또는 시스템 컴퓨팅 리소스에 대한 액세스를 허용하거나 제한하는 프로세스이다. &lt;span style=&quot;color: #000000;&quot;&gt;보안으로부터의 침해 사고를 예방하기 위해 &lt;/span&gt;사용자, 그룹 또는 리소스에 따라&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;세분화된 IAM Role을 부여하도록 한다.&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;c. 네트워크 설계&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;VM은 &lt;span style=&quot;color: #000000;&quot;&gt;Private Subnet 내 &lt;/span&gt;Private IP만 사용하여 배포&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Cloud NAT로 안전한 아웃바운드 인터넷 연결 구성&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Public LoadBalancer를 구성하고, 웹 애플리케이션 방화벽(WAF)와 DDoS 완화 서비스(Cloud Armor) 활성화&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;서버, 리소스 및 VPC에 대한 세분화된 네트워킹 정책 적용&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;필요한 IP 대역 및 포트만 오픈&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;d. 시스템 설계&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;근본적으로 서버 보안을 강화하는 것은 가장 기초가 되는 보안 침해를 방지하는 방안이다. &lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Kubernetes와 같은 컨테이너를 기반으로 서비스를 하더라도 Kubernetes가 설치되는 인프라 보안도 함께 보장되어야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;e. 쿠버네티스 설계&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;서비스 기반 Kubernetes 클러스터를 사용 중이고 Worker Node만 관리한다고 가정한다. 마스터 노드를 관리하는 경우 Kube-bench를 사용하여 관리한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;또한, Worker Node 이미지 보안에 대해 고려해야 한다.&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: 'Noto Serif KR'; color: #000000;&quot;&gt;Secrets - 암호화되어 있고 RBAC가 적용되어 있는지 확인&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;네트워크 정책 - Zero Trust(기본적으로 모든 것을 차단)로 시작하고 필요한 경우에만 허용 규칙 추가. 가장 좋은 방법은 Service Mesh(Linkerd 또는 Istio와 같은)를 적용하여 관리하는 방법. &lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;서비스 메시를 구현하지 않을 경우 강력한 네트워크 정책 관리 및 액세스 제어 목록(ACL)을 지원하기 위한 오버레이 네트워크 사용&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;OPA(Gatekeeper), Kyverno 등을 사용하여 각 네임스페이스에는 서비스 메시 태그 정책을 적용함&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;파이프라인 내에 포함되어야할 Stage는 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;▶ 오픈소스 라이선스 관리 및 보안 취약점 점검 (Blackduck, Protex 등)&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;▶&lt;span&gt; 웹 취약점 분석 (AppScan, Arachni 등)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;▶&lt;/span&gt; 소스코드 정적분석 (SonarQube, Sparrow 등)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;▶&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt; 소스코드 종속성 검사 (Maven, Python Plug-In 등)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;▶&lt;/span&gt; 이미지 취약점분석 수행 (Anchore, Clair 등)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이중 이미지 취약점의 경우 아직 정형화 되어 있는 검증 방식들이 없어 아래와 같은 사항에는 반드시 유의하여 작성하는 것을 권고한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;rarr;&lt;/span&gt;&amp;nbsp;빌드 시 확인할 도커 Base 이미지의 Whitelist를 생성한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;rarr;&lt;/span&gt;&amp;nbsp;암호화된 방식으로 서명된 Base 이미지를 가져오는지 확인한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;rarr;&lt;/span&gt;&amp;nbsp;나중에 확인할 수 있도록 푸시된 이미지의 메타데이터를 암호화된 방식으로 서명한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;rarr;&lt;/span&gt;&amp;nbsp;컨테이너에서는 패키지 관리자의 보안 기능을 사용하여 패키지의 무결성을 확인하는 Linux 배포만 적용한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;rarr;&lt;/span&gt;&amp;nbsp;3rd Party Dependency을 수동으로 가져올 경우 HTTPS만 허용하고, 반드시 Checksum의 유효성을 확인한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;rarr;&lt;/span&gt;&amp;nbsp;HostPath 볼륨은 가능한 접근을 차단한다. 부득이하게 HostPath 볼륨을 PV로 연결해야 할 경우에는 /dev와 같은 중요한 Path에는 접근하지 못하도록 접근을 제한해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;사실 파이프라인에 위에 제시한 5가지 +@가 모두 포함된다면 배포 속도는 굉장히 느려지게 될 것이다. Security의 확보는 굉장히 중요하지만 가능한 배포 품질을 저하 시키는 정도의 시간 낭비는 발생하지 않아야 한다. 따라서 우리는 &lt;span style=&quot;color: #ee2323;&quot;&gt;1회성으로 적용해야 하는 대상&lt;span style=&quot;color: #000000;&quot;&gt;과&lt;/span&gt; 매번 배포시 마다 검증해야하는 대상&lt;span style=&quot;color: #000000;&quot;&gt;을 정의&lt;/span&gt;&lt;/span&gt;해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;예를 들어 오픈소스 보안 취약점 점검의 경우 별도의 Stage로 관리되는 것이 효율적이다. 오픈소스는 새로운 버전으로 업그레이드하거나, 새로 다운로드 할 경우에만 해당 Stage를 통해 검토되도록 구성하고, 검토가 완료된 버전을 Local Repository에 저장 후 사용하는 것이 가장 적합한 방식이 될 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;소스코드나 이미지의 경우 항상 재 검증이 필요하다. 소스코드의 변경은 결국 이미지의 변경을 의미하기 때문에 취약점 점검을 통해 문제를 검토해야 할 사항을 도출해 낼 수 있도록 Stage 작성해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;여기서는 정적분석과 이미지에 대한 내용만 논의했지만, 사실 보안에서 다뤄야 하는 분야는 훨씬 넓다. 동적분석, 상호연계분석 등은 물론 보안을 침해할 수 있는 환경을 구성하고 테스트하는 부분 이를 해결하고 적용하는 부분까지 모두 Security가 담당해야 할 분야라 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;결론&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;다음은 digital.ai에서 만든 DevOps 주기율표이다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1656&quot; data-origin-height=&quot;939&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qLayC/btq0zc8iPUx/iqFbVn4Iryp3tUVYN50hnK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qLayC/btq0zc8iPUx/iqFbVn4Iryp3tUVYN50hnK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qLayC/btq0zc8iPUx/iqFbVn4Iryp3tUVYN50hnK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqLayC%2Fbtq0zc8iPUx%2FiqFbVn4Iryp3tUVYN50hnK%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;1656&quot; height=&quot;939&quot; data-origin-width=&quot;1656&quot; data-origin-height=&quot;939&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;(# 위 이미지는 &lt;a href=&quot;https://digital.ai/periodic-table-of-devops-tools&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;digital.ai/periodic-table-of-devops-tools&lt;/a&gt;에서 확인할 수 있다.)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;DevOps에 대해서는 그간 꾸준히 논의되어 왔고, 이를 적용하기 위해 많은 노력을 기울이고 있는 것이 사실이다. DevOps는 조직과 프로세스의 변화를 요구하는 동시 빠른 개발, 빠른 배포가 가능한 Agile 방법론을 적용하기 위한 필수적인 요건이기 때문이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이제는 보안이라는 요소가 포함되어야 한다. DevSecOps의 시작은 간단히 출발하는 것이 좋다. 소스코드 정적분석, 이미지 취약점 분석을 시작으로 앞서 논의된 수준으로 확대해 나가는 것이 좋을 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;개인적인 의견이지만, Dev : Sec : Ops의 구성 비율은 초기 80 : 10 : 10 수준으로 진행하고, 이후 운영, 테스트, 적용 단계까지 보안 분야를 확대 적용할 경우 70 : 20 : 10 비율로 확대 구성하는 것이 좋아보인다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;지금까지 다룬 내용은 간단해 보이지만 사실 구현과정은 간단하지 않다. 다만 이와 같은 환경을 구성하고 단순화해 나가는 과정을 통해 도출되는 여러가지 보안 요건들을 적용하다보면 그 사례는 분명 하나의 PB 사례가 될 수 있지 않을까 싶다. 사실 DevSecOps를 반드시 적용해야 하는 이유는 단순히 운영조직에서 감당해야 할 운영 상 발생 가능한 보안 위협만의 일은 아니다. 개발조직 역시 심각한 보안 취약점으로 인해 수개월의 프로젝트 동안 개발한 모듈을 전체적으로 재개발해야 하는 일도 발생할 수 있다. 따라서 Sec 영역은 Dev와 Ops 모든 조직에 밀접하게 연관되어 있다는 점을 반드시 기억해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;개발과 운영 조직이 함께 DevOps의 안정성과 품질을 책임지는 것처럼 DevSecOps는 보안을 포함하여 완전한 팀을 구성할 수 있게 한다. 훌륭한 DevSecOps 체계가 구성되면 전체 어플리케이션을 배포하고 제공하는 프로세스의 효율성은 점진적으로 개선되고 안전한 서비스가 가능해 질 것이다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>③ 클라우드/ⓜ MSA</category>
      <category>CI/CD</category>
      <category>DevOps</category>
      <category>DevSecOps</category>
      <category>컨테이너 보안</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/693</guid>
      <comments>https://waspro.tistory.com/693#entry693comment</comments>
      <pubDate>Fri, 19 Mar 2021 00:17:48 +0900</pubDate>
    </item>
    <item>
      <title>컨테이너 이미지 생성시 고려사항</title>
      <link>https://waspro.tistory.com/692</link>
      <description>&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;서론&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;마이크로서비스 환경에서 서비스를 잘 모델링하는 것 만큼 중요한 것이 바로 컨테이너 이미지를 설계하는 것이다. 어플리케이션을 잘 설계하여 소스도 경량화 되고, 확장성을 확보했다고 생각할 수 있지만, 사실은 어플리케이션을 감싸고 있는 컨테이너 이미지가 최적화되어 있지 않을 경우 어플리케이션의 경량화는 의미가 퇴색될 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;174&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cH5Hdg/btqZ3f4LdTu/C2HoN47WUZBf5ApsV6Bp4K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cH5Hdg/btqZ3f4LdTu/C2HoN47WUZBf5ApsV6Bp4K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cH5Hdg/btqZ3f4LdTu/C2HoN47WUZBf5ApsV6Bp4K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcH5Hdg%2FbtqZ3f4LdTu%2FC2HoN47WUZBf5ApsV6Bp4K%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;512&quot; height=&quot;174&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;174&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;지금부터 살펴볼 내용은 컨테이너 이미지를 생성할때 고려해야 할 사항에 대해 본인의 노하우를 섞어 알아보도록 하자.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;첫번째, 경량화&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;역시나 첫번째로 고려해야 할 부분은 바로 컨테이너 이미지의 경량화이다. 이미 수도 없이 강조했지만, 컨테이너 이미지는 작으면 작을 수록 좋다. Scalability를 강조하기 위해서는 무엇보다 가벼운 이미지가 중요하며 경량화를 위한 노력을 무엇보다 지속해 나가야 한다. &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그 대상은 이미지를 구성하는 모든 구성 요소가 될 것이다.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;1) 샌드박스 컨테이너 만들기&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;IT 분야에서 샌드박스라는 의미는 일반적으로 실험적으로 활용하는 영역을 의미한다. 놀이터의 모래밭과 같이 성을 쌓고 무너뜨리고 하면서 원하는 놀이를 하듯 본인의 환경에는 영향을 주지 않고 샌드박스 환경을 구성하여 테스트하기 어려운 환경을 구성하여 대체하는 영역이 바로 샌드박스라고 볼 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;예를 들어 디스크 부족 환경을 테스트 하고 싶은데 내 PC에는 디스크의 여유가 있어 더미 파일을 무작위로 만들어 디스크를 채운다면? 그 자체도 정말 무의미한 작업이지만, 이로 인해 시스템 자체의 장애를 발생 시켜 원하는 검증 자체를 수행하지 못하는 경우가 발생할 수 있다. 이를 대신 테스트 하기 위한 환경. 기존에는 VM이 이러한 환경의 대체가 되었었지만, 최근에는 Container가 바로 샌드박스가 되고 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;샌드박스 환경의 필수 조건은 바로 빈 깡통에서 시작할 수 있어야 한다는 점이다. 이는 경량화 컨테이너를 만들어 가는 과정과 비슷하여 이를 샌드박스 컨테이너 만들기라고 정의했다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;경량화 컨테이너를 만들기 위해서는 이미지의 기반이되는 Base Image의 선택이 중요하다. 대표적인 경량화 이미지로 Alpine과 Debian이 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;반드시 이러한 이미지를 사용해야 하는 것은 아니지만, 가능한 Minimal 이미지를 기반으로 Base Image를 생성하는 것이 컨테이너 사이즈를 줄일 수 있는 방법이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;다음을 살펴보자.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;node:onbuild 이미지는 Dockerfile을 아래와 같이 매우 간단하게 생성할 수 있고, 이미 컴파일과 실행에 필요한 라이브러리를 패키징하고 있어 손쉽게 컨테이너를 구성할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1646230390780&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FROM node:onbuild
EXPOSE 8080&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;node:alpine 이미지는 아래와 같이 Dockerfile을 직접 작성해야 하며, 이외 필요한 라이브러리들도 직접 구성해야 한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1646230651819&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FROM node:alpine
WORKDIR /app
COPY package.json /app/package.json
RUN npm install --production
COPY server.js /app/server.js
EXPOSE 8080
CMD npm start&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;컴파일한 이미지의 사이즈는 아래와 같다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1646230689539&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-78-195 docker]# docker images
nodealpine                            latest                      8a9ab21306d4   5 seconds ago        173MB
nodeonbuild                           latest                      a0cc599f0c87   About a minute ago   682MB
node                                  alpine                      eb56d56623e5   6 days ago           168MB
node                                  onbuild                     ed2506e2e522   3 years ago          673MB
[root@ip-192-168-78-195 docker]#&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;위와 같이 Alpine 이미지로 빌드한 이미지의 사이즈는 173MB로 Onbuild 이미지로 빌드한 이미지는 682MB이다. 이미지의 사이즈를 줄이면 구축 시간과 이미지 Pull 시간을 단축할수 있다는 측면에서 의미가 있다. (대체로 빌드 + push 보다는 pull에 이점이 더 있다.)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;다만, Alpine, Debian을 기반으로 이미지를 생성해 나가는 것은 생각보다 어려운 작업이 될 수 있다. CentOS나 Ubuntu와 같이 기본으로 설치되어 있는 라이브러리들을 하나씩 추가해 나가며 어플리케이션이 동작되게 만드는 것은 다소 시간이 걸리는 작업이기 때문이다. 이러한 작업에 익숙하지 않은 경우에는 CentOS나 Ubuntu를 기반으로 하되 이미지를 Mininal 또는 필수패키지 만 Install된 버전으로 선택하여 구성해 나가는 것이 좋다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;2) Package Manager 패키지 관리&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;Package 매니저로 패키지를 설치할 경우 불필요한 패키지가 함께 설치되는 경우가 많이 있다. 이를 방지하기 위해 --no-install-recommends 옵션을 추가하여 설치하는 것이 이미지를 경량화 하는 방법이다. 또한 설치가 완료되면 패키지 매니저의 캐시 리스트를 함께 제거하는 것도 중요하다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;ex) Dockerfile RUN&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;crystal&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;RUN apt-get update &amp;amp;&amp;amp; apt-get install -y --no-install-recommends ssh vim &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;3) &lt;span style=&quot;color: #000000;&quot;&gt;도커 이미지 Layer 관리&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;도커 이미지에는 Layer라는 Stack이 존재한다. 도커 이미지를 효과적으로 관리하기 위해 Stack 형태로 이미지가 누적되어 쌓이는 방식이다. 동일한 stack이 동일한 Repository에 존재할 경우 굳이 다시 해당 layer를 생성하거나, push하거나 pull 하지 않도록 매커니즘이 구현되어 있다. 이후 도커 이미지는 컨테이너의 사이즈를 결정하기도 하지만, 관리 측면에서 Local Repository나 Docker Registry의 사이즈를 결정하기도 한다. 따라서 Docker Layer 관리는 굉장히 중요한 부분이라 할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;다음과 같은 예를 들어 설명해 보도록 하자.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;[CASE 1]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;dockerfile&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FROM debian:experimental-20210311
RUN apt-get update &amp;amp;&amp;amp; apt-get install -y wget
RUN wget https://download.sonatype.com/nexus/oss/nexus-latest-bundle.tar.gz
RUN rm next-latest-bundle.tar.gz&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;[CASE 2]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;sas&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FROM debian:experimental-20210311
RUN apt-get update &amp;amp;&amp;amp; apt-get install -y wget
RUN wget https://download.sonatype.com/nexus/oss/nexus-latest-bundle.tar.gz &amp;amp;&amp;amp; rm next-latest-bundle.tar.gz&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;이를 각각 빌드한 결과 이미지 사이즈는 다음과 같다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-114-198 layer]# docker images | grep debiansize
debiansize          case2                   b54fe5f58286        4 seconds ago       151MB
debiansize          case1                   26ab4f733fdb        42 seconds ago      234MB
[root@ip-192-168-114-198 layer]# &lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;위와 같이 case1이 234MB, case2가 151MB임을 알 수 있다. 동일한 동작을 수행하였음에도 이와 같이 사이즈에 차이가 나는 이유는 Layer 별 참조 관계 때문이다. Layer를 구성하는 요소는 바로 Dockerfile을 구성하는 Command의 차이에서 확인할 수 있다. CASE 1의 세번째 라인인 wget이 실행되는 Layer에는 이미 Nexus 바이너리가 포함되어 있고, 네번째 라인에서 삭제를 한들 세번째 Layer에는 영향을 주지 않기 때문에 이미지 사이즈의 차이가 발생하는 것이다. 두 케이스의 이미지 사이즈 차이는 결국&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-114-198 layer]# ls -lah
total 80M
drwxr-xr-x  2 root root   82 Mar 14 03:58 .
dr-xr-x--- 20 root root 4.0K Mar 14 03:47 ..
-rw-r--r--  1 root root  189 Mar 14 03:51 Dockerfile
-rw-r--r--  1 root root  190 Mar 14 03:50 Dockerfile_split
-rw-r--r--  1 root root  80M Dec 30 16:44 nexus-latest-bundle.tar.gz
[root@ip-192-168-114-198 layer]# &lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;다운로드 받은 nexus-latest-bundle.tar.gz 사이즈의 차이라고 볼 수 있다. 따라서 삭제가 필요한 파일을 관리할 경우에는 반드시 같은 Layer에서 처리해야 한다. 이 부분은 많은 Dockerfile 작성자 들이 놓치는 부분이라 볼 수 있다.&lt;br /&gt;Docker Layer는 Union Mount라는 Linux Mount 기술을 활용하여 여러 Layer를 통합하여 하나의 이미지로 관리한다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;4) 임&lt;span style=&quot;color: #000000;&quot;&gt;시 파일 삭제&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;불필요한 임시 파일은 삭제하는 것이 좋다. 위와 같이 파일 삭제가 필요한 경우 같은 Layer에서 처리하도록 구성하는 것을 권고했으며, 다음과 같은 방법으로도 이를 사전에 방지할 수 있다. wget을 사용해서 다운로드 받을 경우 파이프라이닝과 조합하여 사용하면 파일 다운로드 시 압축파일은 생성하지 않고 압축이 해제된 파일만 남겨 둘 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;awk&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;wget -O - https://download.sonatype.com/nexus/oss/nexus-latest-bundle.tar.gz | tar zxf -&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;5) 외부 볼륨 활용&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;이미지의 사이즈는 굉장히 중요한 요소임은 이미 충분히 인지했을 거라 생각한다. 컨테이너의 이미지를 경량화 시키기 위해 로그 파일이나 Runtime에 생성되는 Dynamic Class, 업로드 파일 등은 외부 볼륨을 활용하여 저장한다. 특히 대용량 볼륨을 요구하는 사진, 파일 등이 저장되는 공간을 로컬 볼륨에 둘 경우 이미지의 사이즈 증가는 물론 기본 컨테이너 이미지의 내부 공간은 휘발성을 가정하기 때문에 삭제 될 수 있다는 위험을 감수하고 사용해야 한다. 따라서 Network 볼륨을 사용하거나, HostPath 볼륨을 사용하여 관리하는 것이 좋다. 대체로 로그 파일은 HostPath, 모든 Pod에서 공유해서 관리되는 사진이나, 파일은 Network 볼륨에 저장한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;6) 어플리케이션 소스 경량화&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;어플리케이션 소스를 경량화 해야 한다느 점은 아무리 강조해도 부족하다. WAR, EAR, JAR 등의 Archive를 배포한다 하더라도 archive 내부에는 불필요한 libaray의 중복, JDK의 중복, .svn과 같은 메타 파일 또는 소스 파일 등이 포함되어 있을 수도 있기에 직접 압축을 해제해서 검증 과정을 한번쯤은 거치는 것이 좋다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;두번째, 1 Pod - 1 Container&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;컨테이너는 하나의 독립적인 동작을 정의하는 단위라고 볼 수 있다. 이를 Kubernetes와 같은 컨테이너 관리 플랫폼(PaaS)에 배치할 경우 배포 단위는 Container에서 Pod로 변경된다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;여기서 주의할 점은 하나의 Pod에는 여러개의 Container가 포함될 수 있지만, Main이 되는 어플리케이션은 하나만 구성해야 한다는 점이다. 여기서 Main이라 함은 비즈니스를 포함하는 어플리케이션 정도로 생각할 수 있다. SideCar에 의해 배치되는 Logging Bits, Prometheus의 exporter와 같은 Container는 하나의 Pod에 여러 컨테이너로 합류할 수 있지만, 야구 어플리케이션과 농구 어플리케이션이 하나의 Pod 안에 동작하게 해서는 안된다는 것이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;OS가 기동되면 Init Process라는 1번 부모 프로세스가 기동되면서 하위 프로세스를 Fork하여 관리하는 형태로 되어 있다. (물론 Kernel 2.4 이후 버전에서는 System과 사용자 영역이 구분되어 모든 프로세스가 Init 하위에 있는 것은 아니다. 자세한 내용은 &lt;a href=&quot;https://waspro.tistory.com/556&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[Docker] Kubernetes 보안 (Cgroup)&lt;/a&gt;를 참고하자.)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;이는 1번 프로세스가 종료되었을 경우 OS가 종료된다는 의미이며, Pod의 LifeCycle을 관리하는 주체가 된다는 의미로 볼 수 있다. 1번 프로세스는 Dockerfile에 정의된 ENTRYPOINT와 CMD가 그 대상이며, Container 이미지에 포함되어 있는 어플리케이션을 기동하기 위해 미들웨어를 기동하는 Script나 Command가 대체로 이에 포함된다. 즉 미들웨어가 종료되면 컨테이너 이미지는 종료된다고 볼 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;이때, 야구 어플리케이션과 농구 어플리케이션이 서로 다른 마이크로 서비스로 구성되어 있고 각각 WAS 인스턴스로 기동된다고 볼 때 둘 중 하나는 종료에 대한 프로세스로 지정될 수가 없다. 즉 야구 어플리케이션 인스턴스가 init으로 기동될 경우 농구 어플리케이션 인스턴스에 이상이 발생해도 해당 Pod는 정상상태를 유지한다는 것이다. 우회 방안으로 이를 해결할 수 있겠지만, 근본적인 원칙으로는 이와 같이 구성하는 것은 지양하는 것을 권고한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;세번째, 가독성 확보&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;1) Dockerfile 공개&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;Dockerfile은 항상 공개해 두는 것이 좋다. 공개의 의미는 외부의 공개가 아닌 같은 작업자 간의 공유가 가능하도록 하라는 의미이다. 공개 방식은 디스크에 저장하는 방식을 사용하지 말고, 리포지토리를 구성하여 Dockerfile을 관리할 수 있도록 한다. 대표적으로 Docker 이미지를 저장하는 Nexus, Harbor를 함께 활용하거나, Source 형상관리와 묶어 관리하는 방법 등이 있다. Dockerfile은 해당 컨테이너 이미지의 구성을 한눈에 확인할 수 있고 그 의도를 명확히 할 수 있어야 한다. 특히 tag를 통해 버전관리가 되도록 구성하는 것이 반드시 필요하다. 이는 Agility 배포 환경에서 불필요한 확인 시간을 줄이는 방법이라 이미지 수정 시간을 단축할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;2) &lt;span style=&quot;color: #000000;&quot;&gt;태그 활용하기&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;도커 파일은 때로는 수 라인만으로도 생성이 가능하지만, 복잡한 환경의 경우 수십 또는 수백라인으로 구성될 수도 있다. 따라서 자바 코드를 작성하듯 도커 파일의 가독성은 굉장히 중요하다. 이를 통해 이후 유지보수 관점에서 얼마나 신속하고 정확하게 변경할 수 있는지 결정되기 때문이다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;다음 예를 보며 살펴보자.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;routeros&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;RUN apt-get update &amp;amp;&amp;amp; \
    apt-get install -y \
    wget=1.13.4 \
    ca-certificates=20130119
COPY run_wildfly.sh /root
RUN cd /root &amp;amp;&amp;amp; sh run_wildfly.sh&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;위는 가독성을 높여주기 위해 초기 설치되어야하는 패키지 설치과정, 복사, 그리고 복사된 파일을 실행하는 과정이 각각 하나의 라인으로 묶여 있다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;만약 이 과정이 다음과 같이 구분되어 있다고 가정해 보자.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;routeros&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;RUN apt-get update &amp;amp;&amp;amp; \
    apt-get install -y \
RUN wget=1.13.4 \
COPY run_wildfly.sh /root
RUN cd /root &amp;amp;&amp;amp; sh run_wildfly.sh
RUN ca-certificates=20130119&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;위는 모든 라인을 풀어서 라인별로 구성되어 있으며, 각 라인의 동작하고자 하는 목적을 해석하기가 번거롭다. 명확히 도커파일의 각 라인이 동작하고자 하는 목적을 쉽게 파악할 수 있게 라인을 묶어서 구성하는 것과 필요하다면 주석을 다는 것도 가독성을 높이는 방법이 될 것이다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;보다 높은 가독성을 확보하고자 할 경우 ENV 환경 변수를 사용하는 것이 좋다. 환경 변수를 효과적으로 사용하면 가독성은 물론 작업 효율성과 반복에 의한 실수를 줄일 수 있다는 장점까지 가져 갈 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;3) COMMAND 적극 활용&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;RUN, ADD, COPY를 제외한 Command는 가독성을 높이기 위해 사용을 권장한다. 이 3개의 Command 이외의 나머지 명령어들은 Layer에 포함되지 않는다. 즉 나머지 명령어들은 가독성을 높이기 위해 사용될 수 있는 명령어라고 볼 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;예를 들어 보자.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;dockerfile&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FROM debian:experimental-20210311
RUN mkdir -p /home/nrson/test &amp;amp;&amp;amp; \
    cd /home/nrson/test&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;위는 디렉토리 이동을 cd로 동작하도록 구성했으며, &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;dockerfile&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FROM debian:experimental-20210311
RUN mkdir -p /home/nrson/test
WORKDIR /home/nrson/test&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;위는 WORKDIR을 이용하여 디렉토리를 이동하였다. 이때 별도의 Layer가 생성되는 것이 아닌 위와 동일한 사이즈의 이미지와 동일한 Layer 수를 갖게 된다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;따라서 RUN, ADD, COPY를 제외한 Command의 경우 가독성을 위해 적극 사용하는 것이 좋다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;네번째,&amp;nbsp;빌드/배포&amp;nbsp;속도&amp;nbsp;고려&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;1) 어플리케이션 빌드&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;컴파일을 위한 jdk, gcc, python 등 사이즈가 제법 되는 라이브러리들이 함께 설치 되어야 하며 이미지 빌드 시간이 늘어나는 현상이 발생된다. OS 환경의 영향을 덜 받는 Java의 경우 컴파일이 완료된 Class를 패키징하여 업로드 하며, C와 같이 OS 환경의 영향을 많이 받는 경우 Base Image와 동일한 환경을 VM으로 구성해 두고 해당 환경에서 Pre-Compile 후 바이너리만 업로드 하는 것이 좋다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;위와 같이 서버 상에서 컴파일이 필요하지 않을 경우 Java는 JDK가 아닌 JRE, C의 경우 GCC 라이브러리를 설치 하지 않아도 되기 때문에 이미지 경량 효과까지 함께 볼 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;2) 패키지 매니저 관리&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;yum, apt-get과 같은 패키지 매니저의 update &amp;amp; upgade와 같은 동작은 빌드 시간을 대폭 증가 시키게 된다. 필수적으로 필요한 패키지만 설치하도록 하며, 부득이 하게 update &amp;amp; upgrade가 필요할 경우 Custom Image에서 매번 동작하도록 하지 말고, Base Image 생성 시 패키지 매니저 구성을 완료해 두고 이후 Custom Image에서는 어플리케이션만 변경되도록 구성하는 것이 빌드/배포 시간을 단축하는 방법이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;3) Dockerfile Command 순서&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;Dockerfile은 Layer로 관리되기 때문에 각 Layer는 상위 Layer를 참조하는 형태를 띈다. 다음과 같은 Dockerfile을 두고 고민해 보자.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;routeros&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FROM debian:experimental-20210311
RUN uname -a
COPY . /home/nrson/webhome
RUN apt-get update &amp;amp;&amp;amp; apt-get install -y wget ssh&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;위와 같이 빌드가 실행되면, RUN uname -a는 Layer A, COPY는 Layer B, RUN apt-get은 Layer C로 각각 생성된다. 이때, COPY할 파일이 변경되었다고 가정해보자.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Layer는 참조 관계가 있어 하위 Layer가 변경되면 상위 Layer도 함께 변경된다. 따라서 COPY의 변경에 의해 RUN apt-get 역시 다시 이미지 빌드를 수행하는 것을 볼 수 있다. 다시 이미지 빌드를 수행하는 이유는 Layer를 재생성하기 위함이다. 이는 결국 빌드 시간이 늘어나고, 이미지의 Layer가 누적되어 변경되므로 디스크 낭비가 발생한다고 볼 수 있다.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이를 효과적으로 관리하기 위해서는 다음과 같은 두가지 방침을 따라야 한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;첫번째는 변경 가능한 라인은 최대한 아래로 내리는 것이 좋다. 즉 어플리케이션 Layer는 반드시 제일 아래로 내려주는 것이 좋다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;routeros&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FROM debian:experimental-20210311
RUN uname -a
RUN apt-get update &amp;amp;&amp;amp; apt-get install -y wget ssh
COPY . /home/nrson/webhome&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;이렇게 변경될 경우 RUN uname -a와 RUN apt-get은 COPY와 상관없이 고정되게 된다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;두번째는 COPY 명령어를 사용할 경우 디렉토리 형식을 사용하지 말고 가능한 파일을 지정하는 것이 좋다. COPY를 사용할 경우 빌드하는 위치에 따라 불필요한 파일이 함께 업로드 될 수 있어 이를 방지하는 차원에서 파일 명을 지정해 주는 것이 좋다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;다섯번째, 태그 관리&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;도커 파일에 지정되는 이미지의 태그를 latest로 무심결에 저장하는 경우가 많이 있다. 이미지의 최신 버전을 latest로 저장하는 것은 잘못된 습관이며, release 되는 대상이 있을 경우 latest로 저장하여 관리하도록 한다. dev / test 과정의 이미지는 반드시 이미지의 용도나 버전을 확인할 수 있는 tag 명을 정의하여 붙이도록 하며, 같이 작업하는 개발자가 많을 수록 이미지의 Naming을 정의하는 것이 중요하다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;또한 해당 이미지는 Local Repository에 관리하는 것이 아닌 Docker Repository에 Registry 별로 구분하여 관리하도록 구성한다. 특히 어플리케이션에 대한 정보뿐 아니라 이미지의 변경 정보를 함께 tag를 통해 명시적으로 알아볼 수 있게 작성해 주는 것이 중요하다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;결론&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;컨테이너 이미지는 마이크로 서비스 기술의 완성을 위해 반드시 고민해서 작성되어야 한다. 컨테이너의 agility, resilience, reliability, scalability 모두 컨테이너 이미지의 완성도 있는 작성에서부터 그 이점을 가져갈 수 있을 것이라는 점을 기억해야 하며, 전체를 모두 적용할 수 있다면 좋겠지만, 가능한 많은 부분을 검토하여 적용할 수 있도록 어느 정도의 애포트를 들여 적용하는 것은 반드시 필요할 것이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>③ 클라우드/ⓓ Docker</category>
      <category>Dockerfile</category>
      <category>dockerfile 최적화</category>
      <category>도커 이미지 최적화</category>
      <category>샌드박스 컨테이너</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/692</guid>
      <comments>https://waspro.tistory.com/692#entry692comment</comments>
      <pubDate>Sun, 14 Mar 2021 12:35:00 +0900</pubDate>
    </item>
    <item>
      <title>docker container stack size 조절하기</title>
      <link>https://waspro.tistory.com/689</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;docker container는 host kernel을 공유하지만, 때로는 구분된 limit 정보를 구성해야할 경우가 발생한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;예를 들어, nofile(open files)나 nproc(max user processes)의 경우 application의 요구사항에 따라 또는 솔루션의 요구사항에 따라 변경하여 적용할 필요가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;아래는 docker container를 사용할 경우 ulimit을 일괄 변경하는 방법에 대해 알아보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;systemctl show docker&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;먼저, docker의 variable 정보를 확인한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1613317457658&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-114-198 ~]# systemctl show docker
Type=notify
Restart=always
NotifyAccess=main
RestartUSec=2s
...
...
...
LimitCPU=18446744073709551615
LimitFSIZE=18446744073709551615
LimitDATA=18446744073709551615
LimitSTACK=18446744073709551615
LimitCORE=18446744073709551615
LimitRSS=18446744073709551615
LimitNOFILE=2048
LimitAS=18446744073709551615
LimitNPROC=2048
LimitMEMLOCK=65536
LimitLOCKS=18446744073709551615
LimitSIGPENDING=3790
...
...
...&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;docker run --ulimit&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;먼저 docker run --ulimit 옵션으로 각 도커 컨테이너 별 ulimit을 수정할 수 있다. 각 서비스 별로 서로 다른 ulimit 정보를 구성해야 할 경우 해당 옵션을 활용한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1613317722548&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-114-198 ~]# docker run --name ps --rm centos_ps:latest

core file size          (blocks, -c) unlimited
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 3790
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) unlimited
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited
[root@ip-192-168-114-198 ~]# docker run --name ps --ulimit nofile=2048:2048 --rm centos_ps:latest
core file size          (blocks, -c) unlimited
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 3790
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 2048
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) unlimited
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited
[root@ip-192-168-114-198 ~]# &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;위와 같이 docker run --name ps --rm centos_ps:latest의 경우 open files가 1024였으나, docker run --name ps --ulimit nofile=2048:2048 --rm centos_ps:latest 적용 후 open files가 2048로 반영된 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;이와 같은 경우 docker default 설정보다 우선시 되어 반영된다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;docker default options&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;docker의 default 설정은 &lt;span style=&quot;color: #000000;&quot;&gt;/etc/sysconfig/docker&lt;/span&gt;에서 구성할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1613317906263&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-114-198 ~]# cat /etc/sysconfig/docker
# The max number of open files for the daemon itself, and all
# running containers.  The default value of 1048576 mirrors the value
# used by the systemd service unit.
DAEMON_MAXFILES=1048576

# Additional startup options for the Docker daemon, for example:
# OPTIONS=&quot;--ip-forward=true --iptables=true&quot;
# By default we limit the number of open files per container
OPTIONS=&quot;--default-ulimit nofile=1024:4096&quot;

# How many seconds the sysvinit script waits for the pidfile to appear
# when starting the daemon.
DAEMON_PIDFILE_TIMEOUT=10
[root@ip-192-168-114-198 ~]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;OPTIONS=&quot; --default-ulimit nofile=1024:4096&quot; 옵션을 반영할 경우 기본으로 Docker Container가 기동될때 별도의 옵션을 적용하지 않을 경우 1024:4096이 반영된다.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1613318266545&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-114-198 ~]# docker run --name ps --rm centos_ps:latest

core file size          (blocks, -c) unlimited
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 3790
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) unlimited
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited
[root@ip-192-168-114-198 ~]# &lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;daemon.json&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;/etc/docker/daemon.json&lt;/span&gt;의 경우 docker default options와 비슷하게 구성할 수 있으나, 보다 상세한 설정을 반영할 수 있다. daemon.json을 적용하기 위해서는 docker default options를 주석처리해야 반영이 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1613318065742&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
        &quot;default-ulimits&quot;: {
                &quot;nofile&quot;: {
                        &quot;Name&quot;: &quot;nofile&quot;,
                        &quot;Hard&quot;: 64000,
                        &quot;Soft&quot;: 64000
                }
        }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;적용이 완료되면 systemctl restart docker 재시작한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1613318363387&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-114-198 ~]# docker run --name ps --rm centos_ps:latest
core file size          (blocks, -c) unlimited
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 3790
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 64000
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) unlimited
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited
[root@ip-192-168-114-198 ~]#&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;결론&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Kubernetes의 경우에도 마찬가지로 동작한다. docker를 기반으로 동작하기 때문에 Kubernetes의 서비스를 관리하는 방법으로 위와 같은 설정을 적용할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;서비스 별로 서로 다른 ulimit 값을 지정하고 싶은 경우에는 docker run --ulimit 옵션을 재정의하고, 모든 docker image에 일괄로 적용하고 싶을 경우 모든 kubernetes worker node의 daemon.json에 적용하는 방법을 권고한다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>③ 클라우드/ⓓ Docker</category>
      <category>daemon.json</category>
      <category>daemon.json ulimit</category>
      <category>docker default-limits</category>
      <category>docker nofiles</category>
      <category>docker nproc</category>
      <category>docker run --ulimit</category>
      <category>docker ulimit</category>
      <category>systemctl show docker</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/689</guid>
      <comments>https://waspro.tistory.com/689#entry689comment</comments>
      <pubDate>Mon, 15 Feb 2021 01:03:15 +0900</pubDate>
    </item>
    <item>
      <title>Bamboo Plan으로 EKS에 배포하기</title>
      <link>https://waspro.tistory.com/687</link>
      <description>&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;개요&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;Bamboo Plan은 Jenkins의 파이프라인과 같이 여러 Stage를 하나로 묶어 서로 다른 컴포넌트의 동작을 하나처럼 움직이도록 하는 빌드/배포 방식이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;500.0&quot; data-origin-height=&quot;318.0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cVS5m2/btqUuMnjE9g/ybHCa7CRTMfDZKNOlnw99K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cVS5m2/btqUuMnjE9g/ybHCa7CRTMfDZKNOlnw99K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cVS5m2/btqUuMnjE9g/ybHCa7CRTMfDZKNOlnw99K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcVS5m2%2FbtqUuMnjE9g%2FybHCa7CRTMfDZKNOlnw99K%2Fimg.png&quot; data-origin-width=&quot;500.0&quot; data-origin-height=&quot;318.0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;Jenkins의 경우 Pipeline &amp;rarr; Stage&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;rarr; Step&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;rarr; Script로 단계를 관리한다. 이와 마찬가지로 Bamboo는 Plan&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;rarr; Stage&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;rarr; Job&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;rarr; Task로 단계를 관리한다. 지금부터는 이 관계도를 기반으로 어떻게 Bamboo Plan을 구성하고 실행하는지 살펴보도록 하자.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;Bamboo 빌드/배포&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;이제 본격적으로 Bamboo를 구축해 보도록 하자. 모든 Bamboo의 배포 체계를 Plan을 생성함으로써 시작되며, 이미 생성되어 있는 Plan에 Stage를 추가하여 배포를 변경할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;Bamboo Plan&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&amp;gt; Create - Create plan&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0wpPG/btqUtqymSva/JgLSXpTqpxFdVnzCiqLUnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0wpPG/btqUtqymSva/JgLSXpTqpxFdVnzCiqLUnk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0wpPG/btqUtqymSva/JgLSXpTqpxFdVnzCiqLUnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0wpPG%2FbtqUtqymSva%2FJgLSXpTqpxFdVnzCiqLUnk%2Fimg.png&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;먼저 Bamboo Plan을 생성한다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sGDGy/btqUtWDPC31/n8IGGkjwQCATzVA41SWdY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sGDGy/btqUtWDPC31/n8IGGkjwQCATzVA41SWdY1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sGDGy/btqUtWDPC31/n8IGGkjwQCATzVA41SWdY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsGDGy%2FbtqUtWDPC31%2Fn8IGGkjwQCATzVA41SWdY1%2Fimg.png&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;Bamboo Plan을 생성하면, 함께 Project를 생성한다. 만약 기존에 생성해둔 Project가 존재한다면, 해당 프로젝트를 선택할 수 있으며, New Project를 생성할 수도 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;- Project name : 신규 프로젝트 이름&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;- Plan name : 신규 Plan 이름&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;- Plan access : 생성한 Plan에 대한 사용자 View 권한 부여 여부 (체크 시 모든 사용자 View 권한 부여)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;- Link repository to new build plan - Repository host&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;Previously linked repository : Link Repository에 기 등록해 둔 형상관리 Repository 선택&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;Link new repository : 신규 Link Repository 등록&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;None : 형상관리 등록 안함&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;Bamboo Job&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;Configure Job에서는 Plan의 Default Job에 대해 정의한다. 추가 Job은 계속해서 더할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnRfv6/btqUtXpdniG/3SUCUcqhkWhngxcXlUg85k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnRfv6/btqUtXpdniG/3SUCUcqhkWhngxcXlUg85k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnRfv6/btqUtXpdniG/3SUCUcqhkWhngxcXlUg85k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnRfv6%2FbtqUtXpdniG%2F3SUCUcqhkWhngxcXlUg85k%2Fimg.png&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;- Isolate build - Run this job in : Agent environment (Bamboo Server 자체적으로 실행할지 또는 Docker Container를 기동하여 별도의 환경에서 Job을 기동할지 선택)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;- [Add task] 클릭&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&amp;gt; Task 선택&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lZen2/btqUEAF0CwO/kjmgSx9g6FxHOmKulEex9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lZen2/btqUEAF0CwO/kjmgSx9g6FxHOmKulEex9K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lZen2/btqUEAF0CwO/kjmgSx9g6FxHOmKulEex9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlZen2%2FbtqUEAF0CwO%2FkjmgSx9g6FxHOmKulEex9K%2Fimg.png&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;Job의 실제 업무를 정의하는 Task를 선택한다. Builder, Tests, Deployment, Source Control, Variables로 구분해서 원하는 Task를 선택할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&amp;gt; Source Code Checkout&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Cud5S/btqUGUKYJKI/c0KONZPkqulzkIv8zinsVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Cud5S/btqUGUKYJKI/c0KONZPkqulzkIv8zinsVk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Cud5S/btqUGUKYJKI/c0KONZPkqulzkIv8zinsVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCud5S%2FbtqUGUKYJKI%2Fc0KONZPkqulzkIv8zinsVk%2Fimg.png&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;예를 들어 Source Code를 Checkout 받기 위한 Task를 정의한다면, Source Control - Source Code Checkout을 선택하고&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3JSlj/btqUGTSQkH9/ZTqgQnBXllMkRPkPlBt0q1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3JSlj/btqUGTSQkH9/ZTqgQnBXllMkRPkPlBt0q1/img.png&quot; style=&quot;width: 32.8493%; margin-right: 10px;&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3JSlj/btqUGTSQkH9/ZTqgQnBXllMkRPkPlBt0q1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3JSlj%2FbtqUGTSQkH9%2FZTqgQnBXllMkRPkPlBt0q1%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/F2Gnm/btqUGT6ngTD/7MBiwhotECPKRc6waJUX1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/F2Gnm/btqUGT6ngTD/7MBiwhotECPKRc6waJUX1K/img.png&quot; style=&quot;width: 32.4126%; margin-right: 10px;&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/F2Gnm/btqUGT6ngTD/7MBiwhotECPKRc6waJUX1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FF2Gnm%2FbtqUGT6ngTD%2F7MBiwhotECPKRc6waJUX1K%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bao1WG/btqUGURJC3Y/B1yWVPWpAKuadtnpCgHl50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bao1WG/btqUGURJC3Y/B1yWVPWpAKuadtnpCgHl50/img.png&quot; style=&quot;width: 32.4126%;&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bao1WG/btqUGURJC3Y/B1yWVPWpAKuadtnpCgHl50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbao1WG%2FbtqUGURJC3Y%2FB1yWVPWpAKuadtnpCgHl50%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;Source Code Checkout Task 설정 정보를 구성한 후, Task를 Final Tasks로 드레그 앤 &amp;amp; 드랍하여 이동시킨다. 구성이 완료되면, [Create]를 선택한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;Plan 확인&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rCFzY/btqUzwqBeVV/kOTYhaODkJjr3qKuSkqFAK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rCFzY/btqUzwqBeVV/kOTYhaODkJjr3qKuSkqFAK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rCFzY/btqUzwqBeVV/kOTYhaODkJjr3qKuSkqFAK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrCFzY%2FbtqUzwqBeVV%2FkOTYhaODkJjr3qKuSkqFAK%2Fimg.png&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;생성이 완료된 Plan을 위와 같이 확인할 수 있다.&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Plan을 관리하는 3개의 구성 Plan이 존재하며, 이는 다음과 같다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DEcD3/btqUvECKv6r/r8BBY9n0O8g9lY1ja0U5e1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DEcD3/btqUvECKv6r/r8BBY9n0O8g9lY1ja0U5e1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DEcD3/btqUvECKv6r/r8BBY9n0O8g9lY1ja0U5e1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDEcD3%2FbtqUvECKv6r%2Fr8BBY9n0O8g9lY1ja0U5e1%2Fimg.png&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&amp;gt; Disable plan&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rOc2j/btqUtqkQUz3/Irrdfq2RWceldUL2rxOkkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rOc2j/btqUtqkQUz3/Irrdfq2RWceldUL2rxOkkk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rOc2j/btqUtqkQUz3/Irrdfq2RWceldUL2rxOkkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrOc2j%2FbtqUtqkQUz3%2FIrrdfq2RWceldUL2rxOkkk%2Fimg.png&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;Plan Run을 비활성화 한다. 활성화를 위해 Enable plan을 선택할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&amp;gt; Favourite plan&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;해당 Plan을 Favourite으로 지정한다. 한번 더 선택시 해제된다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&amp;gt; Configure plan&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dLrMZP/btqUGTywW7B/06HQU5zZ3okl3OWs4yyuSk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dLrMZP/btqUGTywW7B/06HQU5zZ3okl3OWs4yyuSk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dLrMZP/btqUGTywW7B/06HQU5zZ3okl3OWs4yyuSk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdLrMZP%2FbtqUGTywW7B%2F06HQU5zZ3okl3OWs4yyuSk%2Fimg.png&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;Plan에 대한 구성을 변경할 수 있다. Stage/Job을 구성하거나, Repository 추가, Permission 관리 등을 구성할 수 있으며, Variables를 사용하여 Task에서 사용하는 변수를 구성할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;이 Config plan 중 Variables를 구성해 보도록 하자.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Dm4HK/btqUuMgEI7e/LEYWAEHN9i8IKXhOaxikxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Dm4HK/btqUuMgEI7e/LEYWAEHN9i8IKXhOaxikxk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Dm4HK/btqUuMgEI7e/LEYWAEHN9i8IKXhOaxikxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDm4HK%2FbtqUuMgEI7e%2FLEYWAEHN9i8IKXhOaxikxk%2Fimg.png&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;해당 Variable은 Plan 내 모든 Task가 공유할 수 있다. (Jenkins의 Environment와 같다.)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;Plan 실행&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;Plan은 다음과 같이 실행할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgWn8t/btqUtVLI078/bvfZ8ctc9hUfmhsinKEE60/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgWn8t/btqUtVLI078/bvfZ8ctc9hUfmhsinKEE60/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgWn8t/btqUtVLI078/bvfZ8ctc9hUfmhsinKEE60/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcgWn8t%2FbtqUtVLI078%2FbvfZ8ctc9hUfmhsinKEE60%2Fimg.png&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;Bamboo 대시보드 홈에는 실행 가능한 Plan을 확인할 수 있다. 직접 오른쪽 Run 화살표 버튼으로 Plan을 실행하거나, 상단의 Projects &amp;rarr; Bamboo-K8S-Project &lt;span style=&quot;color: #000000;&quot;&gt;&amp;rarr;k8s-plan으로 이동하여 오른쪽 상단의 Run 버튼으로 실행할 수도 있다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;실행 결과는 Build 넘버(#n)을 클릭하여 확인할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4rv5j/btqUBvrrwbz/XESWOHkojwvyWX6kzypCtK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4rv5j/btqUBvrrwbz/XESWOHkojwvyWX6kzypCtK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4rv5j/btqUBvrrwbz/XESWOHkojwvyWX6kzypCtK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4rv5j%2FbtqUBvrrwbz%2FXESWOHkojwvyWX6kzypCtK%2Fimg.png&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;Summary, Tests, Commits, Artifacts, Logs, Metadata, Webhooks 등을 확인할 수 있으며, 특히 Logs를 통해 전체 상태를 상세하게 확인할 수 있다. (Jenkins의 Console로그와 같다.)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mz2XG/btqUtqSKcyy/eqoNYuIijMKbbLuKGCRbjK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mz2XG/btqUtqSKcyy/eqoNYuIijMKbbLuKGCRbjK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mz2XG/btqUtqSKcyy/eqoNYuIijMKbbLuKGCRbjK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fmz2XG%2FbtqUtqSKcyy%2FeqoNYuIijMKbbLuKGCRbjK%2Fimg.png&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;위와 같이 로그를 확인할 수 있으며, Source Code Checkout Task가 포함되어 있는 해당 Plan에서 정상적으로 소스코드가 체크아웃 되었는지 확인할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;몇몇 로그를 통해 확인할 수 있으며,&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;[Starting task 'Checkout K8S Bitbucket' of type 'com.atlassian.bamboo.plugins.vcs:task.vcs.checkout']&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;[Cloning into '/root/atlassian/bamboo-home/xml-data/build-dir/BAM-K8SPLAN-JOB1'...]&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;위 두 로그를 통해 해당 위치에 소스코드가 Checkout 되었는지 확인해 보도록 하자.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-123-141 BAM-K8SPLAN-JOB1]# pwd
/root/atlassian/bamboo-home/xml-data/build-dir/BAM-K8SPLAN-JOB1
[root@ip-192-168-123-141 BAM-K8SPLAN-JOB1]# ls -la
total 36
drwxr-x--- 6 root root   154 Jan 24 14:49 .
drwxr-x--- 5 root root    83 Jan 24 14:45 ..
drwxr-x--- 4 root root   131 Jan 24 14:49 bin
-rw-r----- 1 root root  1378 Jan 24 14:49 deployment.yaml
-rw-r----- 1 root root   185 Jan 24 14:49 Dockerfile
drwxr-x--- 8 root root   163 Jan 24 14:49 .git
-rw-r----- 1 root root   395 Jan 24 14:49 .gitignore
drwxr-x--- 3 root root    21 Jan 24 14:49 .mvn
-rw-r----- 1 root root 10070 Jan 24 14:49 mvnw
-rw-r----- 1 root root  6608 Jan 24 14:49 mvnw.cmd
-rw-r----- 1 root root  1682 Jan 24 14:49 pom.xml
drwxr-x--- 4 root root    30 Jan 24 14:49 src
[root@ip-192-168-123-141 BAM-K8SPLAN-JOB1]#&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;다음과 같이 소스코드가 정상적으로 Checkout 된 것을 확인할 수 있다. 이는 Jenkins Checkou Stage와 동일하다고 볼 수 있으며, 체크아웃 위치는 $BAMBOO_HOME/xml-data/build-dir/[JOB]으로 Jenkins의 workspace 위치라고 볼 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;Bamboo EKS 배포&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;자 이제 본격적으로 Amazon EKS에 배포를 해보도록 하자. Amazon EKS에 배포하는 과정은 다음과 같은 Job으로 구성된다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;(Bitbucket Checkout - Maven Build &amp;amp; Package - Docker Build - K8S Deploy)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;Bamboo Variables&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;앞서 살펴본데로 Plan 내 공통 변수를 다음과 같이 추가한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IeXKj/btqUBvsrelz/WE22Jgc426Dy2lbaRmYfDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IeXKj/btqUBvsrelz/WE22Jgc426Dy2lbaRmYfDK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IeXKj/btqUBvsrelz/WE22Jgc426Dy2lbaRmYfDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIeXKj%2FbtqUBvsrelz%2FWE22Jgc426Dy2lbaRmYfDK%2Fimg.png&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;DOCKER_USERNAME/DOCKER_PASSWORD : Nexus Docker Repository Credential&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;IMAGE_REGISTRY/SVC_CODE/SYSTEM_CODE/IMAGE_REPO : Docker Image Info&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;Bamboo Job&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cw2JBo/btqULDCWgA6/qm4JVMaktd3QY6wmkCQvC1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cw2JBo/btqULDCWgA6/qm4JVMaktd3QY6wmkCQvC1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cw2JBo/btqULDCWgA6/qm4JVMaktd3QY6wmkCQvC1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcw2JBo%2FbtqULDCWgA6%2Fqm4JVMaktd3QY6wmkCQvC1%2Fimg.png&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;a. Source Code Checkout (Source Checkout Bitbucket Repository)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;Bitbucket 소스를 Checkout하는 Source Code Checkout Task를 생성한다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/x8EZY/btqUM8JeXi6/WOPAJobUR7Cbwkmpw9lf3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/x8EZY/btqUM8JeXi6/WOPAJobUR7Cbwkmpw9lf3K/img.png&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/x8EZY/btqUM8JeXi6/WOPAJobUR7Cbwkmpw9lf3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fx8EZY%2FbtqUM8JeXi6%2FWOPAJobUR7Cbwkmpw9lf3K%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsXlJz/btqUL83OD7H/An26rlnq7crTjBgtnhG38k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsXlJz/btqUL83OD7H/An26rlnq7crTjBgtnhG38k/img.png&quot; style=&quot;width: 49.4186%;&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsXlJz/btqUL83OD7H/An26rlnq7crTjBgtnhG38k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsXlJz%2FbtqUL83OD7H%2FAn26rlnq7crTjBgtnhG38k%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;- Repository : Linked Repository로 연동된 소스 형상관리 도구의 Repository를 선택한다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;- Checkout Directory : Checkout 받을 경로를 지정한다. 지정하지 않을 경우 Default Job 경로에 Checkout을 받는다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;- Force Clean Build : 기존 Repository를 삭제하고 다시 전체 체크아웃을 받을지 여부를 선택한다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;- Add repository : Repository를 추가로 체크아웃 받도록 구성한다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;b. Maven Build &amp;amp; Package&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;Checkout 받은 소스를 Maven Build &amp;amp; Package한다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCR1gw/btqUEzH48Mf/8DSqhcmkW9Adqs7Kz15SM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCR1gw/btqUEzH48Mf/8DSqhcmkW9Adqs7Kz15SM1/img.png&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCR1gw/btqUEzH48Mf/8DSqhcmkW9Adqs7Kz15SM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCR1gw%2FbtqUEzH48Mf%2F8DSqhcmkW9Adqs7Kz15SM1%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cjye93/btqUEznQAv1/y1aoBEjHgcuUHbB9Bmwhb0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cjye93/btqUEznQAv1/y1aoBEjHgcuUHbB9Bmwhb0/img.png&quot; style=&quot;width: 49.4186%;&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cjye93/btqUEznQAv1/y1aoBEjHgcuUHbB9Bmwhb0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcjye93%2FbtqUEznQAv1%2Fy1aoBEjHgcuUHbB9Bmwhb0%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;- Executable : Executable에 등록된 컴포넌트를 선택한다. 빌드 방식 중 Maven, Gradle, Ant 등을 선택할 수 있으며, 현 Task에서는 Maven Build를 적용한다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;- Goal : build &amp;amp; package (option - properties) -Pdev&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;- Build JDK : 빌드 시 사용할 JDK를 선택한다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;- The build will produce test results : JUnit XML 형식의 테스크 결과가 없을 경우 빌드를 실패하도록 한다. Test Code를 생성하지 않고 빌드를 실행할 경우 해당 부분의 체크를 해제하고 Task를 생성해야 한다. 해제 하지 않을 경우, &quot;no failed test found. a possible compilation error occurred.&quot;와 함께 Task 빌드 실패가 발생할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;c. Docker Build&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;Docker Build Script를 통해 Docker login - Docker build - Docker push를 수행한다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/byUJyf/btqUEA1oCLy/0fRvXap96vR4nybS7dZLCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/byUJyf/btqUEA1oCLy/0fRvXap96vR4nybS7dZLCk/img.png&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/byUJyf/btqUEA1oCLy/0fRvXap96vR4nybS7dZLCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbyUJyf%2FbtqUEA1oCLy%2F0fRvXap96vR4nybS7dZLCk%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Awcne/btqUEAmJxan/sVCg3yQlBrsjoccaLcZFmK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Awcne/btqUEAmJxan/sVCg3yQlBrsjoccaLcZFmK/img.png&quot; style=&quot;width: 49.4186%;&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Awcne/btqUEAmJxan/sVCg3yQlBrsjoccaLcZFmK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAwcne%2FbtqUEAmJxan%2FsVCg3yQlBrsjoccaLcZFmK%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;- Interpreter : Shell &amp;amp; Windows PowerShell &amp;amp; /bin/sh or cmd.exe&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;- Script location : Inline &amp;amp; File&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;- Script body&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;armasm&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;echo &quot;Docker Build Start&quot;
docker login -u ${bamboo.DOCKER_USERNAME} -p ${bamboo.DOCKER_PASSWORD} ${bamboo.IMAGE_REGISTRY}
docker build -t ${bamboo.IMAGE_REPO}:dev --rm --force-rm --pull --network host -f Dockerfile-dev .
docker push ${bamboo.IMAGE_REPO}:dev
echo &quot;Docker Build End&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;d. K8S Deploy&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;Docker Build로 생성한 이미지를 Kubernetes에 배포한다. K8S에 배포하기 위해서는 .kube/config 즉 kubeconfig 파일이 사전에 구성되어 있어야 한다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/N6tfo/btqUwxErxmo/ChaRxknKXSnh5vfDutRXak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/N6tfo/btqUwxErxmo/ChaRxknKXSnh5vfDutRXak/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/N6tfo/btqUwxErxmo/ChaRxknKXSnh5vfDutRXak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FN6tfo%2FbtqUwxErxmo%2FChaRxknKXSnh5vfDutRXak%2Fimg.png&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;여기서는 Amazon EKS에 배포하도록 한다. Script Task를 추가하고, 다음과 같이 Script Body를 작성한다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;q&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;echo &quot;Deploy k8s-deploy Start&quot;
kubectl apply -f deployment-dev.yaml
kubectl get all -n dev
kubectl get ingress -n dev
echo &quot;Rollout k8s-deploy&quot;
kubectl --kubeconfig=/root/.kube/config rollout restart deployment/k8s-configmap-deployment -n dev
kubectl get all -n dev
kubectl get ingress -n dev
echo &quot;Deploy k8s-deploy End&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;e. Build 실행&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;위와 같이 작성된 Task를 기반으로 빌드를 실행해 보자.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/t4fLC/btqUOCDljBm/d8WkC8zTwDfjnQEQKlayUK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/t4fLC/btqUOCDljBm/d8WkC8zTwDfjnQEQKlayUK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/t4fLC/btqUOCDljBm/d8WkC8zTwDfjnQEQKlayUK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ft4fLC%2FbtqUOCDljBm%2Fd8WkC8zTwDfjnQEQKlayUK%2Fimg.png&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;위와 같이 빌드가 정상 수행되는 것을 확인할 수 있다. 빌드 결과를 기반으로 다음과 같은 정보를 확인할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;- Summary : Label 구성, 소스 형상관리 Revision, Tests Result&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pEwNp/btqUJYUV9hf/l4DUSUpSygiX71RRLAKGA0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pEwNp/btqUJYUV9hf/l4DUSUpSygiX71RRLAKGA0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pEwNp/btqUJYUV9hf/l4DUSUpSygiX71RRLAKGA0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpEwNp%2FbtqUJYUV9hf%2Fl4DUSUpSygiX71RRLAKGA0%2Fimg.png&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;- &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;Tests : Test Detail 정보&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bL1v30/btqUEA77MWw/hDWhSbr8rsJxsuqgv1H4Kk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bL1v30/btqUEA77MWw/hDWhSbr8rsJxsuqgv1H4Kk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bL1v30/btqUEA77MWw/hDWhSbr8rsJxsuqgv1H4Kk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbL1v30%2FbtqUEA77MWw%2FhDWhSbr8rsJxsuqgv1H4Kk%2Fimg.png&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;- Commits : 변경된 소스 형상관리 Commit 정보&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqFRRf/btqUBwZeX9Q/e67I5H9iowA4UxKrOCUNlk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqFRRf/btqUBwZeX9Q/e67I5H9iowA4UxKrOCUNlk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqFRRf/btqUBwZeX9Q/e67I5H9iowA4UxKrOCUNlk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqFRRf%2FbtqUBwZeX9Q%2Fe67I5H9iowA4UxKrOCUNlk%2Fimg.png&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;- Logs : 로그파일 다운로드 또는 웹 페이지 View&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8lt1E/btqUM7Q8lrY/viKcSS9T2bBKRqI1t8rSgk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8lt1E/btqUM7Q8lrY/viKcSS9T2bBKRqI1t8rSgk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8lt1E/btqUM7Q8lrY/viKcSS9T2bBKRqI1t8rSgk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8lt1E%2FbtqUM7Q8lrY%2FviKcSS9T2bBKRqI1t8rSgk%2Fimg.png&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;f. Plan Summary&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;전체 Job 실행 결과에 대한 Plan Summary 정보와 최근 History, Statics 등을 확인할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/t8U4t/btqUEzajDqI/ALXWnouU1TN8g86dofcQH0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/t8U4t/btqUEzajDqI/ALXWnouU1TN8g86dofcQH0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/t8U4t/btqUEzajDqI/ALXWnouU1TN8g86dofcQH0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ft8U4t%2FbtqUEzajDqI%2FALXWnouU1TN8g86dofcQH0%2Fimg.png&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;이번 포스팅에서는 Bamboo의 Plan을 직접 구성하여 EKS에 배포해 보았다. 본 포스팅에서는 단순한 Plan과 Job의 구성으로 이루어져 있었지만, 이를 보다 다양하게 활용해 나갈 수 있다. 예를 들어 배포 방식의 다양화 단순히 Kubernetes의 Rolling Update가 아닌 Blue-Green / Canary 배포 등을 여러 Plan으로 구분하여 적용할 수 있으며, 승인 프로세스를 구성하거나, 환경별로 구분하여 Stage를 관리하는 등 다양한 방법으로 Bamboo Plan을 활용할 수 있다. 또한 Bitbucket 역시 Branch &amp;amp; Tag 기반 이외에 시점 기반 Commit을 관리할 수도 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;이와 같은 다양한 활용 방법에 대해서는 추가적인 포스팅으로 다루도록 하자.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>⑤ 개발, 데이터베이스/ⓒ CI CD</category>
      <category>BAMBOO</category>
      <category>Bamboo EKS</category>
      <category>Bamboo Job</category>
      <category>Bamboo plan</category>
      <category>Bamboo Plan Stage Job Task</category>
      <category>Bamboo stage</category>
      <category>Bamboo Task</category>
      <category>Bamboo 실행</category>
      <category>Bitbucket</category>
      <category>no failed test found. a possible compilation error occurred</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/687</guid>
      <comments>https://waspro.tistory.com/687#entry687comment</comments>
      <pubDate>Sun, 24 Jan 2021 18:19:57 +0900</pubDate>
    </item>
    <item>
      <title>Bitbucket/Bamboo 구축하기</title>
      <link>https://waspro.tistory.com/685</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;개요&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Atlassian(아틀라시안) 도구는 소프트웨어 개발 및 개발자간 협업을 지원하는 다양한 컴포넌트를 제공한다. 대표적인 개발, 빌드 및 배포 지원 도구로 Bitbucket / Bamboo / Jira / SourceTree 등이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Bitbucket&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Bitbucket은 소스 형상관리 도구로 익히 알고 있는 git을 기반으로 하고 있다. 크게 3가지 형태의 버전을 제공한다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;a.Bitbucket Cloud&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Bitbucket Cloud는 Github와 같이 Atlassian에서 직접 웹 환경에서 제공해 주는 버전이다. &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;(&lt;a href=&quot;https://bitbucket.org/dashboard/overview&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://bitbucket.org/dashboard/overview&lt;/a&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vHqpT/btqUuM8iQTA/mNRkE4rzmQaPLukZlJTc9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vHqpT/btqUuM8iQTA/mNRkE4rzmQaPLukZlJTc9k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vHqpT/btqUuM8iQTA/mNRkE4rzmQaPLukZlJTc9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvHqpT%2FbtqUuM8iQTA%2FmNRkE4rzmQaPLukZlJTc9k%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Public 환경에서 접근이 가능할 경우 유용하게 사용할 수 있다. Bitbucket Private Repository는 무제한으로 생성할 수 있지만, 공유할 수 있는 사용자는 5인으로 제한된다. (유료버전을 사용할 경우 사용자 제한 없이 이용할 수 있다.) 또한 Bitbucket 자체에서 CI/CD 파이프라인을 구성할 수 있다는 장점이 있어 별도의 CI/CD 컴포넌트를 구성할 필요가 없다. (Jenkins / Bamboo 등)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;b. Bitbucket Server&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Private 환경에서 Bitbucket을 사용해야 하는 경우 사용한다. 단일 서버 환경에만 구축이 가능하며, 별도의 파이프라인 환경은 제공하지 않는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;c. Bitbucket Data Center&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Private 환경에서 Bitbucket을 사용해야 하는 경우 사용한다. 다중 서버 환경을 구성할 수 있으며, Bitbucket 서버의 가용성을 높일 수 있다. 별도의 파이프라인 환경은 제공하지 않는다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Bamboo&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Bamboo는 복잡한 빌드/배포 환경의 자동화를 위해 CI/CD 파이프라인을 지원한다. 대표적인 오픈소스 소프트웨어인 Jenkins와 같은 역할을 한다고 볼 수 있다. 특히 Atlassian 계열의 도구들과 유연한 통합을 지원하여 Bitbucket/Jira 등을 사용할 경우 손쉬운 통합을 지원한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;본 가이드에서는 Bitbucket - Bamboot - Nexus - EKS 간의 배포 프로세스에 대해 알아보도록 하자. Native Kubernetes에 대한 GitLab - Jenkins - Nexus - K8S 배포 프로세스를 확인하고자 할 경우 아래를 참고한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #006dd7;&quot;&gt;&lt;a style=&quot;color: #006dd7;&quot; href=&quot;https://waspro.tistory.com/573&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[④ 개발, 데이터베이스/ⓒ CI CD] - Kubernetes Jenkins - 자동 배포환경 구성 (1/2)&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #006dd7;&quot;&gt;&lt;a style=&quot;color: #006dd7;&quot; href=&quot;https://waspro.tistory.com/574&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[④ 개발, 데이터베이스/ⓒ CI CD] - Kubernetes Jenkins - 자동 배포환경 구성 (2/2)&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;본론&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;먼저 Bitbucket과 Bamboo를 구축해 보도록하자. Bitbucket과 Bamboo를 설치하기 전 사전에 구성되어야 할 CLI 컴포넌트는 Git, Maven, Docker 등이 있으며, 사전에 구축한 후 아래를 진행한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Atlassian 공식 사이트에 접속하면 다음과 같은 화면을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lKoR9/btqUtW4qA0J/veE8ExewQtURv9qgBuHls0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lKoR9/btqUtW4qA0J/veE8ExewQtURv9qgBuHls0/img.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lKoR9/btqUtW4qA0J/veE8ExewQtURv9qgBuHls0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlKoR9%2FbtqUtW4qA0J%2FveE8ExewQtURv9qgBuHls0%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dQuwSy/btqUuMUPVvw/H96EkpKuam6HJc3fRuUll1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dQuwSy/btqUuMUPVvw/H96EkpKuam6HJc3fRuUll1/img.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 49.4186%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dQuwSy/btqUuMUPVvw/H96EkpKuam6HJc3fRuUll1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdQuwSy%2FbtqUuMUPVvw%2FH96EkpKuam6HJc3fRuUll1%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;# 계정이 없을 경우 생성후 로그인한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;메뉴 항목 중 ko.atlassian.com을 선택하면, atlassian 도구 다운로드 사이트에 접속할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Bitbucket 설치&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Bitbucket Server를 설치하기 위해 다운로드 사이트에 접속한다. (&lt;a style=&quot;color: #000000;&quot; href=&quot;https://www.atlassian.com/software/bitbucket/download&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;https://www.atlassian.com/software/bitbucket/download&lt;/span&gt;)&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/V4UQB/btqUzwcBm80/Go6x4YcY8tfYdQcfXFqyrk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/V4UQB/btqUzwcBm80/Go6x4YcY8tfYdQcfXFqyrk/img.png&quot; data-filename=&quot;0-1. Bitbucket download.PNG&quot; data-origin-width=&quot;1215&quot; data-origin-height=&quot;968&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/V4UQB/btqUzwcBm80/Go6x4YcY8tfYdQcfXFqyrk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FV4UQB%2FbtqUzwcBm80%2FGo6x4YcY8tfYdQcfXFqyrk%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;1215&quot; height=&quot;968&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbzoml/btqUBv5zSaw/s1cRpHPWQ7SYcwdFz8tdZk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbzoml/btqUBv5zSaw/s1cRpHPWQ7SYcwdFz8tdZk/img.png&quot; data-filename=&quot;0-2. Bitbucket download.PNG&quot; data-origin-width=&quot;1215&quot; data-origin-height=&quot;968&quot; style=&quot;width: 49.4186%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbzoml/btqUBv5zSaw/s1cRpHPWQ7SYcwdFz8tdZk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbbzoml%2FbtqUBv5zSaw%2Fs1cRpHPWQ7SYcwdFz8tdZk%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;1215&quot; height=&quot;968&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; 다운로드 받은 &lt;a style=&quot;color: #000000;&quot; href=&quot;http://atlassian-bitbucket-7.9.1.tar.gz&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;atlassian-bitbucket-7.9.1.tar.gz&lt;/a&gt; Linux 서버에 업로드&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; 압축 해제 후 설정 작업 진행 (&lt;span style=&quot;color: #000000;&quot;&gt;다운로드 받은 압축파일 해제 및 bitbucket-home 디렉토리 생성&lt;/span&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1611412120833&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-123-141 atlassian-bitbucket-7.9.1]# pwd
/root/atlassian/atlassian-bitbucket-7.9.1
[root@ip-192-168-123-141 atlassian-bitbucket-7.9.1]# ls -la
total 64
drwxr-xr-x 8 root     root       107 Jan 23 07:39 .
drwxr-xr-x 6 root     root       187 Jan 23 08:32 ..
drwxr-xr-x 7 root     root       166 Jan 23 07:39 app
drwxr-xr-x 2 root     root      4096 Jan 23 07:54 bin
drwxr-xr-x 8 ec2-user ec2-user   153 Jan 14 04:47 elasticsearch
drwxr-xr-x 3 root     root        20 Jan 23 07:39 lib
drwxr-xr-x 2 root     root     40960 Jan 23 07:39 licenses
-rw-r--r-- 1 ec2-user ec2-user  2601 Jan 14 04:37 README.txt
drwxr-xr-x 3 root     root        32 Jan 23 07:39 tools
[root@ip-192-168-123-141 atlassian-bitbucket-7.9.1]# ls -la ../
total 626980
drwxr-xr-x  6 root     root           187 Jan 23 08:32 .
dr-xr-x--- 18 root     root          4096 Jan 23 07:50 ..
drwxr-xr-x  8 root     root           107 Jan 23 07:39 atlassian-bitbucket-7.9.1
-rw-r--r--  1 root     root     331295025 Jan 23 07:39 atlassian-bitbucket-7.9.1.tar.gz
drwxr-xr-x 11 root     root           181 Jan 23 07:55 bitbucket-home
[root@ip-192-168-123-141 atlassian-bitbucket-7.9.1]#&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- atlassian-bitbucket-7.9.1/bin : 각종 설정 파일 및 Bitbucket 기동/종료 스크립트&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- bitbucket-home : bitbucket repository home&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;gt; &lt;span style=&quot;color: #000000;&quot;&gt;atlassian-bitbucket-7.9.1/bin/set-bitbucket-home.sh&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1611412946162&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[set-bitbucket-home.sh]
...
if [ -z &quot;$BITBUCKET_HOME&quot; ]; then
    BITBUCKET_HOME=/root/atlassian/bitbucket-home
fi
...&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- BITBUCKET_HOME : bitbucket repository 지정 후 저장&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;atlassian-bitbucket-7.9.1/bin/set-jre-home.sh&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1611413309545&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[set-jre-home.sh]
...
if [ -z &quot;$JRE_HOME&quot; ]; then
    if [ -z &quot;$JAVA_HOME&quot; ]; then
        JRE_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.265.b01-1.amzn2.0.1.x86_64/jre
    elif [ -n &quot;$JAVA_HOME&quot; ] &amp;amp;&amp;amp; [ -x &quot;$JAVA_HOME/jre/bin/java&quot; ]; then
        JRE_HOME=&quot;$JAVA_HOME/jre&quot;
    elif [ -n &quot;$JAVA_HOME&quot; ] &amp;amp;&amp;amp; [ -x &quot;$JAVA_HOME/bin/java&quot; ]; then
        JRE_HOME=&quot;$JAVA_HOME&quot;
    fi
fi
...&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- JRE_HOME : jre 지정 후 저장&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;gt; &lt;span style=&quot;color: #000000;&quot;&gt;atlassian-bitbucket-7.9.1/bin/&lt;/span&gt;start-bitbucket.sh&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1611414722993&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-123-141 bin]# sh start-bitbucket.sh
Starting Atlassian Bitbucket as the current user

Starting bundled Elasticsearch
        Hint: Run start-bitbucket.sh --no-search to skip starting Elasticsearch
could not find java in bundled jdk at /root/atlassian/atlassian-bitbucket-7.9.1/elasticsearch/jdk/bin/java
There was a problem starting bundled Elasticsearch

Bitbucket is being run with a umask that contains potentially unsafe settings.
The following issues were found with the mask &quot;u=rwx,g=rx,o=rx&quot; (0022):
 - Access is allowed to 'others'. It is recommended that 'others' be denied
   all access for security reasons.
The recommended umask for Bitbucket is &quot;u=,g=w,o=rwx&quot; (0027) and can be
configured in _start-webapp.sh

Starting Bitbucket webapp at http://localhost:7990
The Bitbucket webapp has been started.

If you cannot access Bitbucket within 3 minutes, or encounter other issues, check the troubleshooting guide at:
https://go.atlassian.com/bbs-troubleshooting-installations
[root@ip-192-168-123-141 bin]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; font-size: 1.12em; letter-spacing: 0px;&quot;&gt;&amp;gt; Bitbucket Dashboard 접속&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/N0rQm/btqUzvxZnRB/f05kHKdKlqcwFYbSH5coWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/N0rQm/btqUzvxZnRB/f05kHKdKlqcwFYbSH5coWK/img.png&quot; data-origin-width=&quot;1528&quot; data-origin-height=&quot;843&quot; style=&quot;width: 34.2387%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/N0rQm/btqUzvxZnRB/f05kHKdKlqcwFYbSH5coWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FN0rQm%2FbtqUzvxZnRB%2Ff05kHKdKlqcwFYbSH5coWK%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;1528&quot; height=&quot;843&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cEXC8b/btqUtqkn19b/3jqk3ntlSqumtXIOw7emMK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cEXC8b/btqUtqkn19b/3jqk3ntlSqumtXIOw7emMK/img.png&quot; data-filename=&quot;2-1. Bitbucket Use.PNG&quot; data-origin-width=&quot;1528&quot; data-origin-height=&quot;910&quot; style=&quot;width: 31.7178%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cEXC8b/btqUtqkn19b/3jqk3ntlSqumtXIOw7emMK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcEXC8b%2FbtqUtqkn19b%2F3jqk3ntlSqumtXIOw7emMK%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;1528&quot; height=&quot;910&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjDNl1/btqUtq5JANP/RDAzjyMxZV0Keqk0K2TDy1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjDNl1/btqUtq5JANP/RDAzjyMxZV0Keqk0K2TDy1/img.png&quot; data-filename=&quot;2-2. Bitbucket Use.PNG&quot; data-origin-width=&quot;1528&quot; data-origin-height=&quot;910&quot; style=&quot;width: 31.7178%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjDNl1/btqUtq5JANP/RDAzjyMxZV0Keqk0K2TDy1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjDNl1%2FbtqUtq5JANP%2FRDAzjyMxZV0Keqk0K2TDy1%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;1528&quot; height=&quot;910&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; font-size: 1.12em; letter-spacing: 0px;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- 대시보드 접속 후 Language (English) 선택 후 Database 선택 (Embedded DB (Internal) or External DB)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR'; font-size: 1.12em; letter-spacing: 0px;&quot;&gt;- Licensing and settings : License 발급을 위해 Server ID 저장, License Key - I need an evaluation license 선택하면 자동으로 라이센스 발급 페이지로 이동 됨&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; Bitbucket Trial License Download (New Trial License &amp;gt; Product &amp;gt; Bitbucket)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SOj8E/btqUpavAjkq/WYDKdg3t0QRF0fOCVo6GQK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SOj8E/btqUpavAjkq/WYDKdg3t0QRF0fOCVo6GQK/img.png&quot; data-filename=&quot;1-2. Bitbucket 체험판라이센스.PNG&quot; data-origin-width=&quot;1215&quot; data-origin-height=&quot;866&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SOj8E/btqUpavAjkq/WYDKdg3t0QRF0fOCVo6GQK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSOj8E%2FbtqUpavAjkq%2FWYDKdg3t0QRF0fOCVo6GQK%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;1215&quot; height=&quot;866&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cmdYRY/btqUvDcjnhH/1FdC8tQrhKJTgYsGAihXKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cmdYRY/btqUvDcjnhH/1FdC8tQrhKJTgYsGAihXKK/img.png&quot; data-filename=&quot;1-3. Bitbucket 체험판라이센스.PNG&quot; data-origin-width=&quot;1215&quot; data-origin-height=&quot;866&quot; style=&quot;width: 49.4186%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cmdYRY/btqUvDcjnhH/1FdC8tQrhKJTgYsGAihXKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcmdYRY%2FbtqUvDcjnhH%2F1FdC8tQrhKJTgYsGAihXKK%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;1215&quot; height=&quot;866&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/edkYWv/btqUsdMqUVl/6cd6OSkMkzeNzNmCKwIpE1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/edkYWv/btqUsdMqUVl/6cd6OSkMkzeNzNmCKwIpE1/img.png&quot; data-filename=&quot;1-5. Bitbucket 체험판라이센스.PNG&quot; data-origin-width=&quot;1528&quot; data-origin-height=&quot;843&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/edkYWv/btqUsdMqUVl/6cd6OSkMkzeNzNmCKwIpE1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FedkYWv%2FbtqUsdMqUVl%2F6cd6OSkMkzeNzNmCKwIpE1%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;1528&quot; height=&quot;843&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bC9ma0/btqUo85MWQe/hEkoZf52Wc5vsdNlfbXu3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bC9ma0/btqUo85MWQe/hEkoZf52Wc5vsdNlfbXu3k/img.png&quot; data-filename=&quot;1-6. Bitbucket 체험판라이센스.PNG&quot; data-origin-width=&quot;1528&quot; data-origin-height=&quot;843&quot; style=&quot;width: 49.4186%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bC9ma0/btqUo85MWQe/hEkoZf52Wc5vsdNlfbXu3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbC9ma0%2FbtqUo85MWQe%2FhEkoZf52Wc5vsdNlfbXu3k%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;1528&quot; height=&quot;843&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- Product : Bitbucket&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;- License type : Bitbucket (Server)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;- Organization : waspro&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;- Your Instance is : not installed yet&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;- Server ID : XXXX-XXXX-XXXX-XXXX&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;- Generate License 클릭&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; Bitbucket setup&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;2-3. Bitbucket Use.PNG&quot; data-origin-width=&quot;1528&quot; data-origin-height=&quot;843&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cPCAmy/btqUuNzscAH/tjSFMjAIjwrAy3xDvCulgK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cPCAmy/btqUuNzscAH/tjSFMjAIjwrAy3xDvCulgK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cPCAmy/btqUuNzscAH/tjSFMjAIjwrAy3xDvCulgK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcPCAmy%2FbtqUuNzscAH%2FtjSFMjAIjwrAy3xDvCulgK%2Fimg.png&quot; data-filename=&quot;2-3. Bitbucket Use.PNG&quot; data-origin-width=&quot;1528&quot; data-origin-height=&quot;843&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;- 발급이 완료되면, 자동으로 라이센스 파일 적용 됨&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; Administrator account setup&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;2-4. Bitbucket Use.PNG&quot; data-origin-width=&quot;1528&quot; data-origin-height=&quot;843&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bB8ACU/btqUtV5wlJG/QCbGzKOUwEggN8I56AJX4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bB8ACU/btqUtV5wlJG/QCbGzKOUwEggN8I56AJX4k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bB8ACU/btqUtV5wlJG/QCbGzKOUwEggN8I56AJX4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbB8ACU%2FbtqUtV5wlJG%2FQCbGzKOUwEggN8I56AJX4k%2Fimg.png&quot; data-filename=&quot;2-4. Bitbucket Use.PNG&quot; data-origin-width=&quot;1528&quot; data-origin-height=&quot;843&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;- Username : admin&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;- Full name : admin&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;- Email address : son.nara@lgcns.com&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;- Password : xxxxxxxx&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;- Confirm password : xxxxxxxx&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nY0xs/btqUnJZlVd0/tk5Z0Z8MpbtD9EJAC3h4Rk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nY0xs/btqUnJZlVd0/tk5Z0Z8MpbtD9EJAC3h4Rk/img.png&quot; data-filename=&quot;2-5. Bitbucket Use.PNG&quot; data-origin-width=&quot;1528&quot; data-origin-height=&quot;843&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nY0xs/btqUnJZlVd0/tk5Z0Z8MpbtD9EJAC3h4Rk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnY0xs%2FbtqUnJZlVd0%2Ftk5Z0Z8MpbtD9EJAC3h4Rk%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;1528&quot; height=&quot;843&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cbLf0I/btqUvDDigwM/93Yhi03oDer2D9f6EPivt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cbLf0I/btqUvDDigwM/93Yhi03oDer2D9f6EPivt1/img.png&quot; data-filename=&quot;2-6. Bitbucket Use.PNG&quot; data-origin-width=&quot;1528&quot; data-origin-height=&quot;843&quot; style=&quot;width: 49.4186%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cbLf0I/btqUvDDigwM/93Yhi03oDer2D9f6EPivt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcbLf0I%2FbtqUvDDigwM%2F93Yhi03oDer2D9f6EPivt1%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;1528&quot; height=&quot;843&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;등록이 완료되면 로그인 후 다음과 같이 접속할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Bamboo 설치&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Bamboo를 설치하기 위해 다운로드 사이트에 접속한다. &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;/span&gt;&lt;a href=&quot;https://www.atlassian.com/software/bitbucket/download&quot;&gt;https://www.atlassian.com/software/bamboo/download&lt;/a&gt;)&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tVibc/btqUtpMDYTM/SPa9Ka1jrpALER4SJROD7K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tVibc/btqUtpMDYTM/SPa9Ka1jrpALER4SJROD7K/img.png&quot; data-filename=&quot;3-1. Bamboo download.PNG&quot; data-origin-width=&quot;1528&quot; data-origin-height=&quot;843&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tVibc/btqUtpMDYTM/SPa9Ka1jrpALER4SJROD7K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtVibc%2FbtqUtpMDYTM%2FSPa9Ka1jrpALER4SJROD7K%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;1528&quot; height=&quot;843&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhcFYx/btqUsdexJb3/mA8IZoMxjXZNmEkVuu92lK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhcFYx/btqUsdexJb3/mA8IZoMxjXZNmEkVuu92lK/img.png&quot; data-filename=&quot;3-3. Bamboo download.PNG&quot; data-origin-width=&quot;1528&quot; data-origin-height=&quot;843&quot; style=&quot;width: 49.4186%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhcFYx/btqUsdexJb3/mA8IZoMxjXZNmEkVuu92lK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhcFYx%2FbtqUsdexJb3%2FmA8IZoMxjXZNmEkVuu92lK%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;1528&quot; height=&quot;843&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; 다운로드 받은&amp;nbsp;&lt;a href=&quot;http://atlassian-bamboo-7.2.2.tar.gz&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;atlassian-bamboo-7.2.2.tar.gz&lt;/a&gt;&amp;nbsp;Linux 서버에 업로드&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; 압축 해제 후 설정 작업 진행 (다운로드 받은 압축파일 해제 및 bamboo-home 디렉토리 생성)&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1611417965275&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[atlassian-bamboo/WEB-INF/classes/bamboo-init.properties]
...
bamboo.home=/root/atlassian/bamboo-home
...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;- bamboo-home 지정&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; atlassian-bamboo-7.2.2/bin/start-bamboo.sh&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1611418374962&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-123-141 bin]# sh start-bamboo.sh 

To run Bamboo in the foreground, start the server with start-bamboo.sh -fg

Server startup logs are located in /root/atlassian/atlassian-bamboo-7.2.2/bin/logs/catalina.out

Bamboo Server Edition
   Version : 7.2.2
                  

If you encounter issues starting or stopping Bamboo Server, please see the Troubleshooting guide at https://confluence.atlassian.com/display/BAMBOO/Installing+and+upgrading+Bamboo

Using CATALINA_BASE:   /root/atlassian/atlassian-bamboo-7.2.2
Using CATALINA_HOME:   /root/atlassian/atlassian-bamboo-7.2.2
Using CATALINA_TMPDIR: /root/atlassian/atlassian-bamboo-7.2.2/temp
Using JRE_HOME:        /usr
Using CLASSPATH:       /root/atlassian/atlassian-bamboo-7.2.2/bin/bootstrap.jar:/root/atlassian/atlassian-bamboo-7.2.2/bin/tomcat-juli.jar
Tomcat started.
[root@ip-192-168-123-141 bin]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; Bamboo License Download&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mUu8V/btqUpaPXGwd/IrlKMru0Y53csiKP6e8t80/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mUu8V/btqUpaPXGwd/IrlKMru0Y53csiKP6e8t80/img.png&quot; data-filename=&quot;4-1. Bamboo 체험판라이센스.PNG&quot; data-origin-width=&quot;1528&quot; data-origin-height=&quot;843&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mUu8V/btqUpaPXGwd/IrlKMru0Y53csiKP6e8t80/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmUu8V%2FbtqUpaPXGwd%2FIrlKMru0Y53csiKP6e8t80%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;1528&quot; height=&quot;843&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/beWCbj/btqUo9wJsbN/budyjAuPKeGCZ82uLNemQk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/beWCbj/btqUo9wJsbN/budyjAuPKeGCZ82uLNemQk/img.png&quot; data-filename=&quot;4-2. Bamboo 체험판라이센스.PNG&quot; data-origin-width=&quot;1528&quot; data-origin-height=&quot;843&quot; style=&quot;width: 49.4186%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/beWCbj/btqUo9wJsbN/budyjAuPKeGCZ82uLNemQk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbeWCbj%2FbtqUo9wJsbN%2FbudyjAuPKeGCZ82uLNemQk%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;1528&quot; height=&quot;843&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; 다운로드 받은 라이센스 적용 후 대시보드 로그인&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LUFht/btqUwyhugKc/5jwf4tNFUDDhHDF4k6nZm0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LUFht/btqUwyhugKc/5jwf4tNFUDDhHDF4k6nZm0/img.png&quot; data-filename=&quot;5-1. Bamboo Use.PNG&quot; data-origin-width=&quot;1528&quot; data-origin-height=&quot;843&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LUFht/btqUwyhugKc/5jwf4tNFUDDhHDF4k6nZm0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLUFht%2FbtqUwyhugKc%2F5jwf4tNFUDDhHDF4k6nZm0%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;1528&quot; height=&quot;843&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k4hEk/btqUwyaI26n/72rkMH7jxehrf08JKfkWNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k4hEk/btqUwyaI26n/72rkMH7jxehrf08JKfkWNK/img.png&quot; data-filename=&quot;5-2. Bamboo Use.PNG&quot; data-origin-width=&quot;1528&quot; data-origin-height=&quot;843&quot; style=&quot;width: 49.4186%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k4hEk/btqUwyaI26n/72rkMH7jxehrf08JKfkWNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk4hEk%2FbtqUwyaI26n%2F72rkMH7jxehrf08JKfkWNK%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;1528&quot; height=&quot;843&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Bamboo Executables&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; Bamboo Executables 구성 (Administration - Excutables)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;6-1. Bamboo Executable.PNG&quot; data-origin-width=&quot;1528&quot; data-origin-height=&quot;843&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4RrZY/btqW1sz1vD0/h8OekNHA8vRsypfQ2rhc60/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4RrZY/btqW1sz1vD0/h8OekNHA8vRsypfQ2rhc60/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4RrZY/btqW1sz1vD0/h8OekNHA8vRsypfQ2rhc60/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4RrZY%2FbtqW1sz1vD0%2Fh8OekNHA8vRsypfQ2rhc60%2Fimg.png&quot; data-filename=&quot;6-1. Bamboo Executable.PNG&quot; data-origin-width=&quot;1528&quot; data-origin-height=&quot;843&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;구성에 필요한 모듈을 등록한다. (Maven을 등록하였으며, 필요 시 SVN, Gradle 등을 추가로 등록할 수 있음)&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Application Link&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;다양한 소스 형상관리 도구와 Bamboo를 연결하여 사용할 수 있지만, Atlassian 계열의 Bitbucket과 Bamboo를 연결하여 구성해 보도록 하자.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;Bitbucket과 Bamboo를 연결하기 위해서 각각 Application Link를 등록해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; Bitbucket Application Link&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;(Administration - Application Links)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1Mykm/btqW1s7TBb5/JGZ1sAZI2sJMR5MPTAUtU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1Mykm/btqW1s7TBb5/JGZ1sAZI2sJMR5MPTAUtU1/img.png&quot; style=&quot;width:NaN%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1Mykm/btqW1s7TBb5/JGZ1sAZI2sJMR5MPTAUtU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1Mykm%2FbtqW1s7TBb5%2FJGZ1sAZI2sJMR5MPTAUtU1%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/D2lyY/btqXgo4kSOO/50JkqcytBUON0SnOEBA7bK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/D2lyY/btqXgo4kSOO/50JkqcytBUON0SnOEBA7bK/img.png&quot; style=&quot;width:NaN%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/D2lyY/btqXgo4kSOO/50JkqcytBUON0SnOEBA7bK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FD2lyY%2FbtqXgo4kSOO%2F50JkqcytBUON0SnOEBA7bK%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cDm6U9/btqW8Gdno5j/Rgqeyksfrd76bsVOUnY8y1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cDm6U9/btqW8Gdno5j/Rgqeyksfrd76bsVOUnY8y1/img.png&quot; style=&quot;width:NaN%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cDm6U9/btqW8Gdno5j/Rgqeyksfrd76bsVOUnY8y1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcDm6U9%2FbtqW8Gdno5j%2FRgqeyksfrd76bsVOUnY8y1%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Configure Application Links에 Bamboo URL을 입력하고 Create new link를 선택한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AWo6Q/btqXj8UpWl4/E8a4ZkvhbO8M1cajlkiGjk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AWo6Q/btqXj8UpWl4/E8a4ZkvhbO8M1cajlkiGjk/img.png&quot; style=&quot;width:NaN%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AWo6Q/btqXj8UpWl4/E8a4ZkvhbO8M1cajlkiGjk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAWo6Q%2FbtqXj8UpWl4%2FE8a4ZkvhbO8M1cajlkiGjk%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MMtek/btqXgoJ0nXO/anFERpXuoq8bhK6JSbYKX1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MMtek/btqXgoJ0nXO/anFERpXuoq8bhK6JSbYKX1/img.png&quot; style=&quot;width:NaN%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MMtek/btqXgoJ0nXO/anFERpXuoq8bhK6JSbYKX1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMMtek%2FbtqXgoJ0nXO%2FanFERpXuoq8bhK6JSbYKX1%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;위와 같이 Bitbucket의 Application Link 만으로는 연결을 완료할 수 없다. Bamboo 역시 Bitbucket에 대한 Application Link를 생성하고 등록해 주어야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;gt; Bamboo Application Link&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;(Administration - Application Links)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d0Xo4x/btqW4hLLLHY/BLsajEN6pwy79bJssRt9XK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d0Xo4x/btqW4hLLLHY/BLsajEN6pwy79bJssRt9XK/img.png&quot; style=&quot;width:NaN%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d0Xo4x/btqW4hLLLHY/BLsajEN6pwy79bJssRt9XK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd0Xo4x%2FbtqW4hLLLHY%2FBLsajEN6pwy79bJssRt9XK%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Yq4ft/btqWX5E6fEW/igJwPq1VMakwyg2EJ7gDvk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Yq4ft/btqWX5E6fEW/igJwPq1VMakwyg2EJ7gDvk/img.png&quot; style=&quot;width:NaN%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Yq4ft/btqWX5E6fEW/igJwPq1VMakwyg2EJ7gDvk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYq4ft%2FbtqWX5E6fEW%2FigJwPq1VMakwyg2EJ7gDvk%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/N3MlQ/btqXb1axtbw/Ktr10XkIjQOYXcuOLVbcq0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/N3MlQ/btqXb1axtbw/Ktr10XkIjQOYXcuOLVbcq0/img.png&quot; style=&quot;width:NaN%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/N3MlQ/btqXb1axtbw/Ktr10XkIjQOYXcuOLVbcq0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FN3MlQ%2FbtqXb1axtbw%2FKtr10XkIjQOYXcuOLVbcq0%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;위와 같이 Bamboo의 Application Link를 추가한 후 CONFIG ERROR를 확인한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/czKbvL/btqXgoDf5lz/HGiuPhpDWshAL5Gan2rlKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/czKbvL/btqXgoDf5lz/HGiuPhpDWshAL5Gan2rlKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/czKbvL/btqXgoDf5lz/HGiuPhpDWshAL5Gan2rlKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FczKbvL%2FbtqXgoDf5lz%2FHGiuPhpDWshAL5Gan2rlKk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;위와 같이 [CONFIG ERROR] OAuth mismatch가 나타날 경우 Bitbucket과 Bamboo의 OAuth를 변경하고 적용한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c4xVjF/btqWX47fLf3/LFDUQLxgVontJlPGflRRak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c4xVjF/btqWX47fLf3/LFDUQLxgVontJlPGflRRak/img.png&quot; style=&quot;width:NaN%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c4xVjF/btqWX47fLf3/LFDUQLxgVontJlPGflRRak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc4xVjF%2FbtqWX47fLf3%2FLFDUQLxgVontJlPGflRRak%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXg12e/btqXgnEmBsa/6K26FqiI7KEIpkudp8p9fk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXg12e/btqXgnEmBsa/6K26FqiI7KEIpkudp8p9fk/img.png&quot; style=&quot;width:NaN%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXg12e/btqXgnEmBsa/6K26FqiI7KEIpkudp8p9fk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXg12e%2FbtqXgnEmBsa%2F6K26FqiI7KEIpkudp8p9fk%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;각각 Bitbucket과 Bamboo의 Outgoing/Incoming Authentication 방식을 OAuth로 변경 후 Save Chages를 선택한다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;인증설정이 완료되면, 다음과 같이 CONNECTED 상태로 변경되는 것을 확인할 수 있을 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9PA6d/btqWXbFy457/uNz8hyQ6y5AijGkKGeq0Pk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9PA6d/btqWXbFy457/uNz8hyQ6y5AijGkKGeq0Pk/img.png&quot; style=&quot;width:NaN%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9PA6d/btqWXbFy457/uNz8hyQ6y5AijGkKGeq0Pk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9PA6d%2FbtqWXbFy457%2FuNz8hyQ6y5AijGkKGeq0Pk%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IZmj3/btqW8GYLvRu/XCg5DTcxScbhOK2X27ZTzk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IZmj3/btqW8GYLvRu/XCg5DTcxScbhOK2X27ZTzk/img.png&quot; style=&quot;width:NaN%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IZmj3/btqW8GYLvRu/XCg5DTcxScbhOK2X27ZTzk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIZmj3%2FbtqW8GYLvRu%2FXCg5DTcxScbhOK2X27ZTzk%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Bitbucket Project &amp;amp; Repository&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; Create project&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zPhTs/btqWX40Ac7s/t9lKkOEi0ZsXeJ2SASoN4K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zPhTs/btqWX40Ac7s/t9lKkOEi0ZsXeJ2SASoN4K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zPhTs/btqWX40Ac7s/t9lKkOEi0ZsXeJ2SASoN4K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzPhTs%2FbtqWX40Ac7s%2Ft9lKkOEi0ZsXeJ2SASoN4K%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Repository를 관리할 Project를 생성한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/db5yWM/btqW4hyg0Zb/9edkhIN82dnKSUkq3XgZP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/db5yWM/btqW4hyg0Zb/9edkhIN82dnKSUkq3XgZP1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/db5yWM/btqW4hyg0Zb/9edkhIN82dnKSUkq3XgZP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdb5yWM%2FbtqW4hyg0Zb%2F9edkhIN82dnKSUkq3XgZP1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;- Project name : 프로젝트 이름&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;- Project key : 자동 생성&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;- Description : 상세 프로젝트 정보&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;- Create Project 선택&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; Create Repository&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgAMX6/btqXj87YCMk/2Eu0tW5EQvKhTcwruhLFF0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgAMX6/btqXj87YCMk/2Eu0tW5EQvKhTcwruhLFF0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgAMX6/btqXj87YCMk/2Eu0tW5EQvKhTcwruhLFF0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcgAMX6%2FbtqXj87YCMk%2F2Eu0tW5EQvKhTcwruhLFF0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;생성한 Project의 Repository를 생성한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Eqe0t/btqWW9VgFOH/xI1dwWBiORh9X0EFuXDGCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Eqe0t/btqWW9VgFOH/xI1dwWBiORh9X0EFuXDGCk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Eqe0t/btqWW9VgFOH/xI1dwWBiORh9X0EFuXDGCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEqe0t%2FbtqWW9VgFOH%2FxI1dwWBiORh9X0EFuXDGCk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;- Name : Repository 이름&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;- Default branch name : Branch 이름&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;- Create repository 선택&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; Repository Source Push&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Pb482/btqXj699GFK/AsPklXc4KheNsqqWewiSk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Pb482/btqXj699GFK/AsPklXc4KheNsqqWewiSk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Pb482/btqXj699GFK/AsPklXc4KheNsqqWewiSk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPb482%2FbtqXj699GFK%2FAsPklXc4KheNsqqWewiSk0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;생성된 Repository에 아래와 같이 Sample Application을 Push한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcEBJb/btqW8GEtlAl/yBTdoMw7hmzGgSuuUMmnNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcEBJb/btqW8GEtlAl/yBTdoMw7hmzGgSuuUMmnNK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcEBJb/btqW8GEtlAl/yBTdoMw7hmzGgSuuUMmnNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcEBJb%2FbtqW8GEtlAl%2FyBTdoMw7hmzGgSuuUMmnNK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;아래와 같이 Repository에 소스코드가 Push 된 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bz5g2G/btqW1smxbof/RYugryfoGrwnDYFOKRZi6K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bz5g2G/btqW1smxbof/RYugryfoGrwnDYFOKRZi6K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bz5g2G/btqW1smxbof/RYugryfoGrwnDYFOKRZi6K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbz5g2G%2FbtqW1smxbof%2FRYugryfoGrwnDYFOKRZi6K%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Bitbucket 역시 GitHub, GitLab과 같은 Git Repository와 동일한 형태로 Git 기반의 저장소이다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Linked Repositories&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;gt; Bamboo Linked Repositories&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;(Administration - Linked repositories)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9SVLY/btqWX4zsex6/8DGh0riTUAhkMIPac10aL0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9SVLY/btqWX4zsex6/8DGh0riTUAhkMIPac10aL0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9SVLY/btqWX4zsex6/8DGh0riTUAhkMIPac10aL0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9SVLY%2FbtqWX4zsex6%2F8DGh0riTUAhkMIPac10aL0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; Add repository - Bitbucket Server / Stash&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBXLZY/btqXj8fPNIM/FywkeBru9itroDMWbxBI5K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBXLZY/btqXj8fPNIM/FywkeBru9itroDMWbxBI5K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBXLZY/btqXj8fPNIM/FywkeBru9itroDMWbxBI5K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBXLZY%2FbtqXj8fPNIM%2FFywkeBru9itroDMWbxBI5K%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&amp;gt; Bitbucket Repository 연결 (Name / Login &amp;amp; approve)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/byr87B/btqXocbaOUQ/n6epeZHjzz9TKehAYc8adk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/byr87B/btqXocbaOUQ/n6epeZHjzz9TKehAYc8adk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/byr87B/btqXocbaOUQ/n6epeZHjzz9TKehAYc8adk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbyr87B%2FbtqXocbaOUQ%2Fn6epeZHjzz9TKehAYc8adk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Login &amp;amp; Approve를 진행하면, 아래와 같이 Bitbucket에 생성한 Repository와 Branch를 선택할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cyLDB8/btqXb1O60Lh/TklfkHaIVAtWRKpCaWkza0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cyLDB8/btqXb1O60Lh/TklfkHaIVAtWRKpCaWkza0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cyLDB8/btqXb1O60Lh/TklfkHaIVAtWRKpCaWkza0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcyLDB8%2FbtqXb1O60Lh%2FTklfkHaIVAtWRKpCaWkza0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;- Name : Bitbucket Repository Name을 구분하는 이름&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;- Server : Bitbucket&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;- Repository : [REPOSITORY]/[PROJECT]&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;- Branch : [BRANCH]&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;- Save repository 선택&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bae8iY/btqW1tyWkMo/s8ZkPbIGYYEsEZ99ENTCck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bae8iY/btqW1tyWkMo/s8ZkPbIGYYEsEZ99ENTCck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bae8iY/btqW1tyWkMo/s8ZkPbIGYYEsEZ99ENTCck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbae8iY%2FbtqW1tyWkMo%2Fs8ZkPbIGYYEsEZ99ENTCck%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;위와 같이 정상정으로 Bitbucket Repository와 연결된 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;다음 포스팅에서는 Bamboo의 빌드/배포 프로세스에 대해 알아보고, Amazon EKS에 배포하는 방법에 대해 알아보자.&lt;/span&gt;&lt;/p&gt;</description>
      <category>⑤ 개발, 데이터베이스/ⓒ CI CD</category>
      <category>Application Links</category>
      <category>Atlassian</category>
      <category>atlassian license</category>
      <category>bamboo bitbucket 연동</category>
      <category>Bitbucket</category>
      <category>Linked Repository</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/685</guid>
      <comments>https://waspro.tistory.com/685#entry685comment</comments>
      <pubDate>Sun, 24 Jan 2021 01:21:25 +0900</pubDate>
    </item>
    <item>
      <title>Kubeflow를 활용하여 머신러닝 분석환경 구축하기</title>
      <link>https://waspro.tistory.com/684</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Kubeflow 란?&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Kubeflow는 Kubernetes 환경에서 머신러닝을 분석할 수 있는 오픈소스 기계 학습 플랫폼이다. Kubeflow를 이용하면, 손쉽게 분석환경을 구축할 수 있으며, 직접 커스터마이징한 이미지를 구동하여 접속할 수 있는 대시보드 환경을 제공한다.&amp;nbsp;kubeflow가 제공하는 다양한 기능에 대해서는 하나씩 구축해 나가면서 알아보기로 하자.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Minimum system requirements&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;먼저 Kubeflow 구축 과정이다. 앞서 이야기한데로 Kubeflow가 구성되기 위해서는 Kubernetes 환경이 사전에 구축되어 있어야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/D8q4E/btqT8HZXW6S/bGw8OOREvn0VKob4gBV8LK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/D8q4E/btqT8HZXW6S/bGw8OOREvn0VKob4gBV8LK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/D8q4E/btqT8HZXW6S/bGw8OOREvn0VKob4gBV8LK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FD8q4E%2FbtqT8HZXW6S%2FbGw8OOREvn0VKob4gBV8LK%2Fimg.jpg&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;실제로 Kubeflow는 복잡한 시스템을 배포, 확장 및 관리하기 위해 Kubernetes를 기반환경으로 사용한다. Kubeflow는 Kubernetes 기반 서비스 제공하는 Public Cloud Managed Service와 On Prem, Local, Private Cloud 모든 환경에서 구성이 가능하다. 기본으로 다양한 Application 라이브러리와 스캐폴드 기술을 제공하며, 다양한 머신러닝 도구와 함께 동작할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;a. Kubernetes 호환 버전&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #006dd7;&quot;&gt;&lt;a style=&quot;color: #006dd7;&quot; href=&quot;https://www.kubeflow.org/docs/started/k8s/overview/&quot;&gt;kubeflow 공식 홈페이지 : &lt;/a&gt;&lt;a style=&quot;color: #006dd7;&quot; href=&quot;https://www.kubeflow.org/docs/started/k8s/overview/&quot;&gt;https://www.kubeflow.org/docs/started/k8s/overview/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rmRTv/btqT9Z6ZZZJ/MnzsplmgXpkk7bTtHIk2B0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rmRTv/btqT9Z6ZZZJ/MnzsplmgXpkk7bTtHIk2B0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rmRTv/btqT9Z6ZZZJ/MnzsplmgXpkk7bTtHIk2B0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrmRTv%2FbtqT9Z6ZZZJ%2FMnzsplmgXpkk7bTtHIk2B0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;현재 EKS가 제공하는 Kubernetes 버전은 1.17이며, 이는 Kubeflow 1.0 이상을 사용해야 호환 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;b. 권장 리소스 요구사항&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Kubernetes Worker 노드의 권고 리소스 요구사항은 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;4 CPU&lt;/span&gt;&lt;/li&gt;
&lt;li data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;12GB 메모리&lt;/span&gt;&lt;/li&gt;
&lt;li data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;50GB 저장공간&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;현재 본 테스트에서 사용하는 EKS Worker Node는 c5.2xlarge로 배포되어 있으며,&amp;nbsp;m5.large의 경우 CPU 부족으로 인해 Pod가 배치되지 않는 1 insufficient cpu, 1 insufficient pods와 같은 현상이 발생할 수 있으며, 추가적인 분석 도구 확장을 위해 c5.2xlarge 이상을 권고한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;# GPU 버전을 사용하고 싶을 경우 P2/P3 등의 EC2 인스턴스를 사용해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Kubeflow Install&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;kubeflow를 설치하기 위해서는 먼저 kubeflow cli 도구인 kfctl을 설치해야 한다. &lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;kfctl은 다음에서 다운로드 받을 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #006dd7;&quot;&gt;&lt;a style=&quot;color: #006dd7;&quot; href=&quot;https://github.com/kubeflow/kfctl/releases/tag/v1.2.0&quot;&gt;https://github.com/kubeflow/kfctl/releases/tag/v1.2.0&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;다운로드 받은 kfctl을 다음과 같이 압축을 해제하고 /usr/local/bin에 복사한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1611050151924&quot; class=&quot;java&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px;&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-114-198 kubeflow_install]# ls -la
total 30456
drwxr-xr-x  2 root root       50 Jan 19 07:47 .
dr-xr-x--- 17 root root     4096 Jan 19 07:46 ..
-rw-r--r--  1 root root 31181024 Jan 19 07:47 kfctl_v1.2.0-0-gbc038f9_linux.tar.gz
[root@ip-192-168-114-198 kubeflow_install]# tar -xzvf kfctl_v1.2.0-0-gbc038f9_linux.tar.gz 
./kfctl
[root@ip-192-168-114-198 kubeflow_install]# ./kfctl version
kfctl v1.2.0-0-gbc038f9
[root@ip-192-168-114-198 kubeflow_install]# cp kfctl /usr/local/bin/
[root@ip-192-168-114-198 kubeflow_install]# kfctl version
kfctl v1.2.0-0-gbc038f9
[root@ip-192-168-114-198 kubeflow_install]# &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;다음으로 kubeflow를 설치하기 위한 env를 해당 console에 직접 등록하거나, profile에 등록한 후 적용한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1611050151924&quot; class=&quot;java&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px;&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export KF_NAME=KFTest
export BASE_DIR=/root/kubeflow
export KF_DIR=${BASE_DIR}/${KF_NAME}
export CONFIG_URI=&quot;https://raw.githubusercontent.com/kubeflow/manifests/v1.1-branch/kfdef/kfctl_k8s_istio.v1.1.0.yaml&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;kfctl로 kubeflow를 설치하는 방법은 다음과 같다. 먼저 실행에 앞서 profile에 등록한 /root/kubeflow 하위에 KF_NAME으로 등록한 디렉토리를 생성한다. 이후 해당 경로로 이동하여 아래와 같은 명령어를 실행한다. 이때, 명령을 실행하는 디렉토리가 비어있어야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;kfctl apply -V -f ${CONFIG_URI} : -V 옵션은 Verbose이며, -f 옵션은 CONFIG_URI에 등록한 yaml 파일을 적용한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1611050151924&quot; class=&quot;java&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px;&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-114-198 KFTest]# kfctl apply -V -f ${CONFIG_URI}
INFO[0000] Downloading https://raw.githubusercontent.com/kubeflow/manifests/v1.1-branch/kfdef/kfctl_k8s_istio.v1.1.0.yaml to /tmp/767353531/tmp.yaml  filename=&quot;utils/k8utils.go:178&quot;
INFO[0000] Downloading https://raw.githubusercontent.com/kubeflow/manifests/v1.1-branch/kfdef/kfctl_k8s_istio.v1.1.0.yaml to /tmp/120901854/tmp_app.yaml  filename=&quot;loaders/loaders.go:71&quot;
INFO[0000] App directory /root/kubeflow/KFTest already exists  filename=&quot;coordinator/coordinator.go:270&quot;
INFO[0000] Writing KfDef to kfctl_k8s_istio.v1.1.0.yaml  filename=&quot;coordinator/coordinator.go:273&quot;
INFO[0000] No name specified in KfDef.Metadata.Name; defaulting to KFTest based on location of config file: /root/kubeflow/KFTest/kfctl_k8s_istio.v1.1.0.yaml.  filename=&quot;coordinator/coordinator.go:202&quot;
INFO[0000] 
****************************************************************
Notice anonymous usage reporting enabled using spartakus
To disable it
If you have already deployed it run the following commands:
  cd $(pwd)
  kubectl -n ${K8S_NAMESPACE} delete deploy -l app=spartakus

For more info: https://www.kubeflow.org/docs/other-guides/usage-reporting/
****************************************************************
  filename=&quot;coordinator/coordinator.go:120&quot;
INFO[0000] Creating directory /root/kubeflow/KFTest/.cache  filename=&quot;kfconfig/types.go:450&quot;
INFO[0000] Fetching https://github.com/kubeflow/manifests/archive/v1.1-branch.tar.gz to /root/kubeflow/KFTest/.cache/manifests  filename=&quot;kfconfig/types.go:498&quot;
INFO[0002] Updating localPath to /root/kubeflow/KFTest/.cache/manifests/manifests-1.1-branch  filename=&quot;kfconfig/types.go:569&quot;
INFO[0002] Fetch succeeded; LocalPath /root/kubeflow/KFTest/.cache/manifests/manifests-1.1-branch  filename=&quot;kfconfig/types.go:590&quot;
INFO[0002] Processing application: namespaces            filename=&quot;kustomize/kustomize.go:569&quot;
INFO[0002] Creating folder /root/kubeflow/KFTest/kustomize/namespaces  filename=&quot;kustomize/kustomize.go:667&quot;
INFO[0002] Processing application: application           filename=&quot;kustomize/kustomize.go:569&quot;
INFO[0002] Creating folder /root/kubeflow/KFTest/kustomize/application  filename=&quot;kustomize/kustomize.go:667&quot;
INFO[0002] Processing application: istio-stack           filename=&quot;kustomize/kustomize.go:569&quot;
INFO[0002] Creating folder /root/kubeflow/KFTest/kustomize/istio-stack  filename=&quot;kustomize/kustomize.go:667&quot;
INFO[0002] Processing application: cluster-local-gateway  filename=&quot;kustomize/kustomize.go:569&quot;
INFO[0002] Creating folder /root/kubeflow/KFTest/kustomize/cluster-local-gateway  filename=&quot;kustomize/kustomize.go:667&quot;
INFO[0002] Processing application: istio                 filename=&quot;kustomize/kustomize.go:569&quot;
INFO[0002] Creating folder /root/kubeflow/KFTest/kustomize/istio  filename=&quot;kustomize/kustomize.go:667&quot;
INFO[0002] Processing application: cert-manager-crds     filename=&quot;kustomize/kustomize.go:569&quot;
INFO[0002] Creating folder /root/kubeflow/KFTest/kustomize/cert-manager-crds  filename=&quot;kustomize/kustomize.go:667&quot;
INFO[0002] Processing application: cert-manager-kube-system-resources  filename=&quot;kustomize/kustomize.go:569&quot;
INFO[0002] Creating folder /root/kubeflow/KFTest/kustomize/cert-manager-kube-system-resources  filename=&quot;kustomize/kustomize.go:667&quot;
INFO[0002] Processing application: cert-manager          filename=&quot;kustomize/kustomize.go:569&quot;
INFO[0002] Creating folder /root/kubeflow/KFTest/kustomize/cert-manager  filename=&quot;kustomize/kustomize.go:667&quot;
INFO[0002] Processing application: add-anonymous-user-filter  filename=&quot;kustomize/kustomize.go:569&quot;
INFO[0002] Creating folder /root/kubeflow/KFTest/kustomize/add-anonymous-user-filter  filename=&quot;kustomize/kustomize.go:667&quot;
INFO[0002] Processing application: metacontroller        filename=&quot;kustomize/kustomize.go:569&quot;
INFO[0002] Creating folder /root/kubeflow/KFTest/kustomize/metacontroller  filename=&quot;kustomize/kustomize.go:667&quot;
INFO[0002] Processing application: bootstrap             filename=&quot;kustomize/kustomize.go:569&quot;
INFO[0002] Creating folder /root/kubeflow/KFTest/kustomize/bootstrap  filename=&quot;kustomize/kustomize.go:667&quot;
INFO[0002] Processing application: spark-operator        filename=&quot;kustomize/kustomize.go:569&quot;
INFO[0002] Creating folder /root/kubeflow/KFTest/kustomize/spark-operator  filename=&quot;kustomize/kustomize.go:667&quot;
INFO[0002] Processing application: kubeflow-apps         filename=&quot;kustomize/kustomize.go:569&quot;
INFO[0002] Creating folder /root/kubeflow/KFTest/kustomize/kubeflow-apps  filename=&quot;kustomize/kustomize.go:667&quot;
INFO[0002] Processing application: knative               filename=&quot;kustomize/kustomize.go:569&quot;
INFO[0002] Creating folder /root/kubeflow/KFTest/kustomize/knative  filename=&quot;kustomize/kustomize.go:667&quot;
INFO[0002] Processing application: kfserving             filename=&quot;kustomize/kustomize.go:569&quot;
INFO[0002] Creating folder /root/kubeflow/KFTest/kustomize/kfserving  filename=&quot;kustomize/kustomize.go:667&quot;
INFO[0002] Processing application: spartakus             filename=&quot;kustomize/kustomize.go:569&quot;
INFO[0002] Creating folder /root/kubeflow/KFTest/kustomize/spartakus  filename=&quot;kustomize/kustomize.go:667&quot;
INFO[0002] /root/kubeflow/KFTest/.cache/manifests exists; not resyncing   filename=&quot;kfconfig/types.go:473&quot;
INFO[0002] namespace: kubeflow                           filename=&quot;utils/k8utils.go:433&quot;
INFO[0002] Creating namespace: kubeflow                  filename=&quot;utils/k8utils.go:438&quot;
INFO[0002] Log cluster name into KfDef: NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io  filename=&quot;kustomize/kustomize.go:253&quot;
INFO[0002] Deploying application namespaces              filename=&quot;kustomize/kustomize.go:266&quot;
namespace/cert-manager created
Warning:  apply should be used on resource created by either  create --save-config or  apply
namespace/kubeflow configured
INFO[0003] Successfully applied application namespaces   filename=&quot;kustomize/kustomize.go:291&quot;
INFO[0003] Deploying application application             filename=&quot;kustomize/kustomize.go:266&quot;
serviceaccount/application-controller-service-account created
customresourcedefinition.apiextensions.k8s.io/applications.app.k8s.io created
clusterrole.rbac.authorization.k8s.io/application-controller-cluster-role created
clusterrolebinding.rbac.authorization.k8s.io/application-controller-cluster-role-binding created
service/application-controller-service created
statefulset.apps/application-controller-stateful-set created
application.app.k8s.io/application-controller-kubeflow created
INFO[0003] Successfully applied application application  filename=&quot;kustomize/kustomize.go:291&quot;
INFO[0003] Deploying application istio-stack             filename=&quot;kustomize/kustomize.go:266&quot;
namespace/istio-system created
configmap/istio created
configmap/istio-galley-configuration created
configmap/istio-security-custom-resources created
configmap/istio-sidecar-injector created
configmap/istio-install-parameters-5kmkd2f29g created
configmap/prometheus created
serviceaccount/istio-pilot-service-account created
serviceaccount/istio-security-post-install-account created
serviceaccount/istio-nodeagent-service-account created
serviceaccount/istio-multi created
serviceaccount/istio-mixer-service-account created
serviceaccount/istio-ingressgateway-service-account created
serviceaccount/prometheus created
serviceaccount/istio-citadel-service-account created
serviceaccount/istio-galley-service-account created
serviceaccount/istio-sidecar-injector-service-account created
customresourcedefinition.apiextensions.k8s.io/authorizationpolicies.rbac.istio.io created
customresourcedefinition.apiextensions.k8s.io/policies.authentication.istio.io created
customresourcedefinition.apiextensions.k8s.io/quotaspecbindings.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/quotaspecs.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/rbacconfigs.rbac.istio.io created
customresourcedefinition.apiextensions.k8s.io/rules.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/serviceentries.networking.istio.io created
customresourcedefinition.apiextensions.k8s.io/meshpolicies.authentication.istio.io created
customresourcedefinition.apiextensions.k8s.io/serviceroles.rbac.istio.io created
customresourcedefinition.apiextensions.k8s.io/sidecars.networking.istio.io created
customresourcedefinition.apiextensions.k8s.io/templates.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/virtualservices.networking.istio.io created
customresourcedefinition.apiextensions.k8s.io/issuers.certmanager.k8s.io created
customresourcedefinition.apiextensions.k8s.io/clusterrbacconfigs.rbac.istio.io created
customresourcedefinition.apiextensions.k8s.io/httpapispecs.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/httpapispecbindings.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/handlers.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/gateways.networking.istio.io created
customresourcedefinition.apiextensions.k8s.io/envoyfilters.networking.istio.io created
customresourcedefinition.apiextensions.k8s.io/destinationrules.networking.istio.io created
customresourcedefinition.apiextensions.k8s.io/clusterissuers.certmanager.k8s.io created
customresourcedefinition.apiextensions.k8s.io/servicerolebindings.rbac.istio.io created
customresourcedefinition.apiextensions.k8s.io/challenges.certmanager.k8s.io created
customresourcedefinition.apiextensions.k8s.io/certificates.certmanager.k8s.io created
customresourcedefinition.apiextensions.k8s.io/adapters.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/instances.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/attributemanifests.config.istio.io created
customresourcedefinition.apiextensions.k8s.io/orders.certmanager.k8s.io created
clusterrole.rbac.authorization.k8s.io/istio-mixer-istio-system created
clusterrole.rbac.authorization.k8s.io/istio-reader created
clusterrole.rbac.authorization.k8s.io/istio-citadel-istio-system created
clusterrole.rbac.authorization.k8s.io/prometheus-istio-system created
clusterrole.rbac.authorization.k8s.io/istio-security-post-install-istio-system created
clusterrole.rbac.authorization.k8s.io/istio-nodeagent-istio-system created
clusterrole.rbac.authorization.k8s.io/istio-galley-istio-system created
clusterrole.rbac.authorization.k8s.io/istio-sidecar-injector-istio-system created
clusterrole.rbac.authorization.k8s.io/istio-pilot-istio-system created
clusterrolebinding.rbac.authorization.k8s.io/istio-mixer-admin-role-binding-istio-system created
clusterrolebinding.rbac.authorization.k8s.io/istio-nodeagent-istio-system created
clusterrolebinding.rbac.authorization.k8s.io/istio-galley-admin-role-binding-istio-system created
clusterrolebinding.rbac.authorization.k8s.io/istio-sidecar-injector-admin-role-binding-istio-system created
clusterrolebinding.rbac.authorization.k8s.io/istio-citadel-istio-system created
clusterrolebinding.rbac.authorization.k8s.io/istio-security-post-install-role-binding-istio-system created
clusterrolebinding.rbac.authorization.k8s.io/istio-multi created
clusterrolebinding.rbac.authorization.k8s.io/istio-pilot-istio-system created
clusterrolebinding.rbac.authorization.k8s.io/prometheus-istio-system created
role.rbac.authorization.k8s.io/istio-ingressgateway-sds created
rolebinding.rbac.authorization.k8s.io/istio-ingressgateway-sds created
service/istio-pilot created
service/istio-citadel created
service/istio-galley created
service/istio-ingressgateway created
service/istio-policy created
service/istio-sidecar-injector created
service/istio-telemetry created
service/prometheus created
daemonset.apps/istio-nodeagent created
deployment.apps/prometheus created
deployment.apps/istio-galley created
deployment.apps/istio-ingressgateway created
deployment.apps/istio-pilot created
deployment.apps/istio-policy created
deployment.apps/istio-citadel created
deployment.apps/istio-telemetry created
deployment.apps/istio-sidecar-injector created
job.batch/istio-security-post-install-release-1.3-latest-daily created
mutatingwebhookconfiguration.admissionregistration.k8s.io/istio-sidecar-injector created
destinationrule.networking.istio.io/istio-telemetry created
destinationrule.networking.istio.io/istio-policy created
horizontalpodautoscaler.autoscaling/istio-telemetry created
horizontalpodautoscaler.autoscaling/istio-ingressgateway created
horizontalpodautoscaler.autoscaling/istio-pilot created
horizontalpodautoscaler.autoscaling/istio-policy created
poddisruptionbudget.policy/istio-telemetry created
poddisruptionbudget.policy/istio-policy created
poddisruptionbudget.policy/istio-sidecar-injector created
poddisruptionbudget.policy/istio-ingressgateway created
poddisruptionbudget.policy/istio-galley created
poddisruptionbudget.policy/istio-pilot created
servicerole.rbac.istio.io/istio-ingressgateway created
servicerolebinding.rbac.istio.io/istio-ingressgateway created
attributemanifest.config.istio.io/kubernetes created
attributemanifest.config.istio.io/istioproxy created
handler.config.istio.io/kubernetesenv created
handler.config.istio.io/prometheus created
instance.config.istio.io/requestcount created
instance.config.istio.io/requestsize created
instance.config.istio.io/tcpbytereceived created
instance.config.istio.io/tcpconnectionsclosed created
instance.config.istio.io/requestduration created
instance.config.istio.io/responsesize created
instance.config.istio.io/attributes created
instance.config.istio.io/tcpconnectionsopened created
instance.config.istio.io/tcpbytesent created
rule.config.istio.io/promtcpconnectionopen created
rule.config.istio.io/tcpkubeattrgenrulerule created
rule.config.istio.io/promhttp created
rule.config.istio.io/kubeattrgenrulerule created
rule.config.istio.io/promtcpconnectionclosed created
rule.config.istio.io/promtcp created
INFO[0009] Successfully applied application istio-stack  filename=&quot;kustomize/kustomize.go:291&quot;
INFO[0009] Deploying application cluster-local-gateway   filename=&quot;kustomize/kustomize.go:266&quot;
namespace/istio-system configured
configmap/cluster-local-gateway-parameters-tbbdb2842d created
serviceaccount/cluster-local-gateway-service-account created
serviceaccount/istio-multi configured
clusterrole.rbac.authorization.k8s.io/istio-reader configured
clusterrolebinding.rbac.authorization.k8s.io/istio-multi configured
service/cluster-local-gateway created
deployment.apps/cluster-local-gateway created
horizontalpodautoscaler.autoscaling/cluster-local-gateway created
poddisruptionbudget.policy/cluster-local-gateway created
INFO[0010] Successfully applied application cluster-local-gateway  filename=&quot;kustomize/kustomize.go:291&quot;
INFO[0010] Deploying application istio                   filename=&quot;kustomize/kustomize.go:266&quot;
configmap/istio-parameters-cm9hckfgmb created
clusterrole.rbac.authorization.k8s.io/kubeflow-istio-admin created
clusterrole.rbac.authorization.k8s.io/kubeflow-istio-edit created
clusterrole.rbac.authorization.k8s.io/kubeflow-istio-view created
clusterrbacconfig.rbac.istio.io/default created
gateway.networking.istio.io/kubeflow-gateway created
serviceentry.networking.istio.io/google-api-entry created
serviceentry.networking.istio.io/google-storage-api-entry created
virtualservice.networking.istio.io/google-api-vs created
virtualservice.networking.istio.io/google-storage-api-vs created
virtualservice.networking.istio.io/grafana-vs created
INFO[0011] Successfully applied application istio        filename=&quot;kustomize/kustomize.go:291&quot;
INFO[0011] Deploying application cert-manager-crds       filename=&quot;kustomize/kustomize.go:266&quot;
customresourcedefinition.apiextensions.k8s.io/certificaterequests.cert-manager.io created
customresourcedefinition.apiextensions.k8s.io/certificates.cert-manager.io created
customresourcedefinition.apiextensions.k8s.io/challenges.acme.cert-manager.io created
customresourcedefinition.apiextensions.k8s.io/clusterissuers.cert-manager.io created
customresourcedefinition.apiextensions.k8s.io/issuers.cert-manager.io created
customresourcedefinition.apiextensions.k8s.io/orders.acme.cert-manager.io created
INFO[0012] Successfully applied application cert-manager-crds  filename=&quot;kustomize/kustomize.go:291&quot;
INFO[0012] Deploying application cert-manager-kube-system-resources  filename=&quot;kustomize/kustomize.go:266&quot;
configmap/cert-manager-kube-params-parameters created
role.rbac.authorization.k8s.io/cert-manager-cainjector:leaderelection created
role.rbac.authorization.k8s.io/cert-manager:leaderelection created
rolebinding.rbac.authorization.k8s.io/cert-manager-cainjector:leaderelection created
rolebinding.rbac.authorization.k8s.io/cert-manager-webhook:webhook-authentication-reader created
rolebinding.rbac.authorization.k8s.io/cert-manager:leaderelection created
INFO[0012] Successfully applied application cert-manager-kube-system-resources  filename=&quot;kustomize/kustomize.go:291&quot;
INFO[0012] Deploying application cert-manager            filename=&quot;kustomize/kustomize.go:266&quot;
namespace/cert-manager configured
configmap/cert-manager-parameters created
serviceaccount/cert-manager created
serviceaccount/cert-manager-cainjector created
serviceaccount/cert-manager-webhook created
clusterrole.rbac.authorization.k8s.io/cert-manager-webhook:webhook-requester created
clusterrole.rbac.authorization.k8s.io/cert-manager-view created
clusterrole.rbac.authorization.k8s.io/cert-manager-edit created
clusterrole.rbac.authorization.k8s.io/cert-manager-cainjector created
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-certificates created
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-challenges created
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-clusterissuers created
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-ingress-shim created
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-issuers created
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-orders created
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-webhook:auth-delegator created
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-cainjector created
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-challenges created
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-clusterissuers created
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-ingress-shim created
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-issuers created
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-orders created
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-certificates created
service/cert-manager created
service/cert-manager-webhook created
deployment.apps/cert-manager created
deployment.apps/cert-manager-cainjector created
deployment.apps/cert-manager-webhook created
mutatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook created
validatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook created
apiservice.apiregistration.k8s.io/v1beta1.webhook.cert-manager.io created
application.app.k8s.io/cert-manager created
WARN[0014] Encountered error applying application cert-manager:  (kubeflow.error): Code 500 with message: Apply.Run : error when creating &quot;/tmp/kout444800521&quot;: Internal error occurred: failed calling webhook &quot;webhook.cert-manager.io&quot;: the server could not find the requested resource  filename=&quot;kustomize/kustomize.go:284&quot;
WARN[0014] Will retry in 2 seconds.                      filename=&quot;kustomize/kustomize.go:285&quot;
namespace/cert-manager unchanged
configmap/cert-manager-parameters unchanged
serviceaccount/cert-manager unchanged
serviceaccount/cert-manager-cainjector unchanged
serviceaccount/cert-manager-webhook unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-webhook:webhook-requester unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-view unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-edit unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-cainjector unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-certificates unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-challenges unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-clusterissuers unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-ingress-shim unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-issuers unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-orders unchanged
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-webhook:auth-delegator configured
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-cainjector unchanged
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-challenges unchanged
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-clusterissuers unchanged
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-ingress-shim unchanged
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-issuers unchanged
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-orders unchanged
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-certificates unchanged
service/cert-manager unchanged
service/cert-manager-webhook unchanged
deployment.apps/cert-manager unchanged
deployment.apps/cert-manager-cainjector configured
deployment.apps/cert-manager-webhook configured
mutatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook configured
validatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook configured
apiservice.apiregistration.k8s.io/v1beta1.webhook.cert-manager.io unchanged
application.app.k8s.io/cert-manager configured
WARN[0017] Encountered error applying application cert-manager:  (kubeflow.error): Code 500 with message: Apply.Run : error when creating &quot;/tmp/kout493229370&quot;: Internal error occurred: failed calling webhook &quot;webhook.cert-manager.io&quot;: the server is currently unable to handle the request  filename=&quot;kustomize/kustomize.go:284&quot;
WARN[0017] Will retry in 4 seconds.                      filename=&quot;kustomize/kustomize.go:285&quot;
namespace/cert-manager unchanged
configmap/cert-manager-parameters unchanged
serviceaccount/cert-manager unchanged
serviceaccount/cert-manager-cainjector unchanged
serviceaccount/cert-manager-webhook unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-webhook:webhook-requester unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-view unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-edit unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-cainjector unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-certificates unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-challenges unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-clusterissuers unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-ingress-shim unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-issuers unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-orders unchanged
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-webhook:auth-delegator configured
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-cainjector unchanged
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-challenges unchanged
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-clusterissuers unchanged
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-ingress-shim unchanged
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-issuers unchanged
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-orders unchanged
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-certificates unchanged
service/cert-manager unchanged
service/cert-manager-webhook unchanged
deployment.apps/cert-manager unchanged
deployment.apps/cert-manager-cainjector configured
deployment.apps/cert-manager-webhook configured
mutatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook configured
validatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook configured
apiservice.apiregistration.k8s.io/v1beta1.webhook.cert-manager.io unchanged
application.app.k8s.io/cert-manager configured
WARN[0021] Encountered error applying application cert-manager:  (kubeflow.error): Code 500 with message: Apply.Run : error when creating &quot;/tmp/kout284290987&quot;: Internal error occurred: failed calling webhook &quot;webhook.cert-manager.io&quot;: the server is currently unable to handle the request  filename=&quot;kustomize/kustomize.go:284&quot;
WARN[0021] Will retry in 5 seconds.                      filename=&quot;kustomize/kustomize.go:285&quot;
namespace/cert-manager unchanged
configmap/cert-manager-parameters unchanged
serviceaccount/cert-manager unchanged
serviceaccount/cert-manager-cainjector unchanged
serviceaccount/cert-manager-webhook unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-webhook:webhook-requester unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-view unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-edit unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-cainjector unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-certificates unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-challenges unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-clusterissuers unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-ingress-shim unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-issuers unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-orders unchanged
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-webhook:auth-delegator configured
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-cainjector unchanged
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-challenges unchanged
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-clusterissuers unchanged
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-ingress-shim unchanged
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-issuers unchanged
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-orders unchanged
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-certificates unchanged
service/cert-manager unchanged
service/cert-manager-webhook unchanged
deployment.apps/cert-manager unchanged
deployment.apps/cert-manager-cainjector configured
deployment.apps/cert-manager-webhook configured
mutatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook configured
validatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook configured
apiservice.apiregistration.k8s.io/v1beta1.webhook.cert-manager.io unchanged
application.app.k8s.io/cert-manager configured
WARN[0027] Encountered error applying application cert-manager:  (kubeflow.error): Code 500 with message: Apply.Run : error when creating &quot;/tmp/kout048781168&quot;: Internal error occurred: failed calling webhook &quot;webhook.cert-manager.io&quot;: the server is currently unable to handle the request  filename=&quot;kustomize/kustomize.go:284&quot;
WARN[0027] Will retry in 8 seconds.                      filename=&quot;kustomize/kustomize.go:285&quot;
namespace/cert-manager unchanged
configmap/cert-manager-parameters unchanged
serviceaccount/cert-manager unchanged
serviceaccount/cert-manager-cainjector unchanged
serviceaccount/cert-manager-webhook unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-webhook:webhook-requester unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-view unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-edit unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-cainjector unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-certificates unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-challenges unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-clusterissuers unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-ingress-shim unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-issuers unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-orders unchanged
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-webhook:auth-delegator configured
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-cainjector unchanged
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-challenges unchanged
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-clusterissuers unchanged
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-ingress-shim unchanged
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-issuers unchanged
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-orders unchanged
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-certificates unchanged
service/cert-manager unchanged
service/cert-manager-webhook unchanged
deployment.apps/cert-manager unchanged
deployment.apps/cert-manager-cainjector configured
deployment.apps/cert-manager-webhook configured
mutatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook configured
validatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook configured
apiservice.apiregistration.k8s.io/v1beta1.webhook.cert-manager.io unchanged
application.app.k8s.io/cert-manager configured
WARN[0035] Encountered error applying application cert-manager:  (kubeflow.error): Code 500 with message: Apply.Run : error when creating &quot;/tmp/kout441774361&quot;: Internal error occurred: failed calling webhook &quot;webhook.cert-manager.io&quot;: the server is currently unable to handle the request  filename=&quot;kustomize/kustomize.go:284&quot;
WARN[0035] Will retry in 18 seconds.                     filename=&quot;kustomize/kustomize.go:285&quot;
namespace/cert-manager unchanged
configmap/cert-manager-parameters unchanged
serviceaccount/cert-manager unchanged
serviceaccount/cert-manager-cainjector unchanged
serviceaccount/cert-manager-webhook unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-webhook:webhook-requester unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-view unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-edit unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-cainjector unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-certificates unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-challenges unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-clusterissuers unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-ingress-shim unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-issuers unchanged
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-orders unchanged
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-webhook:auth-delegator configured
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-cainjector unchanged
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-challenges unchanged
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-clusterissuers unchanged
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-ingress-shim unchanged
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-issuers unchanged
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-orders unchanged
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-certificates unchanged
service/cert-manager unchanged
service/cert-manager-webhook unchanged
deployment.apps/cert-manager unchanged
deployment.apps/cert-manager-cainjector configured
deployment.apps/cert-manager-webhook configured
mutatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook configured
validatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook configured
apiservice.apiregistration.k8s.io/v1beta1.webhook.cert-manager.io unchanged
application.app.k8s.io/cert-manager configured
clusterissuer.cert-manager.io/kubeflow-self-signing-issuer created
INFO[0053] Successfully applied application cert-manager  filename=&quot;kustomize/kustomize.go:291&quot;
INFO[0053] Deploying application add-anonymous-user-filter  filename=&quot;kustomize/kustomize.go:266&quot;
envoyfilter.networking.istio.io/add-user-filter created
INFO[0053] Successfully applied application add-anonymous-user-filter  filename=&quot;kustomize/kustomize.go:291&quot;
INFO[0053] Deploying application metacontroller          filename=&quot;kustomize/kustomize.go:266&quot;
serviceaccount/meta-controller-service created
customresourcedefinition.apiextensions.k8s.io/compositecontrollers.metacontroller.k8s.io created
customresourcedefinition.apiextensions.k8s.io/controllerrevisions.metacontroller.k8s.io created
customresourcedefinition.apiextensions.k8s.io/decoratorcontrollers.metacontroller.k8s.io created
clusterrolebinding.rbac.authorization.k8s.io/meta-controller-cluster-role-binding created
statefulset.apps/metacontroller created
INFO[0053] Successfully applied application metacontroller  filename=&quot;kustomize/kustomize.go:291&quot;
INFO[0053] Deploying application bootstrap               filename=&quot;kustomize/kustomize.go:266&quot;
configmap/admission-webhook-bootstrap-config-map created
serviceaccount/admission-webhook-bootstrap-service-account created
clusterrole.rbac.authorization.k8s.io/admission-webhook-bootstrap-cluster-role created
clusterrolebinding.rbac.authorization.k8s.io/admission-webhook-bootstrap-cluster-role-binding created
statefulset.apps/admission-webhook-bootstrap-stateful-set created
application.app.k8s.io/bootstrap created
INFO[0054] Successfully applied application bootstrap    filename=&quot;kustomize/kustomize.go:291&quot;
INFO[0054] Deploying application spark-operator          filename=&quot;kustomize/kustomize.go:266&quot;
serviceaccount/spark-operatoroperator-sa created
serviceaccount/spark-operatorspark created
customresourcedefinition.apiextensions.k8s.io/scheduledsparkapplications.sparkoperator.k8s.io created
customresourcedefinition.apiextensions.k8s.io/sparkapplications.sparkoperator.k8s.io created
clusterrole.rbac.authorization.k8s.io/spark-operatoroperator-cr created
clusterrolebinding.rbac.authorization.k8s.io/spark-operatorsparkoperator-crb created
role.rbac.authorization.k8s.io/spark-operatorspark-role created
rolebinding.rbac.authorization.k8s.io/spark-operatorspark-role-binding created
deployment.apps/spark-operatorsparkoperator created
application.app.k8s.io/spark-operator created
INFO[0057] Successfully applied application spark-operator  filename=&quot;kustomize/kustomize.go:291&quot;
INFO[0057] Deploying application kubeflow-apps           filename=&quot;kustomize/kustomize.go:266&quot;
2021/01/19 08:13:12 nil value at `valueFrom.configMapKeyRef.name` ignored in mutation attempt
2021/01/19 08:13:12 nil value at `valueFrom.secretKeyRef.name` ignored in mutation attempt
secret/mysql-secret-fd5gktm75t created
secret/mlpipeline-minio-artifact created
secret/metadata-db-secrets created
secret/katib-mysql-secrets created
secret/katib-controller created
configmap/pipeline-api-server-config-f4t72426kt created
configmap/metadata-db-parameters created
configmap/metadata-grpc-configmap created
configmap/metadata-ui-parameters created
configmap/ml-pipeline-ui-configmap created
configmap/mpi-operator-config created
configmap/notebook-controller-notebook-controller-config-h4d668t5tb created
configmap/kubeflow-pipelines-profile-controller-env-mgh6th2gff created
configmap/pipeline-install-config-2829cc67f8 created
configmap/seldon-config created
configmap/trial-template created
configmap/trial-template-labeled created
configmap/workflow-controller-configmap created
configmap/jupyter-web-app-jupyter-web-app-config-dhcbh64467 created
configmap/workflow-controller-parameters created
configmap/kubeflow-pipelines-profile-controller-code-gd97t2m5f5 created
configmap/kubeflow-config created
configmap/katib-config created
configmap/admission-webhook-admission-webhook-parameters created
configmap/pipeline-upstream-install-config-c958fm776d created
configmap/profiles-profiles-config-4mgcmtgk6t created
persistentvolumeclaim/metadata-mysql created
persistentvolumeclaim/mysql-pv-claim created
persistentvolumeclaim/minio-pvc created
persistentvolumeclaim/katib-mysql created
serviceaccount/kubeflow-pipelines-metadata-writer created
serviceaccount/ml-pipeline-scheduledworkflow created
serviceaccount/ml-pipeline-ui created
serviceaccount/ml-pipeline-viewer-crd-service-account created
serviceaccount/ml-pipeline-visualizationserver created
serviceaccount/mpi-operator created
serviceaccount/mxnet-operator created
serviceaccount/notebook-controller-service-account created
serviceaccount/pipeline-runner created
serviceaccount/profiles-controller-service-account created
serviceaccount/pytorch-operator created
serviceaccount/seldon-manager created
serviceaccount/tf-job-dashboard created
serviceaccount/tf-job-operator created
serviceaccount/ml-pipeline-persistenceagent created
serviceaccount/ml-pipeline created
serviceaccount/kubeflow-pipelines-cache-deployer-sa created
serviceaccount/kubeflow-pipelines-cache created
serviceaccount/katib-ui created
serviceaccount/katib-controller created
serviceaccount/jupyter-web-app-service-account created
serviceaccount/centraldashboard created
serviceaccount/argo created
serviceaccount/admission-webhook-service-account created
serviceaccount/kubeflow-pipelines-container-builder created
serviceaccount/kubeflow-pipelines-viewer created
serviceaccount/metadata-ui created
serviceaccount/argo-ui created
customresourcedefinition.apiextensions.k8s.io/tfjobs.kubeflow.org created
customresourcedefinition.apiextensions.k8s.io/mxjobs.kubeflow.org created
customresourcedefinition.apiextensions.k8s.io/notebooks.kubeflow.org created
customresourcedefinition.apiextensions.k8s.io/poddefaults.kubeflow.org created
customresourcedefinition.apiextensions.k8s.io/profiles.kubeflow.org created
customresourcedefinition.apiextensions.k8s.io/pytorchjobs.kubeflow.org created
customresourcedefinition.apiextensions.k8s.io/scheduledworkflows.kubeflow.org created
customresourcedefinition.apiextensions.k8s.io/seldondeployments.machinelearning.seldon.io created
customresourcedefinition.apiextensions.k8s.io/mpijobs.kubeflow.org created
customresourcedefinition.apiextensions.k8s.io/suggestions.kubeflow.org created
customresourcedefinition.apiextensions.k8s.io/trials.kubeflow.org created
customresourcedefinition.apiextensions.k8s.io/viewers.kubeflow.org created
customresourcedefinition.apiextensions.k8s.io/workflows.argoproj.io created
customresourcedefinition.apiextensions.k8s.io/experiments.kubeflow.org created
clusterrole.rbac.authorization.k8s.io/katib-controller created
clusterrole.rbac.authorization.k8s.io/admission-webhook-cluster-role created
clusterrole.rbac.authorization.k8s.io/kubeflow-kubernetes-edit created
clusterrole.rbac.authorization.k8s.io/kubeflow-kubernetes-view created
clusterrole.rbac.authorization.k8s.io/kubeflow-mpijobs-admin created
clusterrole.rbac.authorization.k8s.io/kubeflow-mpijobs-edit created
clusterrole.rbac.authorization.k8s.io/kubeflow-mpijobs-view created
clusterrole.rbac.authorization.k8s.io/kubeflow-mxjobs-admin created
clusterrole.rbac.authorization.k8s.io/kubeflow-mxjobs-edit created
clusterrole.rbac.authorization.k8s.io/kubeflow-mxjobs-view created
clusterrole.rbac.authorization.k8s.io/kubeflow-pipelines-cache-deployer-clusterrole created
clusterrole.rbac.authorization.k8s.io/kubeflow-pipelines-cache-role created
clusterrole.rbac.authorization.k8s.io/kubeflow-pipelines-metadata-writer-role created
clusterrole.rbac.authorization.k8s.io/kubeflow-pytorchjobs-admin created
clusterrole.rbac.authorization.k8s.io/kubeflow-pytorchjobs-edit created
clusterrole.rbac.authorization.k8s.io/kubeflow-pytorchjobs-view created
clusterrole.rbac.authorization.k8s.io/kubeflow-tfjobs-admin created
clusterrole.rbac.authorization.k8s.io/kubeflow-tfjobs-edit created
clusterrole.rbac.authorization.k8s.io/kubeflow-tfjobs-view created
clusterrole.rbac.authorization.k8s.io/kubeflow-katib-view created
clusterrole.rbac.authorization.k8s.io/ml-pipeline-persistenceagent-role created
clusterrole.rbac.authorization.k8s.io/ml-pipeline-scheduledworkflow-role created
clusterrole.rbac.authorization.k8s.io/ml-pipeline-ui created
clusterrole.rbac.authorization.k8s.io/ml-pipeline-viewer-controller-role created
clusterrole.rbac.authorization.k8s.io/mpi-operator created
clusterrole.rbac.authorization.k8s.io/notebook-controller-kubeflow-notebooks-admin created
clusterrole.rbac.authorization.k8s.io/notebook-controller-kubeflow-notebooks-edit created
clusterrole.rbac.authorization.k8s.io/notebook-controller-kubeflow-notebooks-view created
clusterrole.rbac.authorization.k8s.io/notebook-controller-role created
clusterrole.rbac.authorization.k8s.io/seldon-manager-role-kubeflow created
clusterrole.rbac.authorization.k8s.io/kubeflow-view created
clusterrole.rbac.authorization.k8s.io/argo created
clusterrole.rbac.authorization.k8s.io/argo-ui created
clusterrole.rbac.authorization.k8s.io/ml-pipeline created
clusterrole.rbac.authorization.k8s.io/mxnet-operator created
clusterrole.rbac.authorization.k8s.io/pytorch-operator created
clusterrole.rbac.authorization.k8s.io/tf-job-operator created
clusterrole.rbac.authorization.k8s.io/kubeflow-katib-edit created
clusterrole.rbac.authorization.k8s.io/kubeflow-katib-admin created
clusterrole.rbac.authorization.k8s.io/kubeflow-edit created
clusterrole.rbac.authorization.k8s.io/kubeflow-admin created
clusterrole.rbac.authorization.k8s.io/seldon-manager-sas-role-kubeflow created
clusterrole.rbac.authorization.k8s.io/katib-ui created
clusterrole.rbac.authorization.k8s.io/jupyter-web-app-kubeflow-notebook-ui-view created
clusterrole.rbac.authorization.k8s.io/jupyter-web-app-kubeflow-notebook-ui-edit created
clusterrole.rbac.authorization.k8s.io/jupyter-web-app-kubeflow-notebook-ui-admin created
clusterrole.rbac.authorization.k8s.io/jupyter-web-app-cluster-role created
clusterrole.rbac.authorization.k8s.io/centraldashboard created
clusterrole.rbac.authorization.k8s.io/admission-webhook-kubeflow-poddefaults-view created
clusterrole.rbac.authorization.k8s.io/admission-webhook-kubeflow-poddefaults-edit created
clusterrole.rbac.authorization.k8s.io/kubeflow-kubernetes-admin created
clusterrole.rbac.authorization.k8s.io/admission-webhook-kubeflow-poddefaults-admin created
clusterrolebinding.rbac.authorization.k8s.io/jupyter-web-app-cluster-role-binding created
clusterrolebinding.rbac.authorization.k8s.io/katib-controller created
clusterrolebinding.rbac.authorization.k8s.io/katib-ui created
clusterrolebinding.rbac.authorization.k8s.io/centraldashboard created
clusterrolebinding.rbac.authorization.k8s.io/kubeflow-pipelines-cache-deployer-clusterrolebinding created
clusterrolebinding.rbac.authorization.k8s.io/kubeflow-pipelines-metadata-writer-binding created
clusterrolebinding.rbac.authorization.k8s.io/ml-pipeline-persistenceagent-binding created
clusterrolebinding.rbac.authorization.k8s.io/ml-pipeline-scheduledworkflow-binding created
clusterrolebinding.rbac.authorization.k8s.io/ml-pipeline-ui created
clusterrolebinding.rbac.authorization.k8s.io/ml-pipeline-viewer-crd-binding created
clusterrolebinding.rbac.authorization.k8s.io/admission-webhook-cluster-role-binding created
clusterrolebinding.rbac.authorization.k8s.io/notebook-controller-role-binding created
clusterrolebinding.rbac.authorization.k8s.io/profiles-cluster-role-binding created
clusterrolebinding.rbac.authorization.k8s.io/kubeflow-pipelines-cache-binding created
clusterrolebinding.rbac.authorization.k8s.io/seldon-manager-sas-rolebinding-kubeflow created
clusterrolebinding.rbac.authorization.k8s.io/argo created
clusterrolebinding.rbac.authorization.k8s.io/argo-ui created
clusterrolebinding.rbac.authorization.k8s.io/ml-pipeline created
clusterrolebinding.rbac.authorization.k8s.io/mxnet-operator created
clusterrolebinding.rbac.authorization.k8s.io/pytorch-operator created
clusterrolebinding.rbac.authorization.k8s.io/tf-job-operator created
clusterrolebinding.rbac.authorization.k8s.io/mpi-operator created
clusterrolebinding.rbac.authorization.k8s.io/seldon-manager-rolebinding-kubeflow created
role.rbac.authorization.k8s.io/metadata-ui created
role.rbac.authorization.k8s.io/kubeflow-pipelines-cache-role created
role.rbac.authorization.k8s.io/kubeflow-pipelines-metadata-writer-role created
role.rbac.authorization.k8s.io/ml-pipeline created
role.rbac.authorization.k8s.io/kubeflow-pipelines-cache-deployer-role created
role.rbac.authorization.k8s.io/ml-pipeline-scheduledworkflow-role created
role.rbac.authorization.k8s.io/centraldashboard created
role.rbac.authorization.k8s.io/ml-pipeline-ui created
role.rbac.authorization.k8s.io/ml-pipeline-viewer-controller-role created
role.rbac.authorization.k8s.io/pipeline-runner created
role.rbac.authorization.k8s.io/ml-pipeline-persistenceagent-role created
role.rbac.authorization.k8s.io/seldon-leader-election-role created
role.rbac.authorization.k8s.io/jupyter-web-app-jupyter-notebook-role created
rolebinding.rbac.authorization.k8s.io/kubeflow-pipelines-cache-deployer-rolebinding created
rolebinding.rbac.authorization.k8s.io/centraldashboard created
rolebinding.rbac.authorization.k8s.io/kubeflow-pipelines-cache-binding created
rolebinding.rbac.authorization.k8s.io/kubeflow-pipelines-metadata-writer-binding created
rolebinding.rbac.authorization.k8s.io/ml-pipeline created
rolebinding.rbac.authorization.k8s.io/ml-pipeline-persistenceagent-binding created
rolebinding.rbac.authorization.k8s.io/ml-pipeline-ui created
rolebinding.rbac.authorization.k8s.io/ml-pipeline-viewer-crd-binding created
rolebinding.rbac.authorization.k8s.io/pipeline-runner-binding created
rolebinding.rbac.authorization.k8s.io/seldon-leader-election-rolebinding created
rolebinding.rbac.authorization.k8s.io/jupyter-web-app-jupyter-notebook-role-binding created
rolebinding.rbac.authorization.k8s.io/metadata-ui created
rolebinding.rbac.authorization.k8s.io/ml-pipeline-scheduledworkflow-binding created
service/argo-ui created
service/centraldashboard created
service/jupyter-web-app-service created
service/katib-controller created
service/katib-db-manager created
service/katib-mysql created
service/katib-ui created
service/kubeflow-pipelines-profile-controller created
service/metadata-db created
service/metadata-envoy-service created
service/metadata-grpc-service created
service/metadata-service created
service/metadata-ui created
service/minio-service created
service/ml-pipeline created
service/cache-server created
service/ml-pipeline-visualizationserver created
service/admission-webhook-service created
service/notebook-controller-service created
service/profiles-kfam created
service/pytorch-operator created
service/seldon-webhook-service created
service/tf-job-operator created
service/mysql created
service/ml-pipeline-ui created
deployment.apps/cache-deployer-deployment created
deployment.apps/cache-server created
deployment.apps/centraldashboard created
deployment.apps/jupyter-web-app-deployment created
deployment.apps/katib-controller created
deployment.apps/katib-db-manager created
deployment.apps/katib-mysql created
deployment.apps/argo-ui created
deployment.apps/kubeflow-pipelines-profile-controller created
deployment.apps/metadata-db created
deployment.apps/metadata-deployment created
deployment.apps/metadata-envoy-deployment created
deployment.apps/admission-webhook-deployment created
deployment.apps/metadata-ui created
deployment.apps/metadata-writer created
deployment.apps/minio created
deployment.apps/ml-pipeline created
deployment.apps/ml-pipeline-persistenceagent created
deployment.apps/ml-pipeline-scheduledworkflow created
deployment.apps/ml-pipeline-ui created
deployment.apps/ml-pipeline-viewer-crd created
deployment.apps/katib-ui created
deployment.apps/mpi-operator created
deployment.apps/mxnet-operator created
deployment.apps/mysql created
deployment.apps/notebook-controller-deployment created
deployment.apps/profiles-deployment created
deployment.apps/pytorch-operator created
deployment.apps/seldon-controller-manager created
deployment.apps/tf-job-operator created
deployment.apps/workflow-controller created
deployment.apps/ml-pipeline-visualizationserver created
deployment.apps/metadata-grpc-deployment created
mutatingwebhookconfiguration.admissionregistration.k8s.io/seldon-mutating-webhook-configuration-kubeflow created
mutatingwebhookconfiguration.admissionregistration.k8s.io/admission-webhook-mutating-webhook-configuration created
validatingwebhookconfiguration.admissionregistration.k8s.io/seldon-validating-webhook-configuration-kubeflow created
application.app.k8s.io/profiles-profiles created
application.app.k8s.io/minio created
application.app.k8s.io/mpi-operator created
application.app.k8s.io/mxnet-operator created
application.app.k8s.io/mysql created
application.app.k8s.io/centraldashboard created
application.app.k8s.io/kubeflow-pipelines created
application.app.k8s.io/pytorch-job-crds created
application.app.k8s.io/pytorch-operator created
application.app.k8s.io/katib-crds created
application.app.k8s.io/katib-controller created
application.app.k8s.io/tf-job-operator created
application.app.k8s.io/webhook created
application.app.k8s.io/argo created
application.app.k8s.io/notebook-controller-notebook-controller created
application.app.k8s.io/jupyter-web-app-jupyter-web-app created
application.app.k8s.io/tf-job-crds created
application.app.k8s.io/seldon-core-operator created
certificate.cert-manager.io/seldon-serving-cert created
certificate.cert-manager.io/admission-webhook-cert created
compositecontroller.metacontroller.k8s.io/kubeflow-pipelines-profile-controller created
destinationrule.networking.istio.io/ml-pipeline-ui created
destinationrule.networking.istio.io/ml-pipeline-visualizationserver created
destinationrule.networking.istio.io/ml-pipeline created
destinationrule.networking.istio.io/ml-pipeline-mysql created
issuer.cert-manager.io/seldon-selfsigned-issuer created
servicerole.rbac.istio.io/ml-pipeline-ui created
servicerole.rbac.istio.io/cache-server created
servicerole.rbac.istio.io/ml-pipeline-services created
servicerolebinding.rbac.istio.io/bind-gateway-ml-pipeline-ui created
servicerolebinding.rbac.istio.io/bind-ml-pipeline-internal created
servicerolebinding.rbac.istio.io/bind-cache-server-admission-webhook created
virtualservice.networking.istio.io/profiles-kfam created
virtualservice.networking.istio.io/ml-pipeline-ui created
virtualservice.networking.istio.io/jupyter-web-app-jupyter-web-app created
virtualservice.networking.istio.io/centraldashboard created
virtualservice.networking.istio.io/argo-ui created
virtualservice.networking.istio.io/metadata-ui created
virtualservice.networking.istio.io/katib-ui created
virtualservice.networking.istio.io/metadata-grpc created
INFO[0074] Successfully applied application kubeflow-apps  filename=&quot;kustomize/kustomize.go:291&quot;
INFO[0074] Deploying application knative                 filename=&quot;kustomize/kustomize.go:266&quot;
namespace/knative-serving created
secret/webhook-certs created
configmap/config-tracing created
configmap/config-domain created
configmap/config-gc created
configmap/config-istio created
configmap/config-logging created
configmap/config-defaults created
configmap/config-network created
configmap/config-observability created
configmap/config-autoscaler created
configmap/config-deployment created
serviceaccount/controller created
customresourcedefinition.apiextensions.k8s.io/services.serving.knative.dev created
customresourcedefinition.apiextensions.k8s.io/serverlessservices.networking.internal.knative.dev created
customresourcedefinition.apiextensions.k8s.io/routes.serving.knative.dev created
customresourcedefinition.apiextensions.k8s.io/metrics.autoscaling.internal.knative.dev created
customresourcedefinition.apiextensions.k8s.io/ingresses.networking.internal.knative.dev created
customresourcedefinition.apiextensions.k8s.io/images.caching.internal.knative.dev created
customresourcedefinition.apiextensions.k8s.io/configurations.serving.knative.dev created
customresourcedefinition.apiextensions.k8s.io/certificates.networking.internal.knative.dev created
customresourcedefinition.apiextensions.k8s.io/podautoscalers.autoscaling.internal.knative.dev created
customresourcedefinition.apiextensions.k8s.io/revisions.serving.knative.dev created
clusterrole.rbac.authorization.k8s.io/knative-serving-podspecable-binding created
clusterrole.rbac.authorization.k8s.io/custom-metrics-server-resources created
clusterrole.rbac.authorization.k8s.io/knative-serving-addressable-resolver created
clusterrole.rbac.authorization.k8s.io/knative-serving-admin created
clusterrole.rbac.authorization.k8s.io/knative-serving-namespaced-view created
clusterrole.rbac.authorization.k8s.io/knative-serving-namespaced-edit created
clusterrole.rbac.authorization.k8s.io/knative-serving-namespaced-admin created
clusterrole.rbac.authorization.k8s.io/knative-serving-istio created
clusterrole.rbac.authorization.k8s.io/knative-serving-core created
clusterrolebinding.rbac.authorization.k8s.io/knative-serving-controller-admin created
clusterrolebinding.rbac.authorization.k8s.io/hpa-controller-custom-metrics created
clusterrolebinding.rbac.authorization.k8s.io/custom-metrics:system:auth-delegator created
rolebinding.rbac.authorization.k8s.io/custom-metrics-auth-reader created
service/controller created
service/activator-service created
service/autoscaler created
service/webhook created
deployment.apps/webhook created
deployment.apps/activator created
deployment.apps/autoscaler-hpa created
deployment.apps/controller created
deployment.apps/networking-istio created
deployment.apps/autoscaler created
mutatingwebhookconfiguration.admissionregistration.k8s.io/webhook.serving.knative.dev created
validatingwebhookconfiguration.admissionregistration.k8s.io/config.webhook.serving.knative.dev created
validatingwebhookconfiguration.admissionregistration.k8s.io/validation.webhook.serving.knative.dev created
apiservice.apiregistration.k8s.io/v1beta1.custom.metrics.k8s.io created
application.app.k8s.io/knative-serving-crds created
application.app.k8s.io/knative-serving-install created
gateway.networking.istio.io/cluster-local-gateway created
horizontalpodautoscaler.autoscaling/activator created
image.caching.internal.knative.dev/queue-proxy created
servicerole.rbac.istio.io/istio-service-role created
servicerolebinding.rbac.istio.io/istio-service-role-binding created
INFO[0078] Successfully applied application knative      filename=&quot;kustomize/kustomize.go:291&quot;
INFO[0078] Deploying application kfserving               filename=&quot;kustomize/kustomize.go:266&quot;
secret/kfserving-webhook-server-secret created
configmap/inferenceservice-config created
configmap/kfserving-config created
customresourcedefinition.apiextensions.k8s.io/inferenceservices.serving.kubeflow.org created
clusterrole.rbac.authorization.k8s.io/kfserving-proxy-role created
clusterrole.rbac.authorization.k8s.io/kubeflow-kfserving-view created
clusterrole.rbac.authorization.k8s.io/manager-role created
clusterrole.rbac.authorization.k8s.io/kubeflow-kfserving-admin created
clusterrole.rbac.authorization.k8s.io/kubeflow-kfserving-edit created
clusterrolebinding.rbac.authorization.k8s.io/kfserving-proxy-rolebinding created
clusterrolebinding.rbac.authorization.k8s.io/manager-rolebinding created
service/kfserving-controller-manager-service created
service/kfserving-webhook-server-service created
service/kfserving-controller-manager-metrics-service created
statefulset.apps/kfserving-controller-manager created
mutatingwebhookconfiguration.admissionregistration.k8s.io/inferenceservice.serving.kubeflow.org created
validatingwebhookconfiguration.admissionregistration.k8s.io/inferenceservice.serving.kubeflow.org created
application.app.k8s.io/kfserving created
application.app.k8s.io/kfserving-crds created
certificate.cert-manager.io/serving-cert created
issuer.cert-manager.io/selfsigned-issuer created
INFO[0083] Successfully applied application kfserving    filename=&quot;kustomize/kustomize.go:291&quot;
INFO[0083] Deploying application spartakus               filename=&quot;kustomize/kustomize.go:266&quot;
configmap/spartakus-config created
serviceaccount/spartakus created
clusterrole.rbac.authorization.k8s.io/spartakus created
clusterrolebinding.rbac.authorization.k8s.io/spartakus created
deployment.apps/spartakus-volunteer created
application.app.k8s.io/spartakus created
INFO[0084] Successfully applied application spartakus    filename=&quot;kustomize/kustomize.go:291&quot;
INFO[0084] Applied the configuration Successfully!       filename=&quot;cmd/apply.go:75&quot;
[root@ip-192-168-114-198 KFTest]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;설치는 이것으로 완료이다. 정상적으로 Kubeflow가 구축이 되면 다음과 같이 Pod 상태를 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1611050151924&quot; class=&quot;java&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px;&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-114-198 kustomize]# kubectl get pod -A
NAMESPACE         NAME                                                         READY   STATUS      RESTARTS   AGE
cert-manager      cert-manager-cainjector-774bd85548-qzsrw                     1/1     Running     0          6m56s
cert-manager      cert-manager-f8f6c65f9-b79cj                                 1/1     Running     0          6m56s
cert-manager      cert-manager-webhook-59fb566ff-r5kdt                         1/1     Running     1          6m56s
istio-system      cluster-local-gateway-79fd6955d7-6j2t5                       1/1     Running     0          6m58s
istio-system      istio-citadel-6c468575db-c7929                               1/1     Running     0          7m2s
istio-system      istio-galley-68c944d6b4-nv87p                                1/1     Running     0          7m2s
istio-system      istio-ingressgateway-85d57dc8bc-9qhzd                        1/1     Running     0          7m2s
istio-system      istio-nodeagent-2hx77                                        1/1     Running     0          7m3s
istio-system      istio-nodeagent-wr692                                        1/1     Running     0          7m3s
istio-system      istio-pilot-77bc8867cf-ss6g4                                 2/2     Running     0          7m2s
istio-system      istio-policy-59d86bdf79-5zn2l                                2/2     Running     1          7m2s
istio-system      istio-security-post-install-release-1.3-latest-daily-tv7rl   0/1     Completed   0          7m1s
istio-system      istio-sidecar-injector-6746558cb8-w2hh5                      1/1     Running     0          7m1s
istio-system      istio-telemetry-6854d9f564-f5jqn                             2/2     Running     1          7m2s
istio-system      prometheus-6b55759ff5-5r9np                                  1/1     Running     0          7m3s
knative-serving   activator-559f5c99bd-2lb7b                                   1/1     Running     0          5m51s
knative-serving   autoscaler-7f5b5d65dc-gf7jn                                  1/1     Running     0          5m50s
knative-serving   autoscaler-hpa-5f5fb77d99-ntl9s                              1/1     Running     0          5m51s
knative-serving   controller-5bf7fcf7dc-79w6v                                  1/1     Running     0          5m50s
knative-serving   networking-istio-6dcd5c7f7f-bfm4b                            1/1     Running     0          5m50s
knative-serving   webhook-84bb88bf75-7zmqf                                     1/1     Running     0          5m51s
kube-system       aws-node-b88st                                               1/1     Running     0          40m
kube-system       aws-node-p6f7s                                               1/1     Running     0          40m
kube-system       coredns-7dd7f84d9-tr2zb                                      1/1     Running     0          54m
kube-system       coredns-7dd7f84d9-z5b6c                                      1/1     Running     0          54m
kube-system       kube-proxy-5t9lb                                             1/1     Running     0          40m
kube-system       kube-proxy-smm7f                                             1/1     Running     0          40m
kubeflow          admission-webhook-bootstrap-stateful-set-0                   1/1     Running     1          6m15s
kubeflow          admission-webhook-deployment-5bc5f97cfd-g5jm2                1/1     Running     0          5m56s
kubeflow          application-controller-stateful-set-0                        1/1     Running     0          7m6s
kubeflow          argo-ui-669bcd8bfc-pv8pm                                     1/1     Running     0          5m57s
kubeflow          cache-deployer-deployment-b75f5c5f6-6t7sn                    2/2     Running     1          5m57s
kubeflow          cache-server-85bccd99bd-kk8fx                                2/2     Running     0          5m57s
kubeflow          centraldashboard-68965b5d89-xjzlv                            1/1     Running     0          5m57s
kubeflow          jupyter-web-app-deployment-5dfbb68956-ltmcl                  1/1     Running     0          5m57s
kubeflow          katib-controller-76b78f5db-96xpk                             1/1     Running     1          5m57s
kubeflow          katib-db-manager-67c9554b6d-fdrpf                            1/1     Running     2          5m57s
kubeflow          katib-mysql-5754b5dd66-xwwng                                 1/1     Running     0          5m57s
kubeflow          katib-ui-844b4fc655-f8n6z                                    1/1     Running     0          5m54s
kubeflow          kfserving-controller-manager-0                               2/2     Running     0          5m46s
kubeflow          kubeflow-pipelines-profile-controller-65b65d97bb-9gr7v       1/1     Running     0          5m56s
kubeflow          metacontroller-0                                             1/1     Running     0          6m15s
kubeflow          metadata-db-695fb6f55-x97bp                                  1/1     Running     0          5m56s
kubeflow          metadata-deployment-7d77b884b6-ps96k                         1/1     Running     0          5m56s
kubeflow          metadata-envoy-deployment-c5985d64b-mw2cj                    1/1     Running     0          5m56s
kubeflow          metadata-grpc-deployment-9fdb476-vd8d8                       1/1     Running     3          5m52s
kubeflow          metadata-ui-cf67fdb48-j249h                                  1/1     Running     0          5m55s
kubeflow          metadata-writer-59d755696c-cxt4n                             2/2     Running     0          5m55s
kubeflow          minio-6647564c5c-wx6ck                                       1/1     Running     0          5m55s
kubeflow          ml-pipeline-6bc56cd86d-fj5kk                                 2/2     Running     0          5m55s
kubeflow          ml-pipeline-persistenceagent-6f99b56974-pqbtr                2/2     Running     0          5m55s
kubeflow          ml-pipeline-scheduledworkflow-d596b8bd-92l26                 2/2     Running     0          5m54s
kubeflow          ml-pipeline-ui-8695cc6b46-r75fb                              2/2     Running     0          5m54s
kubeflow          ml-pipeline-viewer-crd-5998ff7f56-hw4nv                      2/2     Running     2          5m54s
kubeflow          ml-pipeline-visualizationserver-cbbb5b5b-lm4gb               2/2     Running     0          5m52s
kubeflow          mpi-operator-c747f5bf6-vs4w9                                 1/1     Running     0          5m54s
kubeflow          mxnet-operator-7cd59d475-nglks                               1/1     Running     0          5m53s
kubeflow          mysql-76597cf5b5-ldmzs                                       2/2     Running     0          5m53s
kubeflow          notebook-controller-deployment-756587d86-m9g46               1/1     Running     0          5m53s
kubeflow          profiles-deployment-65fcc9c97-tdz4b                          2/2     Running     0          5m53s
kubeflow          pytorch-operator-5db58565b-sl985                             1/1     Running     0          5m53s
kubeflow          seldon-controller-manager-6ddf664d54-sqwrm                   1/1     Running     0          5m52s
kubeflow          spark-operatorsparkoperator-85bbf89886-5kdwv                 1/1     Running     0          6m12s
kubeflow          spartakus-volunteer-7566cfd658-p9pc6                         1/1     Running     0          5m45s
kubeflow          tf-job-operator-5bf84768bf-27q2k                             1/1     Running     0          5m52s
kubeflow          workflow-controller-54dccb7dc4-59n7h                         1/1     Running     0          5m52s
[root@ip-192-168-114-198 kustomize]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Kubeflow는 총 4개의 Namespace를 생성한다. (istio-system, kubeflow, cert-manager, knative-serving)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dbPSrY/btqT6Id1pnc/h8kx7hfGwlK5my6C0IjP3K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dbPSrY/btqT6Id1pnc/h8kx7hfGwlK5my6C0IjP3K/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dbPSrY/btqT6Id1pnc/h8kx7hfGwlK5my6C0IjP3K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdbPSrY%2FbtqT6Id1pnc%2Fh8kx7hfGwlK5my6C0IjP3K%2Fimg.jpg&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 한눈에 봐도 많아 보이는 Pod들이 기동되고, 그 중 istio-ingressgateway를 통해 kubeflow 대시보드에 접근할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1611050151925&quot; class=&quot;java&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px;&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-114-198 KFTest]# kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name==&quot;http2&quot;)].nodePort}'
31380
[root@ip-192-168-114-198 KFTest]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 대시보드에 접근할 수 있는 NodePort를 확인할 수 있다. 물론 대시보드에 접근하기 위해 Service Type을 변경할 수 있으며, NodePort를 사용하더라도 직접 Worker Node에 접근이 가능하도록 보안그룹을 구성해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Kubeflow Central Dashboard&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Kubeflow 대시보드는 앞서 확인한데로 다음과 같이 접근이 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;http://[WORKER_NODE_IP]:[NODE_PORT]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sScqv/btqT6HeV04v/cfZoYAt0NonuktvMK2g36k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sScqv/btqT6HeV04v/cfZoYAt0NonuktvMK2g36k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sScqv/btqT6HeV04v/cfZoYAt0NonuktvMK2g36k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsScqv%2FbtqT6HeV04v%2FcfZoYAt0NonuktvMK2g36k%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Start Setup 버튼을 클릭하면&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cCft2n/btqTYSaX5ob/pkCSaMYbEzAcLui0uIFN91/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cCft2n/btqTYSaX5ob/pkCSaMYbEzAcLui0uIFN91/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cCft2n/btqTYSaX5ob/pkCSaMYbEzAcLui0uIFN91/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcCft2n%2FbtqTYSaX5ob%2FpkCSaMYbEzAcLui0uIFN91%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;다음과 같이 Namespace를 지정할 수 있으며, Finash 버튼을 클릭하면 메인 화면으로 이동할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tO8D3/btqT19b1NFF/0WUMnRFHpjxnZFRrkZPYB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tO8D3/btqT19b1NFF/0WUMnRFHpjxnZFRrkZPYB1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tO8D3/btqT19b1NFF/0WUMnRFHpjxnZFRrkZPYB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtO8D3%2FbtqT19b1NFF%2F0WUMnRFHpjxnZFRrkZPYB1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;kubeflow를 통해 다양한 기능을 사용할 수 있지만, 그 중 앞서 JupyterHub에서 살펴보았던 Jupyter Notebook을 기동하는 방법에 대해 알아보도록 하자.&amp;nbsp;이전 JupyterHub 포스팅은 다음을 참고한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #006dd7;&quot;&gt;&lt;a style=&quot;color: #006dd7;&quot; href=&quot;https://waspro.tistory.com/567&quot;&gt;[Jupyter Package] Jupyter notebook 환경을 제공하는 Jupyterhub 활용 가이드&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;먼저 왼쪽 메뉴바를 선택한 후 Notebook Servers를 선택한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/P57iE/btqT025hpd0/fEck4UQHugJzfaEdTztglk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/P57iE/btqT025hpd0/fEck4UQHugJzfaEdTztglk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/P57iE/btqT025hpd0/fEck4UQHugJzfaEdTztglk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FP57iE%2FbtqT025hpd0%2FfEck4UQHugJzfaEdTztglk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;gt; + NEW SERVER&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c6gYpI/btqTYRJWEiJ/xQqUHiRCrcXeaXYuzO1jHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c6gYpI/btqTYRJWEiJ/xQqUHiRCrcXeaXYuzO1jHK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c6gYpI/btqTYRJWEiJ/xQqUHiRCrcXeaXYuzO1jHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc6gYpI%2FbtqTYRJWEiJ%2FxQqUHiRCrcXeaXYuzO1jHK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;NOTEBOOK SERVER를 추가하기 위해 아래와 같은 설정을 구성한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dRiyCx/btqTV8rDRzl/GZSFjlVCLKUkyKQqfPXJBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dRiyCx/btqTV8rDRzl/GZSFjlVCLKUkyKQqfPXJBK/img.png&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dRiyCx/btqTV8rDRzl/GZSFjlVCLKUkyKQqfPXJBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdRiyCx%2FbtqTV8rDRzl%2FGZSFjlVCLKUkyKQqfPXJBK%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cmUpbO/btqT91KvRNe/kmGosyEO24aVpE9c4kIu21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cmUpbO/btqT91KvRNe/kmGosyEO24aVpE9c4kIu21/img.png&quot; style=&quot;width: 49.4186%;&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cmUpbO/btqT91KvRNe/kmGosyEO24aVpE9c4kIu21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcmUpbO%2FbtqT91KvRNe%2FkmGosyEO24aVpE9c4kIu21%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;/div&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 data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Name : Notebook Server Name과 Namespace 지정&lt;/span&gt;&lt;/li&gt;
&lt;li data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Image : Jupyter Nodebook 이미지 지정 (기본으로 Tensorflow 라이브러리가 포함된 4개의 버전이 포함되어 있으며, 추가로 커스텀 이미지를 등록하여 기동할 수 있다.)&lt;/span&gt;&lt;/li&gt;
&lt;li data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;CPU/RAM : 이미지에 할당할 CPU/MEMORY를 지정&lt;/span&gt;&lt;/li&gt;
&lt;li data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Workspace Volume : Persistent Volume 영역을 지정 (노트북을 종료할 경우 데이터를 삭제하길 원한다면, Don`y user를 체크한다.)&lt;/span&gt;&lt;/li&gt;
&lt;li data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Data Volumes : 추가로 할당하기 원하는 볼륨 영역을 지정&lt;/span&gt;&lt;/li&gt;
&lt;li data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;GPUs : GPU 사용 여부 지정 (필요시 GPU 수를 지정하며, 이를 사용하기 위해서는 AWS에서는 EC2 P2/P3 등의 Type을 선택하여 Worker Node를 구성해야만 가능하다.)&lt;/span&gt;&lt;/li&gt;
&lt;li data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;마지막으로 Shared Memory 사용 여부를 선택하고 LAUNCH 선택&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/boahUx/btqTV8rDRDD/zQTwvnkVXALkdJ7iLiLRzk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/boahUx/btqTV8rDRDD/zQTwvnkVXALkdJ7iLiLRzk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/boahUx/btqTV8rDRDD/zQTwvnkVXALkdJ7iLiLRzk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FboahUx%2FbtqTV8rDRDD%2FzQTwvnkVXALkdJ7iLiLRzk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 추가한 Jupyter Nodebook이 기동되는 것을 볼 수 있다. 약 1분 정도 시간이 지나면 Notebook Server가 기동된 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgok9C/btqT3sh4d5l/PaGtcbjphY4IkqM7q4KZxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgok9C/btqT3sh4d5l/PaGtcbjphY4IkqM7q4KZxK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgok9C/btqT3sh4d5l/PaGtcbjphY4IkqM7q4KZxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbgok9C%2FbtqT3sh4d5l%2FPaGtcbjphY4IkqM7q4KZxK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 기동이 완료되면 CONNECT 버튼으로 접속이 가능하다. 접속 전 Pod로 기동된 Jupyter Nodebook을 확인해 보자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1611050151931&quot; class=&quot;java&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px;&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-114-198 KFTest]# kubectl get pods -n kfsrv
NAME                                               READY   STATUS    RESTARTS   AGE
jupyternodebook-kubeflow-test-0                    2/2     Running   0          112s
ml-pipeline-ui-artifact-bd978746-dxpfr             2/2     Running   0          30m
ml-pipeline-visualizationserver-865c7865bc-5ql5h   2/2     Running   0          30m
[root@ip-192-168-114-198 KFTest]#&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;위와 같이 jupyternodebook-kubeflow-test-0이 정상 기동된 것을 확인할 수 있다.&amp;nbsp;CONNECT 버튼을 클릭하면 다음과 같이 Jupyter Notebook 대시보드를 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cErDgc/btqT18qAWlq/Kj2A2JyvkhQwH6G1Trt4m1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cErDgc/btqT18qAWlq/Kj2A2JyvkhQwH6G1Trt4m1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cErDgc/btqT18qAWlq/Kj2A2JyvkhQwH6G1Trt4m1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcErDgc%2FbtqT18qAWlq%2FKj2A2JyvkhQwH6G1Trt4m1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;이후 대시보드를 통해 아래와 같이 활용할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/z8YoS/btqTYQqE77c/WDogVflKmSH3XIGjOOJoFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/z8YoS/btqTYQqE77c/WDogVflKmSH3XIGjOOJoFk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/z8YoS/btqTYQqE77c/WDogVflKmSH3XIGjOOJoFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fz8YoS%2FbtqTYQqE77c%2FWDogVflKmSH3XIGjOOJoFk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;Kubeflow는 JupyterHub와 같이 분석도구를 통합으로 관리할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dh9Z5U/btqT17kVOFS/ADDrC5HBD7dTBFqXtK1ZI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dh9Z5U/btqT17kVOFS/ADDrC5HBD7dTBFqXtK1ZI1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dh9Z5U/btqT17kVOFS/ADDrC5HBD7dTBFqXtK1ZI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdh9Z5U%2FbtqT17kVOFS%2FADDrC5HBD7dTBFqXtK1ZI1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;그밖에 다양한 기능을 통해 머신러닝 분석 도구를 제공하는 유용한 툴로써 확장성을 갖고 활용될 수 있을 것이다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>③ 클라우드/ⓚ Kubernetes</category>
      <category>kfctl</category>
      <category>kubeflow</category>
      <category>Kubeflow 대시보드</category>
      <category>kubernetes</category>
      <category>Kubernetes Kubeflow</category>
      <category>Kubernetes ML</category>
      <category>ML 분석도구</category>
      <category>머신러닝 분석</category>
      <category>머신러닝 분석도구</category>
      <category>오픈소스 머신러닝</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/684</guid>
      <comments>https://waspro.tistory.com/684#entry684comment</comments>
      <pubDate>Tue, 19 Jan 2021 19:25:52 +0900</pubDate>
    </item>
    <item>
      <title>Amazon EKS 제로 다운타임 배포환경 구현하기</title>
      <link>https://waspro.tistory.com/682</link>
      <description>&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;서론&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Amazon EKS는 Kubernetes를 기반으로 동작하는 PaaS 플랫폼으로 Kubernetes가 제공하는 Rolling Update 방식을 그대로 적용하여 기본 제로 다운타임 배포를 구현할 수 있다. 다만, EKS 자체의 제로 다운타임배포는 가능하지만 배포 장애에 대한 대응방안과 Managed Service 간의 배포 호환성 등의 검증은 여전히 필요하다. 예를 들어 EKS의 Ingress type으로 &lt;span style=&quot;color: #000000;&quot;&gt;ALB Ingress Controller 등과 연계하여 아키텍처를 설계할때 Pod로 라우팅하는 ALB Ingress의 TargetGroup이 재생성 되는 과정에서 연결 장애가 발생할 수 있기 때문이다. 즉 EKS는 연결되어 있는 Managed Service를 포함하여 제로 다운타임을 함께 고민해야 한다. &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Amazon EKS에서 제로 다운타임을 구현하기 위해 다음을 검토한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;a.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;terminationGracePeriodSeconds&lt;/span&gt;를 구성한다. (Pod 내 Graceful Shutdown 지원) &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;EKS내 Graceful Redeploy를 구현하기 위해서는 현재 Pod에서 처리 중인 요청에 대한 처리를 완료하고 새로운 요청을 받지 않도록 해야 한다. 이때 &lt;span style=&quot;color: #000000;&quot;&gt;terminationGracePeriodSeconds는 &lt;span style=&quot;color: #000000;&quot;&gt;kubelet에서 pod에 SIGTERM을 보낸후에 일정시간동안 graceful shutdown이 되지 않는다면 강제로 SIGKILL을 보내서 pod를 종료하게 하는데&lt;span&gt; 바로 이 &lt;/span&gt;&lt;/span&gt;Graceful Shutdown이 발생하기 까지 얼마나 대기를 시킬 것인지를 설정하는 것이다. &lt;/span&gt;(default 30 sec)&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;b. &lt;span style=&quot;color: #ee2323;&quot;&gt;ReadinessGates&lt;/span&gt;를 구성한다. &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Deployment를 이용해서 배포할 때 maxSurge는 deployment에 설정되어 있는 기본 pod개수보다 여분의 pod가 몇개가 더 추가될 수 있는지를 설정할 수 있다. maxUnavailable는 업데이트하는 동안 몇 개의 pod가 이용 불가능하게 되어도 되는지를 설정하는데 사용된다. 이 두개의 옵션을 운영중인 서비스의 특성에 맞게 적절히 조절해 주어야지 항상 일정 개수 이상의 pod가 이용가능하게 되기 때문에 배포중 트래픽 유실이 없게 된다. 둘 다 한꺼번에 0으로 설정되면 pod가 존재하지 않는 경우가 발생하기 때문에 한꺼번에 0으로 설정할 수는 없다. &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이를 기반으로 배포를 진행할 때, ReadinessGates는 배포 상태를 확인하여 무중단 배포를 실현하게 한다. 컨테이너 이미지가 손상되었거나 구성에 문제가 생겼을 경우, Pod는 새로 시작된 Pod가 Pod ReadinessGates를 통과할 때까지 대기하도록 한다. 이는 Pod가 Loadbalancer의 상태 확인에 응답하는 경우에만 발생한다. Pod가 응답하지 않거나 상태 확인이 잘못 구성된 경우 ReadinessGates 조건을 충족할 수 없으며 롤아웃을 계속할 수 없다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;c. &lt;span style=&quot;color: #ee2323;&quot;&gt;ReadinessProbe, LivenessProbe&lt;/span&gt;를 구성한다. ReadinessProbe는 Pod가 정상 기동되었는지 여부를 확인하는 Probe이며, LivenessProbe는 Pod가 정상동작하는지 여부를 확인하는 Probe이다. 대체로 Readiness는 Port 기반으로 확인하고 Liveness는 httpGet으로 응답을 검증한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;d. &lt;span style=&quot;color: #ee2323;&quot;&gt;Hook(preStop, postStart)&lt;/span&gt;를 활용하여 Pod의 서비스 상태를 지속시킨다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;e. &lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;minReadySeconds&lt;/span&gt;는 &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Pod가 배포되고, 서비스를 시작하는데 딜레이를 주는 옵션이다. 이를 통해 서비스의 준비 시간을 확보할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;본론&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Amazon EKS의 무중단 배포를 이해하기 위해서는 먼저 Pod의 LifeCycle에 대한 이해가 있어야 한다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;Amazon EKS에 애플리케이션을 배포하고 신규 버전을 배포하는 과정에 대해서는 다음을 참고한다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;a href=&quot;https://waspro.tistory.com/651&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[② 클라우드 마스터/ⓐ AWS] - Amazon EKS 30분만에 구성하기 (CloudFormation)&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;LifeCycle&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;먼저 Kubernetes의 최소 배포단위인 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Pod는 다음과 같은 라이프사이클&lt;/b&gt;&lt;/span&gt;을 기반으로 배포되고 배치된다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;a. Pending : &lt;span style=&quot;color: #000000;&quot;&gt;Pod&lt;/span&gt;가 쿠버네티스 클러스터에서 승인되었지만, 하나 이상의 컨테이너가 설정되지 않았고 실행할 준비가 되지 않았다. 여기에는 &lt;span style=&quot;color: #000000;&quot;&gt;Pod&lt;/span&gt;가 스케줄되기 이전까지의 시간 뿐만 아니라 네트워크를 통한 컨테이너 이미지 다운로드 시간도 포함된다. &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;b. Running : &lt;span style=&quot;color: #000000;&quot;&gt;Pod&lt;/span&gt;가 노드에 바인딩되었고, 모든 컨테이너가 생성되었다. 적어도 하나의 컨테이너가 아직 실행 중이거나, 시작 또는 재시작 중에 있다. &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;c. Succeeded : &lt;span style=&quot;color: #000000;&quot;&gt;Pod&lt;/span&gt;에 있는 모든 컨테이너들이 성공적으로 종료되었고, 재시작되지 않을 것이다. &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;d. Failed : &lt;span style=&quot;color: #000000;&quot;&gt;Pod&lt;/span&gt;에 있는 모든 컨테이너가 종료되었고, 적어도 하나 이상의 컨테이너가 실패로 종료되었다. 즉, 해당 컨테이너는 non-zero 상태로 빠져나왔거나(exited) 시스템에 의해서 종료(terminated)되었다. &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;e. Unknown : 어떤 이유에 의해서 파드의 상태를 얻을 수 없다. 이 단계는 일반적으로 파드가 실행되어야 하는 노드와의 통신 오류로 인해 발생한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이와 같이 Pod가 기동되고 배치되면 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Pod는 하나의 &lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;PodStatus&lt;/b&gt;&lt;/span&gt;를 가지며, 그것은 파드가 통과했거나 통과하지 못한 조건에 대한 PodConditions 배열을 갖는다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;a. PodScheduled : 파드가 노드에 스케줄되었다.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;b. ContainersReady : 파드의 모든 컨테이너가 준비되었다.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;c. Initialized : 모든 초기화 컨테이너가 성공적으로 시작되었다.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;d. Ready : 파드는 요청을 처리할 수 있으며 일치하는 모든 서비스의 로드 밸런싱 풀에 추가되어야 한다. &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;노드가 죽거나 클러스터의 나머지와의 연결이 끊어지면, 쿠버네티스는 손실된 노드의 모든 &lt;span style=&quot;color: #000000;&quot;&gt;Pod&lt;/span&gt;의 phase 를 Failed로 설정하는 정책을 적용한다.&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;다음으로 컨테이너이다. &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;전체 파드의 단계뿐 아니라, 쿠버네티스는 파드 내부의 각 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;컨테이너 상태&lt;/b&gt;&lt;/span&gt;를 추적한다. 컨테이너 라이프사이클 훅(hook)을 사용하여 컨테이너 라이프사이클의 특정 지점에서 실행할 이벤트를 트리거할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;일단 스케줄러가 노드에 파드를 할당하면, kubelet은 컨테이너 런타임을 사용하여 해당 파드에 대한 컨테이너 생성을 시작한다. 표시될 수 있는 세 가지 컨테이너 상태는 Waiting, Running 그리고 Terminated 이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;a. Waiting : Waiting 상태의 컨테이너는 시작을 완료하는데 필요한 작업(예를 들어, 컨테이너 이미지 레지스트리에서 컨테이너 이미지 가져오거나, 시크릿(Secret) 데이터를 적용하는 작업)을 계속 실행하고 있는 중이다. kubectl을 사용하여 컨테이너가 Waiting인 파드를 쿼리하면, 컨테이너가 해당 상태에 있는 이유를 요약하는 Reason 필드도 표시된다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;b. Running : Running 상태는 컨테이너가 문제없이 실행되고 있음을 나타낸다. postStart hook이 구성되어 있었다면, 이미 실행되고 완료되었다. kubectl을 사용하여 컨테이너가 Running 인 파드를 쿼리하면, 컨테이너가 Running 상태에 진입한 시기에 대한 정보도 볼 수 있다. &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;c. Terminated : &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Terminated&amp;nbsp;상태의&amp;nbsp;컨테이너는&amp;nbsp;실행을&amp;nbsp;시작한&amp;nbsp;다음&amp;nbsp;완료될&amp;nbsp;때까지&amp;nbsp;실행되었거나&amp;nbsp;어떤&amp;nbsp;이유로&amp;nbsp;실패했다.&amp;nbsp;kubectl&amp;nbsp;을&amp;nbsp;사용하여&amp;nbsp;컨테이너가&amp;nbsp;Terminated&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;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;컨테이너에 구성된 preStop 훅이 있는 경우, 컨테이너가 Terminated 상태에 들어가기 전에 실행된다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이와 같은 컨테이너를 관리하는 정책을 &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;restartPolicy&lt;/span&gt;&lt;/b&gt;라는 필드로 관리할 수 있다.사용 가능한 값은 Always, OnFailure 그리고 Never이다. 기본값은 Always이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;restartPolicy 는 파드 내 모든 컨테이너에 적용된다. restartPolicy는 동일한 노드에서 kubelet에 의한 컨테이너 재시작만을 의미한다. 파드의 컨테이너가 종료된 후, kubelet은 5분으로 제한되는 BackOff Delay(10초, 20초, 40초, &amp;hellip;)로 컨테이너를 재시작한다. 컨테이너가 10분 동안 아무런 문제없이 실행되면, kubelet은 해당 컨테이너의 재시작 백오프 타이머를 재설정한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;RollingUpdate&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;컨테이너와 Pod의 라이프사이클에 대해 알아보았으니 이를 기반으로 Amazon EKS에서는 어떻게 Pod와 Container의 상태를 유지할 수 있는지 알아보자. &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;테스트는 다음과 같이 진행한다. 먼저 기존 HTTPD APP을 배포한 후 신규로 NGINX APP 이미지를 배포하고 그 과정에 서비스 다운타임이 발생하는지 여부를 검증한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;테스트에 활용한 yaml 파일은 다음과 같다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1610851723540&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: httpd
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: my-nginx
  labels:
    run: my-nginx
spec:
  ports:
  - port: 80
    protocol: TCP
    #  type: NodePort
  selector:
    run: my-nginx
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: &quot;ingress-app&quot;
  annotations:
    kubernetes.io/ingress.class: alb
    alb.ingress.kubernetes.io/target-type: ip
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/subnets: subnet-09ab6e9681ccc1d5f,subnet-03a0540fedf080b86
spec:
  rules:
   - http:
      paths:
        - path: /*
          backend:
            serviceName: &quot;my-nginx&quot;
            servicePort: 80&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Deployment의 .spec.template.spec.containers.image의 httpd를 nginx로 변경하여 배포하는 테스트를 진행한다. &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;먼저 httpd app을 배포한 결과이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/43Sbk/btqTDJeG5Im/JbnJfjpsSACXOiya2HeKsk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/43Sbk/btqTDJeG5Im/JbnJfjpsSACXOiya2HeKsk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/43Sbk/btqTDJeG5Im/JbnJfjpsSACXOiya2HeKsk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F43Sbk%2FbtqTDJeG5Im%2FJbnJfjpsSACXOiya2HeKsk%2Fimg.png&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;아래와 같이 pod 2개를 포함하는 Deployment가 배포되어 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-114-198 yaml]# kubectl get pods -o wide
NAME                        READY   STATUS    RESTARTS   AGE   IP                NODE                                               NOMINATED NODE   READINESS GATES
my-nginx-7dc7954b86-c5wrp   1/1     Running   0          71s   192.168.79.209    ip-192-168-79-27.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
my-nginx-7dc7954b86-v7jv2   1/1     Running   0          66s   192.168.145.142   ip-192-168-146-0.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
[root@ip-192-168-114-198 yaml]#&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;다음으로 nginx app을 배포해 보자. 아래와 같이 Pod가 재기동되는 가운데 502 Bad Gateway와 504 Gateway Timeout이 발생하는 것을 알 수 있다.&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;물론 수초뒤 화면은 정상상태로 변경된다. &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cOMRAE/btqTJS9i6oA/p5a4ftNxHtqbGuwHNlMZk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cOMRAE/btqTJS9i6oA/p5a4ftNxHtqbGuwHNlMZk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cOMRAE/btqTJS9i6oA/p5a4ftNxHtqbGuwHNlMZk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcOMRAE%2FbtqTJS9i6oA%2Fp5a4ftNxHtqbGuwHNlMZk0%2Fimg.png&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이는 EKS 자체적인 Rolling Update는 물론 ALB Ingress Controller와의 연결 관계인 Target Group에 대한 draining과정으로 인해 발생한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QLf4W/btqTF3cJ1wo/CTheiQNWsPIdzkxK89EcSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QLf4W/btqTF3cJ1wo/CTheiQNWsPIdzkxK89EcSK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QLf4W/btqTF3cJ1wo/CTheiQNWsPIdzkxK89EcSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQLf4W%2FbtqTF3cJ1wo%2FCTheiQNWsPIdzkxK89EcSK%2Fimg.png&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;ALB Ingress Controller는 EKS의 Ingress로써 동작하며, Pod로의 라우팅을 위해 신규도 배치된 Pod의 Replica 수를 유지하기 위해 이전 Pod를 draining 시키고 신규 Pod를 배치한다. 이때 draining이 발생하는 시점과 신규 Pod가 배치되는 시점이 겹쳐 위와 같은 502/504 응답을 받게 되는 것이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;정리하자면, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;EKS Rolling Update는 다음과 같은 과정으로 신규 Pod가 배치&lt;/b&gt;&lt;/span&gt;된다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;a. Pod는 Rolling Update 규칙에 따라 Pod를 제거하고 생성하여 하나 이상의 Eunning Pod가 유지되도록 관리한다.&lt;br /&gt;b. 새로운 버전의 Pod로 교체 될 때 ALB Ingress Controller는 Target Group에 Pod를 등록하기 위해 이전 Pod를 제거한다.&lt;br /&gt;c&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;. 이때, 새 Pod는 정상적으로 기동이 완료 될때까지 initial 상태로 남아 있게 된다.&lt;br /&gt;d&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;. 이전 Pod의 경우 draining 상태로 변경되어 Pod를 삭제한다. 이때 initial 상태의 Pod 기동이 완료되지 않아 502/504 에러를 발생시킨다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이와 같은 문제를 해결하기 위해 EKS는 다음과 같은 두가지 해결방식을 제공한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;ReadinessGates&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;readinessGates는 파드에 대한 status.condition 필드의 현재 상태에 따라 결정된다. 만약 쿠버네티스가 status.conditions 필드에서 해당하는 조건을 찾지 못한다면, 그 조건의 상태는 기본 값인 &quot;False&quot;가 된다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1610854433885&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;kind: Pod
...
spec:
  readinessGates:
    - conditionType: &quot;www.example.com/feature-1&quot;
status:
  conditions:
    - type: Ready                              # 내장된 PodCondition이다
      status: &quot;False&quot;
      lastProbeTime: null
      lastTransitionTime: 2018-01-01T00:00:00Z
    - type: &quot;www.example.com/feature-1&quot;        # 추가적인 PodCondition
      status: &quot;False&quot;
      lastProbeTime: null
      lastTransitionTime: 2018-01-01T00:00:00Z
  containerStatuses:
    - containerID: docker://abcd...
      ready: true
...&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;사용자 지정 조건을 사용하는 파드의 경우, 다음 두 조건이 모두 적용되는 경우에 만 해당 파드가 준비된 것으로 평가된다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;a. readinessGates에 지정된 모든 조건들이 True 이다. &lt;br /&gt;b. Pod의 컨테이너가 Ready 이나 적어도 한 개의 사용자 지정 조건이 빠졌거나 False 이면, kubelet은 &lt;span style=&quot;color: #000000;&quot;&gt;Pod&lt;/span&gt;의 조건을 ContainerReady 로 설정한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;yaml&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx
        ports:
        - containerPort: 80
      readinessGates:
      - conditionType: target-health.alb.ingress.k8s.aws/ingress-app_my-nginx_80&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;버전 v1.1.6 부터 ALB Ingress Controller는 &lt;span style=&quot;color: #000000;&quot;&gt;readinessGates&lt;/span&gt;를 도입했다 .이 기능은 EKS가 Rolling Update를 진행하는 과정에서 예기치 않은 문제 (예 : AWS API에 대한 Timeout 등)가 발생할 경우 배포를 중지하여 항상 정상상태의 Pod가 유지될 수 있게 한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;readinessGates는 다음과 같이 추가할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;- conditionType: target-health.alb.ingress.k8s.aws/&lt;span style=&quot;color: #ee2323;&quot;&gt;[INGRESS_NAME]_[SERVICE_NAME]_[SERVICE_PORT]&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;위와 같이 추가한 후 Deployment를 배치하면 다음과 같이 Pod의 상태에서 ReadinessGates 정보를 확인할 수 있다. 아래는 pod가 배치되는 과정이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-114-198 yaml]# kubectl get pods -o wide -w
NAME                       READY   STATUS    RESTARTS   AGE   IP                NODE                                               NOMINATED NODE   READINESS GATES
my-nginx-7cdd7f9d8-442lq   1/1     Running   0          45m   192.168.109.191   ip-192-168-79-27.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
my-nginx-7cdd7f9d8-86xzz   1/1     Running   0          45m   192.168.143.73    ip-192-168-146-0.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
my-nginx-6dc7bdd648-wsxs9   0/1     Pending   0          0s    &amp;lt;none&amp;gt;            &amp;lt;none&amp;gt;                                             &amp;lt;none&amp;gt;           0/1
my-nginx-6dc7bdd648-wsxs9   0/1     Pending   0          0s    &amp;lt;none&amp;gt;            ip-192-168-79-27.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           0/1
my-nginx-6dc7bdd648-wsxs9   0/1     ContainerCreating   0          0s    &amp;lt;none&amp;gt;            ip-192-168-79-27.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           0/1
my-nginx-6dc7bdd648-wsxs9   0/1     Terminating         0          1s    &amp;lt;none&amp;gt;            ip-192-168-79-27.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           0/1
my-nginx-75b764b685-6v2wc   0/1     Pending             0          0s    &amp;lt;none&amp;gt;            &amp;lt;none&amp;gt;                                             &amp;lt;none&amp;gt;           0/1
my-nginx-75b764b685-6v2wc   0/1     Pending             0          0s    &amp;lt;none&amp;gt;            ip-192-168-146-0.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           0/1
my-nginx-75b764b685-6v2wc   0/1     ContainerCreating   0          0s    &amp;lt;none&amp;gt;            ip-192-168-146-0.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           0/1
my-nginx-6dc7bdd648-wsxs9   0/1     Terminating         0          2s    &amp;lt;none&amp;gt;            ip-192-168-79-27.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           0/1
my-nginx-6dc7bdd648-wsxs9   0/1     Terminating         0          2s    &amp;lt;none&amp;gt;            ip-192-168-79-27.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           0/1
my-nginx-75b764b685-6v2wc   1/1     Running             0          5s    192.168.186.167   ip-192-168-146-0.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           0/1
my-nginx-75b764b685-6v2wc   1/1     Running             0          21s   192.168.186.167   ip-192-168-146-0.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           1/1
my-nginx-75b764b685-6v2wc   1/1     Running             0          21s   192.168.186.167   ip-192-168-146-0.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           1/1
my-nginx-7cdd7f9d8-86xzz    1/1     Terminating         0          45m   192.168.143.73    ip-192-168-146-0.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
my-nginx-75b764b685-2ncpv   0/1     Pending             0          0s    &amp;lt;none&amp;gt;            &amp;lt;none&amp;gt;                                             &amp;lt;none&amp;gt;           0/1
my-nginx-75b764b685-2ncpv   0/1     Pending             0          0s    &amp;lt;none&amp;gt;            ip-192-168-79-27.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           0/1
my-nginx-75b764b685-2ncpv   0/1     ContainerCreating   0          0s    &amp;lt;none&amp;gt;            ip-192-168-79-27.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           0/1
my-nginx-7cdd7f9d8-86xzz    0/1     Terminating         0          45m   192.168.143.73    ip-192-168-146-0.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
my-nginx-7cdd7f9d8-86xzz    0/1     Terminating         0          45m   192.168.143.73    ip-192-168-146-0.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
my-nginx-7cdd7f9d8-86xzz    0/1     Terminating         0          45m   192.168.143.73    ip-192-168-146-0.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
my-nginx-75b764b685-2ncpv   1/1     Running             0          4s    192.168.107.130   ip-192-168-79-27.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           0/1
my-nginx-75b764b685-2ncpv   1/1     Running             0          19s   192.168.107.130   ip-192-168-79-27.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           1/1
my-nginx-75b764b685-2ncpv   1/1     Running             0          19s   192.168.107.130   ip-192-168-79-27.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           1/1
my-nginx-7cdd7f9d8-442lq    1/1     Terminating         0          45m   192.168.109.191   ip-192-168-79-27.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
my-nginx-7cdd7f9d8-442lq    0/1     Terminating         0          45m   192.168.109.191   ip-192-168-79-27.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
my-nginx-7cdd7f9d8-442lq    0/1     Terminating         0          46m   192.168.109.191   ip-192-168-79-27.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
my-nginx-7cdd7f9d8-442lq    0/1     Terminating         0          46m   192.168.109.191   ip-192-168-79-27.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
[root@ip-192-168-114-198 yaml]# kubectl get pods -o wide -w
NAME                        READY   STATUS    RESTARTS   AGE     IP                NODE                                               NOMINATED NODE   READINESS GATES
my-nginx-75b764b685-2ncpv   1/1     Running   0          3m13s   192.168.107.130   ip-192-168-79-27.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           1/1
my-nginx-75b764b685-6v2wc   1/1     Running   0          3m34s   192.168.186.167   ip-192-168-146-0.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           1/1
[root@ip-192-168-114-198 yaml]#&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;위와 같이 READINESS GATES가 &amp;lt;none&amp;gt;에서 0/1 &amp;rarr; 1/1로 변경되는 것을 확인할 수 있다. READY 상태가 된 이후 이전 버전의 pod를 terminating한다. 다만, 이와 같이 Readiness Gates가 등록되었음에도 Service는 여전히 502/504 에러가 발생하는 것을 볼 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cOMRAE/btqTJS9i6oA/p5a4ftNxHtqbGuwHNlMZk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cOMRAE/btqTJS9i6oA/p5a4ftNxHtqbGuwHNlMZk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cOMRAE/btqTJS9i6oA/p5a4ftNxHtqbGuwHNlMZk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcOMRAE%2FbtqTJS9i6oA%2Fp5a4ftNxHtqbGuwHNlMZk0%2Fimg.png&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;사실 Readiness Gates는 Pod의 배포 여부를 검증하는 것이지,&amp;nbsp; ALB Ingress Controller와의 Rolling 업데이트와는 별개의 동작이므로 다운타임이 발생할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Pod LifeCycle&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;다음은 lifecycle을 통해 hook을 실행하는 yaml 형식이다. 컨테이너가 lifecycle의 이벤트를 인지하고 이에 상응되는 이벤트가 실행될 때 command를 실행할 수 있다. &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;Gracefule Redeploy&lt;/span&gt;를 실현하기 위해서는 먼저 Pod가 종료되는 순서에 대한 이해가 있어야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;1 - 포드가&amp;nbsp;종료&amp;nbsp;상태로&amp;nbsp;전환되고&amp;nbsp;새 트래픽 수신을 중지한다.&amp;nbsp;컨테이너는 여전히 포드 내에서 실행 중인 상태일 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;3efb&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;2 - REST 또는 HTTP 요청은&amp;nbsp;preStop&amp;nbsp;후크가 실행되고 포드 내부의 컨테이너로 전송된다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;842e&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;3 -&amp;nbsp;SIGTERM&amp;nbsp;신호가 포드로 전송되고 컨테이너가 곧 닫힐 것임을 인식한다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;cfe0&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;4 - Kubernetes는&amp;nbsp;유예 기간 (terminationGracePeriodSeconds)을&amp;nbsp;기다린다&amp;nbsp;.&amp;nbsp;이 대기는 preStop 후크 및 SIGTERM (기본값 30 초)과 병렬이다.&amp;nbsp;따라서 Kubernetes는 이러한 작업이 완료 될 때까지 기다리지 않는다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;5364&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;5 -&amp;nbsp;SIGKILL&amp;nbsp;신호가 포드로 전송되고 포드가 제거된다.&amp;nbsp;컨테이너가 유예 기간 후에도 계속 실행 중이면&amp;nbsp;SIGKILL에 의해&amp;nbsp;포드가&amp;nbsp;강제로&amp;nbsp;제거되고 종료가 완료된다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;컨테이너 hook은 크게 두가지가 존재한다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 2
  minReadySeconds: 5
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx
        ports:
        - containerPort: 80
        lifecycle:
          preStop:
            exec:
              command: [&quot;/bin/sh&quot;, &quot;-c&quot;, &quot;sleep 40&quot;]
      readinessGates:
      - conditionType: target-health.alb.ingress.k8s.aws/ingress-app_my-nginx_80
      terminationGracePeriodSeconds: 60&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;a. PostStart (&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;컨테이너가 생성된 직후에 실행된다. 그러나, hook이 컨테이너 엔트리포인트에 앞서서 실행된다는 보장은 없다. 즉, 파라미터는 핸들러에 전달되지 않는다.)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;b. PreStop (&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이 hook은 API 요청이나 활성 프로브(liveness probe) 실패, 선점, 자원 경합 등의 관리 이벤트로 인해 컨테이너가 종료되기 직전에 호출된다. 컨테이너가 이미 terminated 또는 completed 상태인 경우에는 preStop 훅 요청이 실패한다. 그것은 동기적인 동작을 의미하는, 차단(blocking)을 수행하고 있으므로, 컨테이너를 중지하기 위한 신호가 전송되기 전에 완료되어야 한다. 파라미터는 핸들러에 전달되지 않는다.)&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;위 yaml 파일은 &lt;span style=&quot;color: #000000;&quot;&gt;preStop&lt;/span&gt; hook과 함께 sleep command를 적용하여 Pod가 종료되기 전 40초를 대기 시키는 hook이다. 이와 같은 방법은 ALB가 Target Group에서 이전 버전을 완전히 제거 할 시간을 가질 수 있도록 한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그 밖에 서비스 시작전 즉 Pod가 기동이 완료 된 이후 일정 시간 딜레이를 주거나, 강제 종료를 방지하는 옵션들이 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;a. &lt;span style=&quot;color: #000000;&quot;&gt;minReadySeconds (&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Pod가 배포되고, 서비스를 시작하는데 딜레이를 주는 옵션이다. 이를 통해 서비스의 준비 시간을 확보할 수 있다.)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;b. terminationGracePeriodSeconds (&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;kubelet이 Pod를 중지하기 위해 SIGTERM을 보낸 후 일정 시간동안 서비스가 중지 되지 않을 경우 SIGKILL을 전송하게 되는데, 이때까지의 대기시간을 terminationGracePeriodSeconds으로 구성할 수 있다. PreStop보다 우선순위가 높아 PreStop Sleep을 주더라도 terminationGracePeriodSeconds 시간이 넘어 갈 경우 강제로 SIGTERM이 날라가고 서비스가 중지된다. 따라서 terminationGracePeriodSeconds는 충분히 길제 구성해야 할 수 있으며, PreStop보다 최소 길어야 한다.)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;위 구성으로 다시 재기동해보도록 하자.현재 nginx image가 배포되어 있는 상태이다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPpOQS/btqTKLWsdOz/jLOwRzqNTS0h3qfBK5CFo1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPpOQS/btqTKLWsdOz/jLOwRzqNTS0h3qfBK5CFo1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPpOQS/btqTKLWsdOz/jLOwRzqNTS0h3qfBK5CFo1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbPpOQS%2FbtqTKLWsdOz%2FjLOwRzqNTS0h3qfBK5CFo1%2Fimg.png&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&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; font-family: 'Noto Serif KR';&quot;&gt;yaml 파일에 pod lifecycle을 적용한 후 다음과 같이 재기동을 수행해 보자.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4gMDl/btqTPxJUrWL/UiuC7m43EMVaeG0EsAZ84K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4gMDl/btqTPxJUrWL/UiuC7m43EMVaeG0EsAZ84K/img.png&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4gMDl/btqTPxJUrWL/UiuC7m43EMVaeG0EsAZ84K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4gMDl%2FbtqTPxJUrWL%2FUiuC7m43EMVaeG0EsAZ84K%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dLTpDc/btqTLxwViHw/Xkf2YAhwKC3ghyLXv4Mbqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dLTpDc/btqTLxwViHw/Xkf2YAhwKC3ghyLXv4Mbqk/img.png&quot; style=&quot;width: 49.4186%;&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dLTpDc/btqTLxwViHw/Xkf2YAhwKC3ghyLXv4Mbqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdLTpDc%2FbtqTLxwViHw%2FXkf2YAhwKC3ghyLXv4Mbqk%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;실제 pod의 동작 방식은 아래와 같다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-114-198 yaml]# kubectl get pods -o wide -w
NAME                        READY   STATUS    RESTARTS   AGE   IP               NODE                                               NOMINATED NODE   READINESS GATES
my-nginx-57d7f69d8d-kmlx6   1/1     Running   0          39s   192.168.143.73   ip-192-168-146-0.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           1/1
my-nginx-57d7f69d8d-qmzlk   1/1     Running   0          61s   192.168.65.159   ip-192-168-79-27.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           1/1
my-nginx-656b8fdb58-9d44g   0/1     Pending   0          0s    &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;                                             &amp;lt;none&amp;gt;           0/1
my-nginx-656b8fdb58-9d44g   0/1     Pending   0          0s    &amp;lt;none&amp;gt;           ip-192-168-79-27.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           0/1
my-nginx-656b8fdb58-9d44g   0/1     ContainerCreating   0          0s    &amp;lt;none&amp;gt;           ip-192-168-79-27.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           0/1
my-nginx-656b8fdb58-9d44g   0/1     Terminating         0          2s    &amp;lt;none&amp;gt;           ip-192-168-79-27.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           0/1
my-nginx-878597468-qnkr6    0/1     Pending             0          0s    &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;                                             &amp;lt;none&amp;gt;           0/1
my-nginx-878597468-qnkr6    0/1     Pending             0          0s    &amp;lt;none&amp;gt;           ip-192-168-79-27.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           0/1
my-nginx-878597468-qnkr6    0/1     ContainerCreating   0          0s    &amp;lt;none&amp;gt;           ip-192-168-79-27.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           0/1
my-nginx-656b8fdb58-9d44g   0/1     Terminating         0          4s    &amp;lt;none&amp;gt;           ip-192-168-79-27.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           0/1
my-nginx-656b8fdb58-9d44g   0/1     Terminating         0          4s    &amp;lt;none&amp;gt;           ip-192-168-79-27.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           0/1
my-nginx-878597468-qnkr6    1/1     Running             0          6s    192.168.109.191   ip-192-168-79-27.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           0/1
my-nginx-878597468-qnkr6    1/1     Running             0          21s   192.168.109.191   ip-192-168-79-27.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           0/1
my-nginx-878597468-qnkr6    1/1     Running             0          21s   192.168.109.191   ip-192-168-79-27.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           0/1
my-nginx-878597468-qnkr6    1/1     Running             0          36s   192.168.109.191   ip-192-168-79-27.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           1/1
my-nginx-878597468-qnkr6    1/1     Running             0          36s   192.168.109.191   ip-192-168-79-27.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           1/1
my-nginx-57d7f69d8d-qmzlk   1/1     Terminating         0          3m14s   192.168.65.159    ip-192-168-79-27.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           1/1
my-nginx-878597468-bzc9z    0/1     Pending             0          0s      &amp;lt;none&amp;gt;            &amp;lt;none&amp;gt;                                             &amp;lt;none&amp;gt;           0/1
my-nginx-878597468-bzc9z    0/1     Pending             0          0s      &amp;lt;none&amp;gt;            ip-192-168-146-0.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           0/1
my-nginx-878597468-bzc9z    0/1     ContainerCreating   0          0s      &amp;lt;none&amp;gt;            ip-192-168-146-0.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           0/1
my-nginx-878597468-bzc9z    1/1     Running             0          5s      192.168.186.167   ip-192-168-146-0.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           0/1
my-nginx-878597468-bzc9z    1/1     Running             0          20s     192.168.186.167   ip-192-168-146-0.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           1/1
my-nginx-878597468-bzc9z    1/1     Running             0          20s     192.168.186.167   ip-192-168-146-0.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           1/1
my-nginx-57d7f69d8d-kmlx6   1/1     Terminating         0          3m12s   192.168.143.73    ip-192-168-146-0.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           1/1
my-nginx-57d7f69d8d-qmzlk   0/1     Terminating         0          3m55s   192.168.65.159    ip-192-168-79-27.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           1/1
my-nginx-57d7f69d8d-qmzlk   0/1     Terminating         0          4m5s    192.168.65.159    ip-192-168-79-27.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           1/1
my-nginx-57d7f69d8d-qmzlk   0/1     Terminating         0          4m5s    192.168.65.159    ip-192-168-79-27.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           1/1
my-nginx-57d7f69d8d-kmlx6   0/1     Terminating         0          3m53s   192.168.143.73    ip-192-168-146-0.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           1/1
my-nginx-57d7f69d8d-kmlx6   0/1     Terminating         0          3m57s   192.168.143.73    ip-192-168-146-0.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           1/1
my-nginx-57d7f69d8d-kmlx6   0/1     Terminating         0          3m57s   192.168.143.73    ip-192-168-146-0.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           1/1
[root@ip-192-168-114-198 yaml]# kubectl get pods -o wide -w
NAME                       READY   STATUS    RESTARTS   AGE     IP                NODE                                               NOMINATED NODE   READINESS GATES
my-nginx-878597468-bzc9z   1/1     Running   0          99s     192.168.186.167   ip-192-168-146-0.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           1/1
my-nginx-878597468-qnkr6   1/1     Running   0          2m15s   192.168.109.191   ip-192-168-79-27.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           1/1
[root@ip-192-168-114-198 yaml]#&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;위와 같이 Pod가 기동되는 시점에 중복되는 initial과 draining 시간을 없애기 위해 Terminating되는 시점을 preStop으로 강제로 연장하여 정상 상태를 확보할 수 있다. 위와 같이 첫번째 Pod의 기동이 완료되면 한번씩 번갈아 가며, 호출되고, 두대 모두 기동이 완료되면, httpd의 It Works! 페이지가 계속 나오는 것을 알 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;결론&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;단순히 Kubernetes가 제공하는 Rolling Update나 CI/CD 배포 방식&lt;span style=&quot;color: #000000;&quot;&gt;(A/B, Blue/Green 등)&lt;/span&gt;을 적용하여 제로 다운타임을 구현할 수 있으나, 이는 AWS 환경 상에서 연결 되는 Managed Service까지 커버할 수는 없다. 따라서 EKS와 LB 간의 배포 프로세스에 ReadinessGates와 PreStop Hook을 적용하여 서비스 가용성을 높이고, 안정성을 도모할 수 있도록 구성해야 할 것이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;EKS의 가용성을 위해 총 4가지 요소를 알아 보았다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;span style=&quot;color: #ee2323; font-family: 'Noto Serif KR';&quot;&gt;- terminationGracePeriodSeconds&lt;/span&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;span style=&quot;color: #ee2323; font-family: 'Noto Serif KR';&quot;&gt;- ReadinessGates&lt;/span&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;span style=&quot;color: #ee2323; font-family: 'Noto Serif KR';&quot;&gt;- ReadinessProbe, LivenessProbe&lt;/span&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;span style=&quot;color: #ee2323; font-family: 'Noto Serif KR';&quot;&gt;- Hook(preStop, postStart)&lt;/span&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;span style=&quot;color: #ee2323; font-family: 'Noto Serif KR';&quot;&gt;- minReadySeconds&lt;/span&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이는 다음과 같은 조합으로 구성할 경우 최적의 아키텍처를 구성할 수 있다. 먼저, &lt;span style=&quot;color: #000000;&quot;&gt;terminationGracePeriodSeconds는 서비스가 완전히 종료될 수 있도록 충분히 긴 시간으로 구성한다. 이때 PreStop Hook과 연계하여 신규 Pod가 완전히 기동되기 전까지 기존 버전의 Pod가 중지되지 않도록 Sleep을 구성하며, &lt;span style=&quot;color: #000000;&quot;&gt;terminationGracePeriodSeconds를 넘지 않도록 한다. 또한 배포 장애를 사전에 차단하고 네트워크 딜레이 등의 문제를 해소하기 위해 &lt;span style=&quot;color: #000000;&quot;&gt;ReadinessGates와 &lt;span style=&quot;color: #000000;&quot;&gt;minReadySeconds를 구성한다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Pod의 Graceful Shutdown은 다음과 같이 동작한다고 정리해 볼 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1) 새 배포를 시작하면 이전 포드가 Terminating 상태로 변경된다 . 이 시점에서 서비스는 iptable 에서 포드의 IP를 제거 하고 새로운 트래픽이 들어오는 것을 방지한다. &lt;br /&gt;2) 그 후 preStop 후크 및 SIGTERM 신호가 종료 포드로 전송된다. SIGTERM 메시지를 수신하는 애플리케이션은 종료 준비를 시작하고 연결을 닫으려고한다. &lt;br /&gt;3) 동시에 preStop 후크가 실행되며 httpGet, command Sleep 등을 실행한다. 이후 애플리케이션의 상태를 DOWN으로 설정하고 여기서 terminateGracePeriodSeconds 값을 기다린다. 애플리케이션이 유예 기간 전에 종료되는 경우 terminateGracePeriodSeconds만큼 대기하지 않고 포드를 직접 종료한다. &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;여기에서 대기 프로세스 (연결 종료, 로깅 등) 전에 원하는 일부 기능을 코딩 할 수 있다. 예를 들어, 포드가 Terminate 상태에 있고 최종 요청을 처리하는 동안 일부 Spring Bean을 찾을 수 없어 BeanException이 발생g할 수 있다. 일부 빈이 조기에 종료되는 것을 방지하기 위해 Tomcat 서버를 대기 상태로 유지한다.&lt;br /&gt;4) terminateGracePeriodSeconds가 지나면 포드에 대한 작업이 성공적으로 완료되고 연결이 닫힌다. SIGKILL 신호를 사용하면 이전 포드가 제거되고 새 포드 만 기동 상태가 된다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이와 같은 문제는 AWS와 같은 CSP를 사용할 경우 충분히 발생가능한 이슈이다. 여러 컴포넌트가 연계되어 구성되는 경우 각 컴포넌트간의 관계를 진단하고 서비스 장애를 차단할 수 있는 아키텍처를 설계해야 한다는 점에 유의하여 구성해야 할 것이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>③ 클라우드/ⓐ AWS</category>
      <category>amazon EKS</category>
      <category>graceful shutdown</category>
      <category>minReadySeconds</category>
      <category>Pod lifecycle</category>
      <category>poststart</category>
      <category>prestop</category>
      <category>readinessgates</category>
      <category>terminationGracePeriodSeconds</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/682</guid>
      <comments>https://waspro.tistory.com/682#entry682comment</comments>
      <pubDate>Sun, 17 Jan 2021 01:48:47 +0900</pubDate>
    </item>
    <item>
      <title>Kubernetes 환경변수 구성하기 (ConfigMap, Secret)</title>
      <link>https://waspro.tistory.com/681</link>
      <description>&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;서론&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Legacy 환경에서 각 환경별(개발, 테스트, 운영)로 설정을 구분하기 위해 우리는 Property를 활용해 왔다. Property를 적용하기 위해 application.properties나 application.yml과 같은 설정 파일 기반으로 적용하거나 @Configuration 어노테이션을 사용하여 각 환경 별 구분된 환경 정보를 가져갈 수 있었다. 이러한 방식은 모두 애플리케이션 레벨에서 환경 설정을 관리하는 방법이라 할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dL9wBi/btqSEKkh1js/bRdoOg9TAl95iXc2ak7Xu0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dL9wBi/btqSEKkh1js/bRdoOg9TAl95iXc2ak7Xu0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dL9wBi/btqSEKkh1js/bRdoOg9TAl95iXc2ak7Xu0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdL9wBi%2FbtqSEKkh1js%2FbRdoOg9TAl95iXc2ak7Xu0%2Fimg.png&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;최근&amp;nbsp;애플리케이션은&amp;nbsp;Cloud&amp;nbsp;Native하게&amp;nbsp;개발하기&amp;nbsp;위해&amp;nbsp;개발방식도&amp;nbsp;변화되어&amp;nbsp;가고&amp;nbsp;있다.&amp;nbsp;특히&amp;nbsp;Spring&amp;nbsp;Boot&amp;nbsp;기반의&amp;nbsp;가볍고&amp;nbsp;빠른&amp;nbsp;개발을&amp;nbsp;지원하는&amp;nbsp;Runtime&amp;nbsp;Framework의&amp;nbsp;활용도가&amp;nbsp;높아지고&amp;nbsp;있으며,&amp;nbsp;이는&amp;nbsp;Cloud&amp;nbsp;Platform에&amp;nbsp;빠르게&amp;nbsp;이식되어&amp;nbsp;민첩하게&amp;nbsp;배포&amp;nbsp;될&amp;nbsp;수&amp;nbsp;있도록&amp;nbsp;개발해야&amp;nbsp;한다.&amp;nbsp;이를&amp;nbsp;CNA라고&amp;nbsp;부른다. &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;이때 환경 설정을 애플리케이션 레벨에서 관리하게 될 경우 소스코드와의 Dependency가 많아지고, 환경 설정의 변경이 발생할때 마다 매번 소스코드 체크아웃부터 시작한다면, 이는 CNA의 신속한 반영을 저해하는 요소가 될 수 있다. 따라서 Kubernetes와 같은 클라우드 환경에 적용하기 위해서는 애플리케이션 레벨이 아닌 오브젝트 레벨에서 환경 설정을 관리할 수 있도록 구성해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;이를 Kubernetes는 configMap과 secret이라는 오브젝트를 통해 제공하고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;configMap은&amp;nbsp;다른&amp;nbsp;오브젝트가&amp;nbsp;사용할&amp;nbsp;구성&amp;nbsp;대체로&amp;nbsp;Pod&amp;nbsp;내&amp;nbsp;컨테이너가&amp;nbsp;사용할&amp;nbsp;구성을&amp;nbsp;저장할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;Kubernetes의&amp;nbsp;오브젝트이다.&amp;nbsp;spec&amp;nbsp;이&amp;nbsp;있는&amp;nbsp;대부분의&amp;nbsp;쿠버네티스&amp;nbsp;오브젝트와&amp;nbsp;달리,&amp;nbsp;컨피그맵에는&amp;nbsp;data&amp;nbsp;및&amp;nbsp;binaryData&amp;nbsp;필드가&amp;nbsp;있다.&amp;nbsp;이러한&amp;nbsp;필드는&amp;nbsp;key&amp;nbsp;-&amp;nbsp;value&amp;nbsp;값으로&amp;nbsp;구성된다.&amp;nbsp;data&amp;nbsp;필드와&amp;nbsp;binaryData&amp;nbsp;는&amp;nbsp;모두&amp;nbsp;선택&amp;nbsp;사항으로&amp;nbsp;data&amp;nbsp;필드는&amp;nbsp;UTF-8&amp;nbsp;바이트&amp;nbsp;시퀀스를&amp;nbsp;포함하도록&amp;nbsp;설계되었으며&amp;nbsp;binaryData&amp;nbsp;필드는&amp;nbsp;바이너리&amp;nbsp;데이터를&amp;nbsp;포함하도록&amp;nbsp;설계되었다. &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;configMap은 많은 양의 데이터를 보유하도록 설계되지 않았다. configMap에 저장된 데이터는 1MiB를 초과할 수 없다. 이 제한보다 큰 설정을 저장해야 하는 경우, 볼륨을 마운트하는 것을 고려하거나 별도의 데이터베이스 또는 파일 서비스를 사용할 수 있다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;configMap은 별도의 보안 또는 암호화를 제공하지 않는다. 저장되어 있는 data를 kubernetes api 또는 yaml 파일을 통해 손쉽게 값을 확인할 수 있어 Credential 정보를 저장하기에는 부적합하며, 일반적인 정보를 저장하는데 적합하다. 예를 들어 로그 레벨이나 dev, prod와 같은 환경 구분 등을 설정하는데 활용된다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;따라서 저장하려는 데이터가 Credential한 정보 즉, ID/Passwd 등 인 경우, configMap 대신 시크릿(Secret) 또는 3rd Party 툴을 사용하여 데이터를 비공개로 유지하는 것이 바람직하다.&lt;/span&gt;&lt;/p&gt;

&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;ConfigMap 적용&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;configMap을 사용하여 Pod에서 참조할 수 있도록 구성하는 방법으로는 크게 네가지 방법을 제시할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;1) 컨테이너 내에서 CLI 또는 ARGS로 참조&lt;br /&gt;2) 컨테이너의 환경 변수&amp;nbsp;&lt;br /&gt;3) 애플리케이션이 참조할 수 있도록 읽기 전용 볼륨에 파일을 추가하여 참조&lt;br /&gt;4) 쿠버네티스 API를 사용하여 컨피그맵을 읽는 파드 내에서 실행할 코드 작성&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이러한 방법들은 소비되는 데이터를 모델링하는 방식에 따라 다르게 쓰인다.&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;처음 세 가지 방법의 경우, kubelet이 Pod내 컨테이너를 시작할 때 configMap의 데이터를 사용한다.&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;네 번째 방법은 configMap과 데이터를 읽기 위해 코드를 작성해야 한다는 것을 의미한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;먼저 간단히 샘플을 작성하여 테스트 해보도록 하자.&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;샘플은 Spring Boot 환경 기반 application.properties에 env를 적용하고 configMap으로 변경하여 반영하는 방법이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;a. 소스코드 작성&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;application.properties&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;echo.log.level=Debug&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;HelloController.java&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;crystal&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package com.sonnara.k8s;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {
	@Value(&quot;${echo.log.level}&quot;)
	String echoLogLevel;

	@RequestMapping(value = &quot;/hello&quot;, method = RequestMethod.GET)
	public String hello() {
		return &quot;Hi MSA World!&quot; + &quot; &quot; + echoLogLevel;

	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;위와 같이 적용하고 호출하면, 아래와 같이 화면에 출력되는 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CfiYm/btqSGimLips/cM8MCxwjwETu1FW4nkYuCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CfiYm/btqSGimLips/cM8MCxwjwETu1FW4nkYuCk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CfiYm/btqSGimLips/cM8MCxwjwETu1FW4nkYuCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCfiYm%2FbtqSGimLips%2FcM8MCxwjwETu1FW4nkYuCk%2Fimg.png&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;이를 configMap에 적용하기 위해 다음과 같이 application.properties를 수정한다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;echo.log.level=${&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;LOG_LEVEL&lt;/span&gt;&lt;/b&gt;}&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;font-size: 1.12em; letter-spacing: 0px;&quot;&gt;b. configMap.yaml 작성&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;이제 LOG_LEVEL이라는 환경 변수를 configMap으로부터 받아 HelloController.java에 매핑 시켜주면 완성이다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;apiVersion:&amp;nbsp;v1 &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;kind:&amp;nbsp;ConfigMap &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;metadata: &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;name:&amp;nbsp;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;loglevel-configmap&lt;/span&gt; &lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;data: &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;b&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;loglevel&lt;/span&gt;&lt;/b&gt;:&amp;nbsp;DEBUG&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;위는 loglevel이라는 key와 INFO라는 value를 갖는 loglevel-configmap이라는 이름의 ConfigMap을 정의한 yaml 파일이다. &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이를 deployment.yaml과 매핑하여 Container 내부 env로 전달한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;c. deployment.yaml 작성&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;apiVersion:&amp;nbsp;apps/v1 &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;kind:&amp;nbsp;Deployment &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;metadata: &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;name:&amp;nbsp;k8s-configmap-deployment &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;labels: &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;app:&amp;nbsp;k8s-configmap &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;spec: &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;replicas:&amp;nbsp;1 &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;selector: &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;matchLabels: &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;app:&amp;nbsp;k8s-configmap &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;template: &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;metadata: &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;labels: &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;app:&amp;nbsp;k8s-configmap &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;spec: &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;containers: &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;name:&amp;nbsp;k8s-configmap &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;image:&amp;nbsp;192.168.123.141:5000/middleware/springboot/configmap:latest &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;imagePullPolicy:&amp;nbsp;Always &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ports: &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;containerPort:&amp;nbsp;8080 &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;env: &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;name:&amp;nbsp;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;LOG_LEVEL &lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;valueFrom: &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;configMapKeyRef:&amp;nbsp; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;name:&amp;nbsp;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;loglevel-configmap&lt;/span&gt; &lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;key:&amp;nbsp;&lt;b&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;loglevel&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;font-size: 1.12em; letter-spacing: 0px;&quot;&gt;configMap이 매핑되어 HelloController의 return echoLogLevel까지 전달되는 과정은 다음과 같이 도식화 해 볼 수 있다.&lt;/span&gt;위와 같이 spec.template.spec.container.env를 활용하여 환경변수를 적용한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/beKzNA/btqSsQyA6CO/xnIyspN9SIpLe0EcDesF21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/beKzNA/btqSsQyA6CO/xnIyspN9SIpLe0EcDesF21/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/beKzNA/btqSsQyA6CO/xnIyspN9SIpLe0EcDesF21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbeKzNA%2FbtqSsQyA6CO%2FxnIyspN9SIpLe0EcDesF21%2Fimg.png&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;작성이 완료되면 각각 apply를 수행하고 테스트를 진행해보자.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cPxkeE/btqSDvAkM3A/9WKotHer6sKHx5qxKXpKs1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cPxkeE/btqSDvAkM3A/9WKotHer6sKHx5qxKXpKs1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cPxkeE/btqSDvAkM3A/9WKotHer6sKHx5qxKXpKs1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcPxkeE%2FbtqSDvAkM3A%2F9WKotHer6sKHx5qxKXpKs1%2Fimg.png&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;위와 같이 configMap에 적용한 key(loglevel)를 기반으로 value 값인 INFO가 함께 출력되는 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;d. config 수정 반영&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;properties 파일이나 @Configuration 어노테이션을 적용할 경우 config를 변경하면, 소스코드 빌드/패키징 부터 전체 플로우를 모두 진행한 후 배포를 진행해야 했다. 위와 같이 configMap을 사용하면 아래와 같이 쉽게 적용이 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;routeros&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-114-198 ~]# kubectl edit configmap loglevel-configmap
# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: v1
data:
  loglevel: TRACE
kind: ConfigMap
metadata:
  creationTimestamp: &quot;2021-01-05T00:59:13Z&quot;
  name: loglevel-configmap
  namespace: default
  resourceVersion: &quot;221016&quot;
  selfLink: /api/v1/namespaces/default/configmaps/loglevel-configmap
  uid: 3b9c36a7-910e-49a1-a3a0-6d05b7a0628b
configmap/loglevel-configmap edited
[root@ip-192-168-114-198 ~]#&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;위와 같이 kubectl edit (loglevel: TRACE)로 변경한 후&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@ip-192-168-114-198 ~]# kubectl rollout restart deployment/k8s-configmap-deployment
deployment.apps/k8s-configmap-deployment restarted
[root@ip-192-168-114-198 ~]# kubectl get pods
NAME                                        READY   STATUS        RESTARTS   AGE
k8s-configmap-deployment-76d87bc586-m7z28   0/1     Terminating   0          19m
k8s-configmap-deployment-7d4b6bcc94-t4js7   1/1     Running       0          6s
[root@ip-192-168-114-198 ~]#&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;kubectl rollout으로 deployment를 restart를 하면&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bMVSgU/btqSIYof2zM/TE4CpiWcNZnr0DrlWREkJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMVSgU/btqSIYof2zM/TE4CpiWcNZnr0DrlWREkJ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMVSgU/btqSIYof2zM/TE4CpiWcNZnr0DrlWREkJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMVSgU%2FbtqSIYof2zM%2FTE4CpiWcNZnr0DrlWREkJ0%2Fimg.png&quot; data-origin-width=&quot;0.0&quot; data-origin-height=&quot;0.0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;위와 같이 정상적으로 TRACE로 변경된것을 알 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;configMap만 수정한 후에는 변경된 데이터가 반영되지는 않는다. 앞서 적용 방법에 대해 이야기했듯이 configMap은 kubelet이 pod 내 container를 기동하는 시점에 configmap을 적용하기 때문이다. 다만, 별도로 application level에서 수정하지 않고도 environment가 적용되는 것을 확인할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;

&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Secret 적용&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;a. secret.yaml 작성&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;apiVersion:&amp;nbsp;v1 &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;kind:&amp;nbsp;Secret &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;metadata: &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;name:&amp;nbsp;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;loglevel-secret &lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;data: &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;b&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;loglevel&lt;/span&gt;&lt;/b&gt;:&amp;nbsp;U0UtSU5GTw==&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Secret도 ConfigMap과 동일한 형태로 yaml파일이 작성된다. 다만 plain type의 ConfigMap과 다르게 Base64 형태로 value를 구성한다. &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;configmap의 경우 loglevel: SE-INFO라고 구성한다면, secret은 loglevel: U0UtSU5GTw==으로 구성한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;b. deployment.yaml 작성&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;apiVersion:&amp;nbsp;apps/v1 &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;kind:&amp;nbsp;Deployment &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;metadata: &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;name:&amp;nbsp;k8s-configmap-deployment &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;labels: &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;app:&amp;nbsp;k8s-configmap &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;spec: &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;replicas:&amp;nbsp;1 &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;selector: &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;matchLabels: &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;app:&amp;nbsp;k8s-configmap &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;template: &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;metadata: &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;labels: &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;app:&amp;nbsp;k8s-configmap &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;spec: &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;containers: &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;name:&amp;nbsp;k8s-configmap &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;image:&amp;nbsp;192.168.123.141:5000/middleware/springboot/configmap:latest &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;imagePullPolicy:&amp;nbsp;Always &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ports: &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;containerPort:&amp;nbsp;8080 &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;env: &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;name:&amp;nbsp;CONFIGMAP_LOG_LEVEL &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;valueFrom: &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;configMapKeyRef:&amp;nbsp; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;name:&amp;nbsp;loglevel-configmap &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;key:&amp;nbsp;loglevel &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;name:&amp;nbsp;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;SECRET_LOG_LEVEL&lt;/span&gt; &lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;valueFrom: &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;secretKeyRef:&amp;nbsp; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;name:&amp;nbsp;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;loglevel-secret&lt;/span&gt; &lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; 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;key:&amp;nbsp;&lt;b&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;loglevel&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;configmap과 마찬가지로 deployment.yaml에 정의하며, configMapKeyRef 대신 secretKeyRef에 name과 key를 정의한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;c. 소스코드 작성&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1609906494196&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;application.properties&amp;gt;
echo.secret.log.level=${SECRET_LOG_LEVEL}

&amp;lt;HelloController.java&amp;gt;
@Value(&quot;${echo.secret.log.level}&quot;)
String echoSecretLogLevel;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;위와 같이 ConfigMap과 Secret을 함께 정의한 후 배포 및 호출을 진행해 보자.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wiUHG/btqSIYCGvLD/ln9LpYLnTzm9TYcORkTuWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wiUHG/btqSIYCGvLD/ln9LpYLnTzm9TYcORkTuWK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wiUHG/btqSIYCGvLD/ln9LpYLnTzm9TYcORkTuWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwiUHG%2FbtqSIYCGvLD%2Fln9LpYLnTzm9TYcORkTuWK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;위와 같이 ConfigMap은 Plain 형태 그대로 표출되고, Secret은 Base64로 정의된 Value의 Decode 값이 Return 되는 것을 확인할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이와 같이 Log Level, Database Info, Spring Profile 등 간단한 설정 정보를 Properties 파일로 관리할 수도 있지만, configMap과 secret으로도 손쉽게 적용이 가능하며, 민첩하게 반영이 가능하다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;

&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;결론&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Serif KR';&quot;&gt;Cloud Native Application을 개발하기 위해서는 경량화 된 Runtime Framework를 사용하여 민첩하게 배포하는 것이 무엇보다 중요하다. 단순한 환경 설정을 적용하기 위해 전체 CI/CD 파이프라인을 태우면서 배포해야 하는 것은 민첩성에 부합한다. 코드 레벨을 벗어나 Kubernetes Object 레벨에서 설정을 적용하기를 원한다면, configMap과 secret을 사용해 보자.&lt;/span&gt;&lt;/p&gt;</description>
      <category>③ 클라우드/ⓚ Kubernetes</category>
      <category>ConfigMap</category>
      <category>kubernetes configmap</category>
      <category>kubernetes configserver</category>
      <category>kubernetes secret</category>
      <category>Secret</category>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/681</guid>
      <comments>https://waspro.tistory.com/681#entry681comment</comments>
      <pubDate>Sun, 3 Jan 2021 23:12:54 +0900</pubDate>
    </item>
    <item>
      <title>2021년 waspro 포스팅 예정 내용</title>
      <link>https://waspro.tistory.com/notice/680</link>
      <description>&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;2021년 포스팅 예정&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2021년 신축년 새해가 밝았습니다. 올 한해의 시작은 여전한 포스트 코로나 시대로 시작을 했는데요. 올해 말에는 이전과 같은 평범한 한해로 돌아가 있었으면 좋겠습니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;올해도 여전히 주를 이룰 토픽은 클라우드와 MSA가 될 예정입니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;[MSA &amp;amp; Cloud]&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;i&gt;&lt;s&gt;1) Kubeflow (&lt;a style=&quot;color: #dddddd;&quot; href=&quot;https://waspro.tistory.com/684&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;waspro.tistory.com/684&lt;/a&gt;)&lt;/s&gt;&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2) kubevirt&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;i&gt;&lt;s&gt;3) Docker images 빌드 최적화 (&lt;a style=&quot;color: #dddddd;&quot; href=&quot;https://waspro.tistory.com/692&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;waspro.tistory.com/692&lt;/a&gt;)&lt;/s&gt;&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;i&gt;&lt;s&gt;: 재사용을 위한 docker images의 build 순서를 조정하거나, 불필요한 layer를 줄이는 등의 방법&lt;/s&gt;&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;4) Docker Union 동작방식&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;i&gt;&lt;s&gt;5) DevSecOps 구현 (&lt;a style=&quot;color: #dddddd;&quot; href=&quot;https://waspro.tistory.com/693&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://waspro.tistory.com/693&lt;/a&gt;)&lt;/s&gt;&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;[Kubernetes]&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;s&gt;1) Container 기동 후 Complete 에서 지속 Restart되는 현상 (&lt;a style=&quot;color: #dddddd;&quot; href=&quot;https://waspro.tistory.com/591&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;waspro.tistory.com/591&lt;/a&gt;)&lt;/s&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;s&gt;- Docker Image의 CMD Script가 종료되어 Init으로 기동되는 CMD를 종료되지 않도록 변경해야 하는 방안&lt;/s&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;s&gt;- BASH의 경우 종료되지 않음&lt;/s&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;s&gt;- Shell Script의 완료로 인해 발생 가능함&lt;/s&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;s&gt;2) Container의 Stack Size를 조절하는 방안 (&lt;a style=&quot;color: #dddddd;&quot; href=&quot;https://waspro.tistory.com/689&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;waspro.tistory.com/689&lt;/a&gt;)&lt;/s&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;s&gt;- /etc/docker/daemon.json에 반영&lt;/s&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;s&gt;- default-ulimits name stack hard soft 적용&lt;/s&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;3) kubectl config use-context minikube&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- 다중 클러스터 접근 구성&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;- &lt;a style=&quot;color: #dddddd;&quot; href=&quot;https://kubernetes.io/ko/docs/tasks/access-application-cluster/configure-access-multiple-clusters/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://kubernetes.io/ko/docs/tasks/access-application-cluster/configure-access-multiple-clusters/&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;i&gt;&lt;s&gt;&lt;/s&gt;&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;i&gt;&lt;s&gt;4) kubernetes configMap (&lt;a style=&quot;color: #dddddd;&quot; href=&quot;https://waspro.tistory.com/681&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;waspro.tistory.com/681&lt;/a&gt;)&lt;/s&gt;&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;5) SCC 권한&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;6) POD 강제 재기동&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;7) Pod Topology Spread Constraints&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;8) CSI&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;9) Kuberhealthy&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;10) WSL + Docker and Kubernetes&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;11) KubeInvaders&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;12) Kubefed&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;13) Metallb (ARP PROXY, ARP SPEAKER)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;14) Terraform&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;15) Velero&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;[AWS]&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1) 랜딩존&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;i&gt;&lt;s&gt;&lt;/s&gt;&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;i&gt;&lt;s&gt;2) EKS ALB Rolling Update (readinessGates) (&lt;a style=&quot;color: #dddddd;&quot; href=&quot;https://waspro.tistory.com/682&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;waspro.tistory.com/682&lt;/a&gt;)&lt;/s&gt;&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;3) AWS NETWORK 구조 설계&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;[CI/CD &amp;amp; Framework]&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;i&gt;&lt;s&gt;1) Git branch Strategy (GitLab Issue) (&lt;a style=&quot;color: #dddddd;&quot; href=&quot;https://waspro.tistory.com/710&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://waspro.tistory.com/710&lt;/a&gt;)&lt;/s&gt;&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2) Git sourcetree / Git gitkraken&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;3) Eclipse Sub Project 구조&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;4) Jenkins Pipeline&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- NotifyFailed&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;i&gt;&lt;s&gt;&lt;/s&gt;&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;i&gt;&lt;s&gt;- Multibranch Pipeline (&lt;a style=&quot;color: #dddddd;&quot; href=&quot;https://waspro.tistory.com/707&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://waspro.tistory.com/707&lt;/a&gt;)&lt;/s&gt;&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;5) Jenkins Pipeline Pod Deployment Check Stage&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;i&gt;&lt;s&gt;&lt;/s&gt;&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;i&gt;&lt;s&gt;6) Tekton&lt;/s&gt;&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;i&gt;&lt;s&gt;&lt;/s&gt;&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;i&gt;&lt;s&gt;- 개요 (Pipeline 구성) (&lt;a style=&quot;color: #dddddd;&quot; href=&quot;https://waspro.tistory.com/705&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://waspro.tistory.com/705&lt;/a&gt;)&lt;/s&gt;&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;i&gt;&lt;s&gt;&lt;/s&gt;&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;i&gt;&lt;s&gt;- Architecture 설계 (&lt;a style=&quot;color: #dddddd;&quot; href=&quot;https://waspro.tistory.com/706&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://waspro.tistory.com/706&lt;/a&gt;)&lt;/s&gt;&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;i&gt;&lt;s&gt;&lt;/s&gt;&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;i&gt;&lt;s&gt;- 구축 (&lt;a style=&quot;color: #dddddd;&quot; href=&quot;https://waspro.tistory.com/711&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://waspro.tistory.com/711&lt;/a&gt;)&lt;/s&gt;&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;7) GitlabCI&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;i&gt;&lt;s&gt;&lt;/s&gt;&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;i&gt;&lt;s&gt;8) Atlassian 구축/배포 (&lt;a style=&quot;color: #dddddd;&quot; href=&quot;https://waspro.tistory.com/685&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;waspro.tistory.com/685&lt;/a&gt;, &lt;a style=&quot;color: #dddddd;&quot; href=&quot;https://waspro.tistory.com/687&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;waspro.tistory.com/687&lt;/a&gt;)&lt;/s&gt;&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;9) Atlassian 시점 기반 Commit&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;10) Git Cherry-Pick&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;11) Telepresence&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;12) argoCD&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;13) mockserver&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;14) subtree&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;15) Harbor Image Sign&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- Harbor Image Sign CI/CD 체계 적용&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;i&gt;&lt;s&gt;&lt;/s&gt;&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;i&gt;&lt;s&gt;- Image Sign 설계 (&lt;a style=&quot;color: #dddddd;&quot; href=&quot;https://waspro.tistory.com/716&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://waspro.tistory.com/716&lt;/a&gt;)&lt;/s&gt;&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;[OpenSource Software]&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1) Kafka&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- Kafka NewTopic&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- Kafka sample test 환경&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- Kafka 순서보장&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;i&gt;&lt;s&gt;&lt;/s&gt;&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;i&gt;&lt;s&gt;2) Redis&lt;/s&gt;&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;i&gt;&lt;s&gt;&lt;/s&gt;&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;i&gt;&lt;s&gt;- Cluster 구성하기 (&lt;a style=&quot;color: #dddddd;&quot; href=&quot;https://waspro.tistory.com/696&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://waspro.tistory.com/696&lt;/a&gt;)&lt;/s&gt;&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;i&gt;&lt;s&gt;&lt;/s&gt;&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;i&gt;&lt;s&gt;- Redis Architecture (&lt;a style=&quot;color: #dddddd;&quot; href=&quot;https://waspro.tistory.com/697&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://waspro.tistory.com/697&lt;/a&gt;)&lt;/s&gt;&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;i&gt;&lt;s&gt;&lt;/s&gt;&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;i&gt;&lt;s&gt;- Redis vs Memcached 비교 (&lt;a style=&quot;color: #dddddd;&quot; href=&quot;https://waspro.tistory.com/699&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://waspro.tistory.com/699&lt;/a&gt;)&lt;/s&gt;&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;i&gt;&lt;s&gt;&lt;/s&gt;&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;i&gt;&lt;s&gt;- Redis 운영관리 (&lt;a style=&quot;color: #dddddd;&quot; href=&quot;https://waspro.tistory.com/704&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://waspro.tistory.com/704&lt;/a&gt;)&lt;/s&gt;&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;3) Apache HTTPD&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- SSLSESSIONCOOKIE&lt;br /&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;s&gt;&lt;i&gt;&lt;/i&gt;&lt;/s&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;s&gt;&lt;i&gt;4) Netdata&lt;/i&gt;&lt;/s&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;s&gt;&lt;i&gt;&lt;/i&gt;&lt;/s&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;s&gt;&lt;i&gt;- 구축 활용 (&lt;a style=&quot;color: #dddddd;&quot; href=&quot;https://waspro.tistory.com/712&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://waspro.tistory.com/712&lt;/a&gt;)&lt;/i&gt;&lt;/s&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;s&gt;&lt;i&gt;&lt;/i&gt;&lt;/s&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;s&gt;&lt;i&gt;- 커스터마이징 (&lt;a style=&quot;color: #dddddd;&quot; href=&quot;https://waspro.tistory.com/712&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://waspro.tistory.com/712&lt;/a&gt;)&lt;/i&gt;&lt;/s&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;s&gt;&lt;i&gt;&lt;/i&gt;&lt;/s&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;s&gt;&lt;i&gt;5) Heimdall (&lt;a style=&quot;color: #dddddd;&quot; href=&quot;https://waspro.tistory.com/713&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://waspro.tistory.com/713&lt;/a&gt;)&lt;/i&gt;&lt;/s&gt;&lt;/span&gt;&lt;br /&gt;&lt;i&gt;&lt;u&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/u&gt;&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;i&gt;&lt;u&gt;&lt;span style=&quot;color: #000000;&quot;&gt;#앞으로 추가되는 내용은 계속 업데이트 예정&lt;/span&gt;&lt;/u&gt;&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;올 한해는 코로나로 인해 모두 어려운 한해를 보내왔으며, 그 기조는 앞으로도 당분간 유지될 것으로 보입니다. 모두 힘내서 코로나를 극복하고 힘찬 2021년을 맞이했으면 좋겠습니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;마스크 벗고 맘껏 웃으면서 회식하는 그날이 빨리 돌아오기를 바라며..!&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;# 참조&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- kubectl get pods podsname -n namespaces -o yaml&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- kubectl get pods -w&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- kubectl get service --all-namespaces&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- kubectl --kubeconfig=$HOME/.kube/config rollout restart deployment/test-deployment&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- kubectl create secrets tls / ingress yaml apply&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- docker exec -itu root contianer_name bash&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- watch -n interval &quot;command&quot;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- fuser -ck /dev/sdb1 &amp;amp;&amp;amp; umount /dev/sdb1&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- curl -k (--insecure : https test)&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- curl -X POST \&lt;/span&gt;&lt;br /&gt;http://localhost:8080/servlet \ &lt;br /&gt;-H 'Accept: application/json' \ &lt;br /&gt;-H 'Cache-Control: no-cache' \ &lt;br /&gt;-H 'Content-Type: multipart/mixed' \ &lt;br /&gt;-H 'Postman-Token: 406bfbe4-94d3-0c70-1b0f-0d1fdb2a6f5b' \ &lt;br /&gt;-H 'content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW' \ &lt;br /&gt;-F 'uploadFile=@access_log.2021.01.06' &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <author>GodNR</author>
      <guid isPermaLink="true">https://waspro.tistory.com/notice/680</guid>
      <pubDate>Sat, 2 Jan 2021 11:50:13 +0900</pubDate>
    </item>
  </channel>
</rss>