<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>builder</title>
    <link>https://tigercoin.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Fri, 8 May 2026 19:31:50 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>vataops</managingEditor>
    <image>
      <title>builder</title>
      <url>https://tistory1.daumcdn.net/tistory/4861264/attach/df04d195210f4222892908a3965e000b</url>
      <link>https://tigercoin.tistory.com</link>
    </image>
    <item>
      <title>MetalLB Layer 2, BGP (Border Gateway Protocol) 모드</title>
      <link>https://tigercoin.tistory.com/415</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;MetalLB에 대한 설명은 생략하고, MetalLB의 로드밸런싱 방식인 Layer2와 BGP 모드에 대해서 정리하려고 한다. 현재 네트워크와 서버 환경에 적합한 모드를 선택하는 것은 안정성과 레이턴시 기준에서 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두가지 모드의 장단점을 비교해서 어떤 조건에 어떤 모드가 더 적합할지 정리해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MetalLB는 두개의 컴포넌트로 구성된다. Controller와 Speaker.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1593&quot; data-origin-height=&quot;976&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mU0he/btsK0IeUq6Q/r2ExDMaJ9hC8pQpVKbM370/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mU0he/btsK0IeUq6Q/r2ExDMaJ9hC8pQpVKbM370/img.png&quot; data-alt=&quot;https://www.zentao.pm/blog/kubernetes-load-balancing-scheme-metallb-1345.html&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mU0he/btsK0IeUq6Q/r2ExDMaJ9hC8pQpVKbM370/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmU0he%2FbtsK0IeUq6Q%2Fr2ExDMaJ9hC8pQpVKbM370%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1593&quot; height=&quot;976&quot; data-origin-width=&quot;1593&quot; data-origin-height=&quot;976&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.zentao.pm/blog/kubernetes-load-balancing-scheme-metallb-1345.html&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Controller는 Deployment로 배포되는 반면에, Speaker는 Daemonset으로 노드마다 하나씩 배포된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Controller는 서비스의 변화를 모니터링하는 역할을 하는데, 만약 서비스가 Load Balancer 모드로 구성된다면 Controller는 인터넷 프로토콜 주소를 IP 풀로부터 할당되도록 하며 IP의 라이프 사이클을 관리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면, Speaker는 실제 네트워크 작업을 수행하며, 클러스터 내에서 트래픽을 라우팅하거나 브로드 캐스트하는 역할을 담당한다. 즉, ARP 요청(IPv4) 또는 NDP 요청(IPv6)에 응답하여, 서비스에 할당된 IP 주소를 네트워크에 광고한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;Controller&lt;/b&gt;는 Kubernetes API를 감시하여 IP 주소를 할당하고, 이를 MetalLB 설정에 반영 (특정 Service에 192.168.1.240을 할당)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Speaker&lt;/b&gt;는 Controller의 지시에 따라 실제 네트워크에서 ARP/NDP 광고를 하거나, BGP 라우팅 정보를 업데이트. ( ARP 요청에 &quot;192.168.1.240은 이 노드의 MAC 주소&quot;라고 응답)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 노드가 TCP/UDP 프로토콜을 통해서 트래픽을 받게되면, Kube Proxy는 트래픽을 처리하고 일치하는 서비스의 파드로 분산시키게 된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Layer 2&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Layer 2 모드는 비유를 들자면, 한 동네에서 택배 배달원들이 서로 누가 어떤 물건을 배달할지 결정하는 방식과 비슷하다. 특정 주소에 물건을 배달한다면, 동네에서 가장 가까운 배달원이 요청하여 물건을 배달한다. 여기서 배달원은 MetalLB고 배달할 주소가 LoadBalancer IP다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;레이어2 모드에서는 모든 service IP의 트래픽이 하나의 노드로 가며, kube-proxy가 트래픽을 모든 서비스의 파드로 분산시킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비유에 이어서, 작동 방식을 기술적인 관점에서 설명해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1376&quot; data-origin-height=&quot;703&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cuq5De/btsKSQF2jwc/kmYAkRZrjFy3HMfxrl8kQK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cuq5De/btsKSQF2jwc/kmYAkRZrjFy3HMfxrl8kQK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cuq5De/btsKSQF2jwc/kmYAkRZrjFy3HMfxrl8kQK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcuq5De%2FbtsKSQF2jwc%2FkmYAkRZrjFy3HMfxrl8kQK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1376&quot; height=&quot;703&quot; data-origin-width=&quot;1376&quot; data-origin-height=&quot;703&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;b&gt;Speaker Pod:&lt;/b&gt; MetalLB에서 실행되는 파드로 IP 주소를 소유하고 네트워크로 광고한다. 여기서 각 노드의 Host Network에서 데몬셋으로 행된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Lear Speaker Pod:&lt;/b&gt; 특정 서비스(SVC1, SVC2)의 IP를 소유하는 책임을 가진 Speaker Pod다. 위 그림에서 Node1과 Node3의 Speaker Pod가 각각 리더로 작동한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;iptables:&lt;/b&gt; 노드의 트래픽을 분산 처리하고 DNAT로 올바른 파드로 전달하는 역할을 한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;GARP(Gratuitous ARP):&lt;/b&gt; MetalLB의 Leader Speaker가 자신이 해당 서비스의 IP의 소유자임을 네트워크에 알리기 위해 사용하는 ARP 패킷이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로직의 순서는 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1) 서비스 IP 요청 및 할당&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클라이언트가 특정 LB 서비스의 IP 주소에 연결을 시도한다.&lt;/li&gt;
&lt;li&gt;MetalLB는 Configmap에서 정의된 IP 풀에서 SVC1과 SVC2에 각각 적절한 IP를 할당한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2) Leader Speaker Pod가 GARP로 광고&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SVC1의 IP는 Node1 Speaker Pod가, SVC2의 IP는 Node3 Speaker Pod가 리더 역할을 담당한다.&lt;/li&gt;
&lt;li&gt;각 리더 Speaker Pod는 GARP 패킷을 브로드 캐스트로 네트워크에 뿌려 자신이 해당 IP의 소유자임을 광고한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3) 클라이언트 트래픽 전달&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클라이언트는 SVC1의 IP로 요청을 보낸다.&lt;/li&gt;
&lt;li&gt;네트워크 장비는 GARP 정보를 기반으로 해당 IP 트래픽을 Node1으로 전달한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4) Node의 iptables가 트래픽을 분산 처리&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Node1의 iptables는 SVC1 서비스에 연결된 파드들로 트래픽을 분산처리한다.&lt;/li&gt;
&lt;li&gt;이 과정에서 DNAT를 사용하여 클라이언트의 요청 IP를 실제 파드로 변경한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5) 파드 응답&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;파드는 요청을 처리하고 응답을 클라이언트로 반환해준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주요 특징은 BGP에 비해 간단한 설정이 가능하다. 외부 라우터나 BGP 설정없이 GARP, iptables 만으로 동작이 된다. 온프레미스 환경에서 쉽게 구현할 수 있다. &lt;b&gt;특히, 리더 Speaker Pod가 다운될 경우 다른 노드의 Speaker Pod가 GARP를 통해 IP를 인계 받아 서비스를 중단 없이 처리해준다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Layer2의 한계는 &lt;b&gt;단일 노드 병목 현상&lt;/b&gt;과 &lt;b&gt;잠재적으로 느린 failover다. &lt;/b&gt;아무래도 하나의 노드가 모든 트래픽을 받기 때문에 병목 현상이 발생할 수 있으며, 리더 노드의 MAC 주소를 광고하는 gratuitous 패킷 전달의 실패로 failover가 느려지거나 실패할 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 구성이 간단하고 구성에 따라서 효율적으로 활용할 수 있기 때문에 소규모 네트워크에 적합하게 사용될 수 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;BGP (Border Gateway Protocol)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 91px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;특징&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;Layer 2&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;BGP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;트래픽 경로&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;클라이언트 &amp;rarr; 노드 &amp;rarr; 파드&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;클라이언트 &amp;rarr; 라우터 &amp;rarr; 노드 &amp;rarr; 파드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;레이턴시&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;낮은&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;비교적 높음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;스케일&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;소규모 네트워크 적합&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;대규모 네트워크 적합&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;네트워크 부하&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;ARP/NDP 브로드캐스트로 약간 증가&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;라우터의 경로 설정으로 부하 감소&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DevOps/Kubernetes</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/415</guid>
      <comments>https://tigercoin.tistory.com/415#entry415comment</comments>
      <pubDate>Thu, 28 Nov 2024 15:05:18 +0900</pubDate>
    </item>
    <item>
      <title>Kubernetes Calico CNI(Container Network Interface)</title>
      <link>https://tigercoin.tistory.com/414</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;Calico&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kubespray로 클러스터를 구성하면 default CNI로 Calico가 셋업된다. 현재 회사에 구성된 클러스터에 사용되는 CNI만큼, 한번 살펴보려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요즘 Cilium에 대한 언급이 많은데, Cilium은 eBPF 기반으로 L7 네트워크 정책과 보안에 특화되어있어, 고성능 및 세분화된 보안 정책이면 Calico는 Linux 커널의 L3 라우팅 기반으로 BGP(Border Gateway Protocol)을 활용하여 주로 대규모 클러스터 환경에서 기본적인 보안 정책을 지원하며 성능 최적화도 뛰어나다고 알려져있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Calico는 Tigera라는 회사에서 개발했으며, 아래 공식 문서를 참고하면 좋다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1082&quot; data-origin-height=&quot;653&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cey9hD/btsKq11Jx6A/ovl1qY9LTrxmqFKsk3MqSk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cey9hD/btsKq11Jx6A/ovl1qY9LTrxmqFKsk3MqSk/img.png&quot; data-alt=&quot;https://docs.tigera.io/calico/latest/about/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cey9hD/btsKq11Jx6A/ovl1qY9LTrxmqFKsk3MqSk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcey9hD%2FbtsKq11Jx6A%2Fovl1qY9LTrxmqFKsk3MqSk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1082&quot; height=&quot;653&quot; data-origin-width=&quot;1082&quot; data-origin-height=&quot;653&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://docs.tigera.io/calico/latest/about/&lt;/figcaption&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;/li&gt;
&lt;li&gt;베어메탈로 구성된 클러스터부터, EKS, GKE, AKS, OpenShift, VMware, openstack 지원 및 Flannel 통합&lt;/li&gt;
&lt;li&gt;Dataplane으로 iptables, eBPF, VPP, Windows HNX 지원&lt;/li&gt;
&lt;li&gt;클러스터 내의 allow/deny 정책을 namespace, global로 설정가능&lt;/li&gt;
&lt;li&gt;HTTP method, path 등을 통하여 Application L7 정책 강화&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Architecture&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;architecture-calico-deae813300e472483f84d6bfb49650ab.svg&quot; data-origin-width=&quot;222&quot; data-origin-height=&quot;150&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SH28c/btsKqyyYbfg/2ak26iQ4GwiVcNw4KxwiGk/tfile.svg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SH28c/btsKqyyYbfg/2ak26iQ4GwiVcNw4KxwiGk/tfile.svg&quot; data-alt=&quot;https://docs.tigera.io/calico/latest/reference/architecture/overview&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SH28c/btsKqyyYbfg/2ak26iQ4GwiVcNw4KxwiGk/tfile.svg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSH28c%2FbtsKqyyYbfg%2F2ak26iQ4GwiVcNw4KxwiGk%2Ftfile.svg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;931&quot; height=&quot;629&quot; data-filename=&quot;architecture-calico-deae813300e472483f84d6bfb49650ab.svg&quot; data-origin-width=&quot;222&quot; data-origin-height=&quot;150&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://docs.tigera.io/calico/latest/reference/architecture/overview&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Calico-node&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 클러스터 노드에 설치되는 데몬으로 아래와 같이 daemonset과 노드별로 pod가 생성되어 있는 것을 확인할 수 있다. 네트워크 정책 및 라우팅을 관리하며 두가지 핵심 컴포넌트가 존재한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1120&quot; data-origin-height=&quot;133&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbLAWK/btsKsb3qh1u/NChTD62qtKifdZThwAretK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbLAWK/btsKsb3qh1u/NChTD62qtKifdZThwAretK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbLAWK/btsKsb3qh1u/NChTD62qtKifdZThwAretK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbLAWK%2FbtsKsb3qh1u%2FNChTD62qtKifdZThwAretK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1120&quot; height=&quot;133&quot; data-origin-width=&quot;1120&quot; data-origin-height=&quot;133&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;944&quot; data-origin-height=&quot;250&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sbJEY/btsKqrGJSc6/U9CCK45qADFJJ8xnCupMGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sbJEY/btsKqrGJSc6/U9CCK45qADFJJ8xnCupMGK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sbJEY/btsKqrGJSc6/U9CCK45qADFJJ8xnCupMGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsbJEY%2FbtsKqrGJSc6%2FU9CCK45qADFJJ8xnCupMGK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;944&quot; height=&quot;250&quot; data-origin-width=&quot;944&quot; data-origin-height=&quot;250&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Felix: Calico의 주요 에이전트로, 각 노드에서 실행되며, 포드간 네트워크 정책을 설정하고 적용함. IP 테이블을 이용해 네트워크 트래픽을 제어하며, 네트워크 정책을 기반으로 포드간 트래픽을 허용하고 차단함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- BIRD: BGP 라우터로, 각 노드 간 경로 정보를 교환하고 라우팅을 관리함. BGP로 네트워크 경로 설정하고, 노드 간 라우팅 정보를 동기화함.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Kubernetes API Server&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Calico 설정과 상태를 저장하는 데이터 저장소. 초기에는 etcd가 주로 사용되었으나, 현재는 Kubernetes API와 통합하여 상태를 관리. 각 파드에 할당된 IP 주소와 네트워크 정책 등의 정보를 중앙에서 관리.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Typha&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대규모 클러스터에서 사용되는 컴포넌트, 클러스터에 있는 여러 calico-node의 업데이트 정보를 집계하여 Felix에 전달. Felix와 etcd간 직접적인 통신을 줄여 대규모 환경에서 성능을 최적화.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;CNI Plugin&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Calico CNI 플러그인은 쿠버네티스의 네트워크 인터페이스 역할을 담당하여 파드가 생성되거나 삭제될 때 IP 주소를 할당하고 네트워크 설정을 적용. (Kubernetes와 Calico 간의 연결을 담당)&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;CNI IPAM&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 파드에 고유한 IP를 할당하고 할당된 IP 주소를 관리. IP 주소 충돌을 방지하며, 네트워크 자원을 효율적으로 사용할 수 있도록 도움.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;835&quot; data-origin-height=&quot;259&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cIRglN/btsKqBP4kj7/TEXCCwlqWU4O9vxjOxinHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cIRglN/btsKqBP4kj7/TEXCCwlqWU4O9vxjOxinHK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cIRglN/btsKqBP4kj7/TEXCCwlqWU4O9vxjOxinHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcIRglN%2FbtsKqBP4kj7%2FTEXCCwlqWU4O9vxjOxinHK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;835&quot; height=&quot;259&quot; data-origin-width=&quot;835&quot; data-origin-height=&quot;259&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;calicoctl ipam show를 통해서 IPAM 정보를 확인할 수 있다. 할당 가능한 대역대가 현재 많이 남아있는 것을 볼 수 있다.(Blcok은 각 노드에 할당된 Pod CIDR 정보를 말한다)&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Workflow of Calico Architecture&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 파드 생성: Kubernetes는 Calico CNI 플러그인을 호출하여 새 파드에 IP를 할당하고 네트워크 인터페이스를 설정. 여기서 IPAM을 통해 고유 IP 주소가 부여.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. Felix: 각 노드에서 Felix 에이전트가 실행되어 네트워크 정책을 가져와 IP 테이블에 적용. 이를 통해 설정된 네트워크 정책에 따라 파드간 트래픽이 허용되거나 차단.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. BIRD BGP: 각 노드간의 라우팅 정보를 동기화하여 포드 간 L3 통신을 지원. 노드간에 직접 연결된 라우팅 경로를 통해 파드가 서로 통신(VXLAN을 사용하면 vxlan.calico라는 가상 네트워크 인터페이스를 통해서 사용되기 때문에 BIRD 프로세스가 사용되지 않음)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 클러스터 구성에따라 Typha가 calico-node의 상태를 집계하여 최적화하는 작업이 추가된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;calicoctl&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IPAM을 확인해보려면 calicoctl을 이용해야한다. 아래 링크를 참고해서 설치한 후에 ippool의 ip 할당 상태와 pod의 IP를 확인해본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.tigera.io/calico/latest/operations/calicoctl/install&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.tigera.io/calico/latest/operations/calicoctl/install&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1730367712408&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;Install calicoctl | Calico Documentation&quot; data-og-description=&quot;Install the CLI for Calico.&quot; data-og-host=&quot;docs.tigera.io&quot; data-og-source-url=&quot;https://docs.tigera.io/calico/latest/operations/calicoctl/install&quot; data-og-url=&quot;https://docs.tigera.io/calico/latest/operations/calicoctl/install&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.tigera.io/calico/latest/operations/calicoctl/install&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.tigera.io/calico/latest/operations/calicoctl/install&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;Install calicoctl | Calico Documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Install the CLI for Calico.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.tigera.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;666&quot; data-origin-height=&quot;555&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KLViS/btsKsv1ACVk/MwO1RpOl4uv0OQKiKkyDPk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KLViS/btsKsv1ACVk/MwO1RpOl4uv0OQKiKkyDPk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KLViS/btsKsv1ACVk/MwO1RpOl4uv0OQKiKkyDPk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKLViS%2FbtsKsv1ACVk%2FMwO1RpOl4uv0OQKiKkyDPk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;666&quot; height=&quot;555&quot; data-origin-width=&quot;666&quot; data-origin-height=&quot;555&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ippool을 확인해보면, vxlanMode가 Always로 설정된 것을 알 수 있다. Vxlan(Virtual Extensible LAN)은 네트워크 오버레이 기술로, 대규모 쿠버네티스 클러스터나 여러 서브넷에 노드 간 네트워크 트래픽을 안정적으로 전달하는 데 사용된다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;VxLAN&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;L2 데이터 링크 계층의 오버레이 네트워크를 L3 네트워크 위에 생성하여 서로 다른 서브넷에 있는 노드 통신이 가능케한다. 쉽게 말하면, 서로 다른 데이터센터나 서브넷에 있어도 파드들이 같은 가상 네트워크에 연결된 것처럼 통신된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;646&quot; data-origin-height=&quot;131&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cdGzDg/btsKsawMWo2/gkc4Lm93KK0ekm1fHxDJHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cdGzDg/btsKsawMWo2/gkc4Lm93KK0ekm1fHxDJHk/img.png&quot; data-alt=&quot;BGP를 사용하지 않기 때문에 node status는 확인할 수 없다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cdGzDg/btsKsawMWo2/gkc4Lm93KK0ekm1fHxDJHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcdGzDg%2FbtsKsawMWo2%2Fgkc4Lm93KK0ekm1fHxDJHk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;646&quot; height=&quot;131&quot; data-origin-width=&quot;646&quot; data-origin-height=&quot;131&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;BGP를 사용하지 않기 때문에 node status는 확인할 수 없다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 모드를 사용하면 BGP가 필요없으며, 16만 개 이상의 가상 네트워크를 지원하기 때문에 대규모 클러스터에서 유용하다.&amp;nbsp; 특히 트래픽이 캡슐화되어 전달되기 때문에 노드와 서브넷간에 동일한 IP를 사용하더라도 트래픽이 충돌하지 않는다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;509&quot; data-origin-height=&quot;82&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/V1S8r/btsKrJMWRbX/iuUxc8Km3MKmYmkBSkvTZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/V1S8r/btsKrJMWRbX/iuUxc8Km3MKmYmkBSkvTZK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/V1S8r/btsKrJMWRbX/iuUxc8Km3MKmYmkBSkvTZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FV1S8r%2FbtsKrJMWRbX%2FiuUxc8Km3MKmYmkBSkvTZK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;509&quot; height=&quot;82&quot; data-origin-width=&quot;509&quot; data-origin-height=&quot;82&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;1109&quot; data-origin-height=&quot;83&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cbmrNN/btsKsoIdDlq/ovz2WDW7jE86gjzWAxv05K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cbmrNN/btsKsoIdDlq/ovz2WDW7jE86gjzWAxv05K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cbmrNN/btsKsoIdDlq/ovz2WDW7jE86gjzWAxv05K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcbmrNN%2FbtsKsoIdDlq%2Fovz2WDW7jE86gjzWAxv05K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1109&quot; height=&quot;83&quot; data-origin-width=&quot;1109&quot; data-origin-height=&quot;83&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;calicoctl get ippool: default-pool이라는 IP pool이 생성되어있고, CIDR qjadnlrk 10.233.64.0/18로 설정되어있다. Selector는 all()로 설정되어 모든 노드에 이 IP pool이 사용된다. (10.233.64.0/18로 설정된 IP 풀은 10.233.64.1부터 10.233.127.254까지 IP를 포함)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;calicoctl get wep -n arbitrum-full: wep는 workload endpoint를 의미한다. arbitrum-full 네임스페이스의 워크로드에 대한 설정을 확인할 수 있다. IP pool의 CIDR 기준으로 할당된 IP 주소는 10.233.111.195/32, 인터페이스는 cali4f9077be901이다.(각 워크로드에는 고유한 가상 네트워크 인터페이스가 생성)&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;route -n&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1017&quot; data-origin-height=&quot;346&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b3VH4Q/btsKqAXVGFG/MYq2Y1RqtKmtpQldu1UFqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b3VH4Q/btsKqAXVGFG/MYq2Y1RqtKmtpQldu1UFqk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b3VH4Q/btsKqAXVGFG/MYq2Y1RqtKmtpQldu1UFqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb3VH4Q%2FbtsKqAXVGFG%2FMYq2Y1RqtKmtpQldu1UFqk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1017&quot; height=&quot;346&quot; data-origin-width=&quot;1017&quot; data-origin-height=&quot;346&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버의 라우팅 테이블을 살펴보면 calico에 네트워크 경로가 어떻게 구성되어있는지 확인가능하다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Default Route(0.0.0.0)은 기본 라우팅 경로로, 서버가 외부 네트워크와 통신할 때 사용되는 경로이며 enp1s0f0 인터페이스를 사용한다. calico관련된 것은 vxlan.calico, cali207106af9cc, calif1f81b83f47 인터페이스다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;vxlan.calico는 VXLAN 오버레이 네트워크를 통해 노드 간 통신에 VXLAN 터널링이 사용되고 있는 것을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나머지 calico workload interface는 개별 파드의 네트워크 트래픽을 처리하여 10.233.97.128과 10.233.97.131에 직접 연결한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1992&quot; data-origin-height=&quot;75&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dEy4zQ/btsKq02VCe1/NvpXzGRNu7mCiDjvBDZUs1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dEy4zQ/btsKq02VCe1/NvpXzGRNu7mCiDjvBDZUs1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dEy4zQ/btsKq02VCe1/NvpXzGRNu7mCiDjvBDZUs1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdEy4zQ%2FbtsKq02VCe1%2FNvpXzGRNu7mCiDjvBDZUs1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1992&quot; height=&quot;75&quot; data-origin-width=&quot;1992&quot; data-origin-height=&quot;75&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;859&quot; data-origin-height=&quot;53&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Vk9I8/btsKsxruSqR/6JDRgCq1WEZMLz5EjXCim1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Vk9I8/btsKsxruSqR/6JDRgCq1WEZMLz5EjXCim1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Vk9I8/btsKsxruSqR/6JDRgCq1WEZMLz5EjXCim1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVk9I8%2FbtsKsxruSqR%2F6JDRgCq1WEZMLz5EjXCim1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;859&quot; height=&quot;53&quot; data-origin-width=&quot;859&quot; data-origin-height=&quot;53&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;10.233.97.128를 사용하는 파드는 이전에 할당되었다가 삭제되어 발견할 수 없었으나, 10.233.97.131은 dns-autoscaler가 사용하는 ip였다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DevOps/Kubernetes</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/414</guid>
      <comments>https://tigercoin.tistory.com/414#entry414comment</comments>
      <pubDate>Thu, 31 Oct 2024 19:05:16 +0900</pubDate>
    </item>
    <item>
      <title>Lava Network Provider Architecture with Kubernetes</title>
      <link>https://tigercoin.tistory.com/413</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;Lava Network&lt;/h2&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/o7Nzj/btsJVDUQN5x/eNACX79f41EKBGskyfIoJk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o7Nzj/btsJVDUQN5x/eNACX79f41EKBGskyfIoJk/img.png&quot; data-origin-width=&quot;911&quot; data-origin-height=&quot;584&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;37.89&quot; style=&quot;width: 37.4453%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o7Nzj/btsJVDUQN5x/eNACX79f41EKBGskyfIoJk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo7Nzj%2FbtsJVDUQN5x%2FeNACX79f41EKBGskyfIoJk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;911&quot; height=&quot;584&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dOHjyT/btsJ0ihj8vj/UJ79PlOC3E2uG1uCi1Tcw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dOHjyT/btsJ0ihj8vj/UJ79PlOC3E2uG1uCi1Tcw0/img.png&quot; data-origin-width=&quot;1734&quot; data-origin-height=&quot;678&quot; data-is-animation=&quot;false&quot; style=&quot;width: 61.3919%;&quot; data-widthpercent=&quot;62.11&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dOHjyT/btsJ0ihj8vj/UJ79PlOC3E2uG1uCi1Tcw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdOHjyT%2FbtsJ0ihj8vj%2FUJ79PlOC3E2uG1uCi1Tcw0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1734&quot; height=&quot;678&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;Degraded된 것은 Unstaking 중인 프로토콜 (지원종료를 의미)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Lava Network는 탈중앙화된 RPC 프로바이더 플랫폼이자, 블록체인 데이터 서비스를 위한 마켓플레이스를 구축하고 있다. 이를 통해 Infura, Alchemy, AllThatNode와 같은 기존의 RPC 및 API 인프라 제공자뿐만 아니라, 개인이 직접 운영하는 RPC 노드도 탈중앙화된 네트워크를 통해 클라이언트에게 서비스를 제공할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Lava network는 Cosmos SDK 기반으로 구현되었으며, 현재 이더리움, 폴리곤, 솔라나 등 30여 개 이상의 블록체인에 대한 RPC 서비스를 지원한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Lava&amp;nbsp;Network에는&amp;nbsp;크게&amp;nbsp;서비스&amp;nbsp;사용자(Customer),&amp;nbsp;서비스&amp;nbsp;제공자(Provider),&amp;nbsp;그리고&amp;nbsp;네트워크의&amp;nbsp;검증자(Validator)라는&amp;nbsp;세&amp;nbsp;가지&amp;nbsp;주요&amp;nbsp;주체가&amp;nbsp;있다.&amp;nbsp;내가&amp;nbsp;속한&amp;nbsp;팀은&amp;nbsp;다양한&amp;nbsp;프로토콜의&amp;nbsp;노드를&amp;nbsp;운영하고&amp;nbsp;있으며,&amp;nbsp;이를&amp;nbsp;Provider&amp;nbsp;역할을&amp;nbsp;통해&amp;nbsp;기존의&amp;nbsp;서비스로&amp;nbsp;제공되던&amp;nbsp;노드&amp;nbsp;리소스를&amp;nbsp;보다&amp;nbsp;효율적으로&amp;nbsp;활용하고&amp;nbsp;있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Lava Network Components&lt;/h3&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/OQPQY/btsJVN3XFrw/dxVF37hJs2MndrQTiNBtN1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OQPQY/btsJVN3XFrw/dxVF37hJs2MndrQTiNBtN1/img.png&quot; data-origin-width=&quot;1074&quot; data-origin-height=&quot;867&quot; data-is-animation=&quot;false&quot; style=&quot;width: 38.6202%; margin-right: 10px;&quot; data-widthpercent=&quot;39.07&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OQPQY/btsJVN3XFrw/dxVF37hJs2MndrQTiNBtN1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOQPQY%2FbtsJVN3XFrw%2FdxVF37hJs2MndrQTiNBtN1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1074&quot; height=&quot;867&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/be0pWB/btsJY8GQ5ih/ngYNIKSsTKH1LKqoK7wKb0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/be0pWB/btsJY8GQ5ih/ngYNIKSsTKH1LKqoK7wKb0/img.png&quot; data-origin-width=&quot;902&quot; data-origin-height=&quot;467&quot; data-is-animation=&quot;false&quot; style=&quot;width: 60.217%;&quot; data-widthpercent=&quot;60.93&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/be0pWB/btsJY8GQ5ih/ngYNIKSsTKH1LKqoK7wKb0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbe0pWB%2FbtsJY8GQ5ih%2FngYNIKSsTKH1LKqoK7wKb0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;902&quot; height=&quot;467&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Lava Network의 컴포넌트의 역할에 대해서 간단히 설명하면, &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Lava Nework는 Latency, Sync, Availibility 기준으로 높은 QoS를 유지하는 Provider들의 List를 Consumer에게 제공하는 Pairing 작업을 진행하며,&lt;/span&gt; Consumer는 Provider에게 요청(Request)을 보내고, Provider는 RPC 서비스를 Consumer에게 제공한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Latency: 클라이언트가 요청을 전송하고 응답을 받을 때까지 소요되는 시간&lt;/li&gt;
&lt;li&gt;Sync:&amp;nbsp; 노드가 클라이언트에게 반환하는 데이터의 정확성&lt;/li&gt;
&lt;li&gt;Availability: 노드가 다운타임 없이 지속적으로 서비스를 제공하는 능력&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;2060&quot; data-origin-height=&quot;1093&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjfr0R/btsJZ5Cvbh5/KkvbawmxY7lKtxia8KUw11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjfr0R/btsJZ5Cvbh5/KkvbawmxY7lKtxia8KUw11/img.png&quot; data-alt=&quot;Reward types&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjfr0R/btsJZ5Cvbh5/KkvbawmxY7lKtxia8KUw11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbjfr0R%2FbtsJZ5Cvbh5%2FKkvbawmxY7lKtxia8KUw11%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2060&quot; height=&quot;1093&quot; data-origin-width=&quot;2060&quot; data-origin-height=&quot;1093&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Reward types&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Lava network는 위와 같은 Reward Flow를 가지고 있는데, 특히&amp;nbsp;Provider가&amp;nbsp;Staking을&amp;nbsp;할&amp;nbsp;수&amp;nbsp;있으며,&amp;nbsp;Consumer로부터&amp;nbsp;구독(Subscription)&amp;nbsp;보상을&amp;nbsp;받는&amp;nbsp;것이&amp;nbsp;특징이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Consumer의&amp;nbsp;Pairing부터&amp;nbsp;Provider의&amp;nbsp;QoS&amp;nbsp;평가&amp;nbsp;및&amp;nbsp;보상까지&amp;nbsp;모든&amp;nbsp;과정은&amp;nbsp;탈중앙화된&amp;nbsp;Lava&amp;nbsp;Network에서&amp;nbsp;자동으로&amp;nbsp;이뤄진다.&amp;nbsp;RPC&amp;nbsp;노드&amp;nbsp;운영자는&amp;nbsp;이&amp;nbsp;네트워크를&amp;nbsp;통해&amp;nbsp;Provider&amp;nbsp;등록부터&amp;nbsp;보상까지&amp;nbsp;모든&amp;nbsp;과정을&amp;nbsp;자체적으로&amp;nbsp;진행할&amp;nbsp;수&amp;nbsp;있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Lava Provider Architecture&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 아키텍처에서는 단일 서버에 Provider를 Docker로 구성하여 모든 프로토콜의 요청을 nginx로 받아서 처리해왔다. Provider는 Lava Network와 통신도 필요하기 때문에 &amp;nbsp;같은 서버에 Lava RPC Node도 함께 구성되어 있었다.결국, Nginx, Provider, Lava RPC Node가 하나의 서버에서 작동하면서 SPOF(단일 장애점) 리스크가 있었다. 또한, 하나의 Provider 프로세스에서 모든 프로토콜의 요청을 처리했기 때문에 프로토콜의 health 체크와 관리가 어려운 문제도 존재했다.&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/ejkgeg/btsJZT9V2du/VcEjEVg1gz68i0Od9TDoxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ejkgeg/btsJZT9V2du/VcEjEVg1gz68i0Od9TDoxk/img.png&quot; data-origin-width=&quot;777&quot; data-origin-height=&quot;882&quot; data-is-animation=&quot;false&quot; style=&quot;width: 42.7997%; margin-right: 10px;&quot; data-widthpercent=&quot;43.3&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ejkgeg/btsJZT9V2du/VcEjEVg1gz68i0Od9TDoxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fejkgeg%2FbtsJZT9V2du%2FVcEjEVg1gz68i0Od9TDoxk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;777&quot; height=&quot;882&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cI80AC/btsJZRLbLpM/nOaqWTOthZsRu4pc7wD5ck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cI80AC/btsJZRLbLpM/nOaqWTOthZsRu4pc7wD5ck/img.png&quot; data-origin-width=&quot;1060&quot; data-origin-height=&quot;919&quot; data-is-animation=&quot;false&quot; style=&quot;width: 56.0375%;&quot; data-widthpercent=&quot;56.7&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cI80AC/btsJZRLbLpM/nOaqWTOthZsRu4pc7wD5ck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcI80AC%2FbtsJZRLbLpM%2FnOaqWTOthZsRu4pc7wD5ck%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/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;919&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;좌: 기존 아키텍처, 우: 개선한 아키텍처&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Provider는 더 많은 요청을 받기 위해서 더 많은 Consumer와 페어링되어야 했으며, 그 기준은 Latency와 Availbility, Sync QoS로 결정된다. 그래서 프로토콜과 리전에 따라 Provider를 구성하여 트래픽 분산, 효율적인 Config 관리와 빠른 배포 등 Provider의 효율적인 관리를 통해 QoS를 높이고 서비스의 안정성을 높일 필요가 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 점에서, 쿠버네티스(Kubernetes)가 Provider 구성을 최적화하기에 적합하다고 판단했다. Provider마다 Pod로 구하여 트래픽을 분산할 수 있으며, Helm&amp;nbsp;chart를&amp;nbsp;통해&amp;nbsp;리전과&amp;nbsp;프로토콜별로&amp;nbsp;일관된&amp;nbsp;배포와&amp;nbsp;설정&amp;nbsp;관리가&amp;nbsp;가능했으며,&amp;nbsp;ArgoCD를&amp;nbsp;이용한&amp;nbsp;GitOps&amp;nbsp;방식의&amp;nbsp;빠르고&amp;nbsp;효율적인&amp;nbsp;배포가&amp;nbsp;가능했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만,&amp;nbsp;현재&amp;nbsp;베어메탈&amp;nbsp;기반의&amp;nbsp;Kubernetes&amp;nbsp;클러스터를&amp;nbsp;사용하고&amp;nbsp;있어&amp;nbsp;TLS를&amp;nbsp;적용해&amp;nbsp;443&amp;nbsp;포트를&amp;nbsp;사용하기에는&amp;nbsp;한계가&amp;nbsp;있었다.&amp;nbsp;외부&amp;nbsp;통신에&amp;nbsp;NodePort를&amp;nbsp;사용해야&amp;nbsp;했기&amp;nbsp;때문에&amp;nbsp;30000-32767&amp;nbsp;범위의&amp;nbsp;포트만&amp;nbsp;서버에서&amp;nbsp;노출할&amp;nbsp;수&amp;nbsp;있었고,&amp;nbsp;Lava&amp;nbsp;재단에서도&amp;nbsp;Consumer의&amp;nbsp;outbound에&amp;nbsp;443&amp;nbsp;포트만&amp;nbsp;허용한다면&amp;nbsp;요청이&amp;nbsp;차단되는&amp;nbsp;문제가&amp;nbsp;발생할&amp;nbsp;수&amp;nbsp;있다고&amp;nbsp;지적해&amp;nbsp;443&amp;nbsp;포트로&amp;nbsp;노출할&amp;nbsp;방법을&amp;nbsp;고민해야&amp;nbsp;했다.&lt;br /&gt;&lt;br /&gt;물론 MetalLB같은 로드밸런싱 오픈소스 툴을 이용할 순 있으나, 오버엔지니어링이 될 수 있다는 판단하에, 443 port를 사용할 효율적인 방법이 필요했다. (클러스터의 안정적인 운영을 위해 api server의 --service-node-port-range 를 손대고 싶진 않았음)&lt;/p&gt;
&lt;pre id=&quot;code_1728470768956&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;http {
    server_names_hash_bucket_size 128;
    
    server {
        listen 443 ssl http2;
        server_name lavap-testnet-ftm-eu.{ domain }.com;

        ssl_certificate /etc/letsencrypt/live/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/privkey.pem;
        error_log /var/log/nginx/ftm.log debug;

        location / {
            proxy_pass http://fantom-lavap-testnet-eu-v1-provider.lavap-testnet-eu.svc.cluster.local:2200;
            grpc_pass fantom-lavap-testnet-eu-v1-provider.lavap-testnet-eu.svc.cluster.local:2200;
        }
    }

    server {
        listen 443 ssl http2;
        server_name lavap-testnet-ftm-eu-metrics.{ domain }.com;

        ssl_certificate /etc/letsencrypt/live/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/privkey.pem;
        error_log /var/log/nginx/ftm.log debug;

        location / {
            proxy_pass http://fantom-lavap-testnet-eu-v1-provider.lavap-testnet-eu.svc.cluster.local:3200;
        }
    }
   }&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;nginx conf&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 현재 Kubespray로 구성한 클러스터는 Nginx 프로세스를 통해 API 서버와 kubelet이 통신하고 있어, 자칫 클러스터 통신에 영향을 줄 수 있는 부분도 고려해야 했다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1712&quot; data-origin-height=&quot;1098&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sX8JZ/btsJ0Q7v4JR/MwH1RI44q4Kc07FbDsnrnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sX8JZ/btsJ0Q7v4JR/MwH1RI44q4Kc07FbDsnrnk/img.png&quot; data-alt=&quot;현재 구성된 클러스터의 nginx proxy - kube apiserver&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sX8JZ/btsJ0Q7v4JR/MwH1RI44q4Kc07FbDsnrnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsX8JZ%2FbtsJ0Q7v4JR%2FMwH1RI44q4Kc07FbDsnrnk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1712&quot; height=&quot;1098&quot; data-origin-width=&quot;1712&quot; data-origin-height=&quot;1098&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;현재 구성된 클러스터의 nginx proxy - kube apiserver&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다행히도, 클러스터에서 사용되는 Nginx는 시스템 프로세스로 실행되지 않았기 때문에, TLS를 적용한 Nginx를 시스템 프로세스로 실행하여 외부 요청을 받아 내부 클러스터의 서비스로 라우팅하는 방법을 고안했다. Nginx 프록시는 요청된 도메인에 따라 지정된 서비스(ClusterIP)로 요청을 라우팅하며, 클러스터 내부 서버의 Nginx 프록시이기 때문에 Kubernetes의 coreDNS를 활용해 이를 지정할 수 있었다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Github Action - Helm chart - ArgoCD&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1333&quot; data-origin-height=&quot;693&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pzg0x/btsJZvV0tkK/0KJp7EYYKVfj9dlTcw95zk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pzg0x/btsJZvV0tkK/0KJp7EYYKVfj9dlTcw95zk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pzg0x/btsJZvV0tkK/0KJp7EYYKVfj9dlTcw95zk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fpzg0x%2FbtsJZvV0tkK%2F0KJp7EYYKVfj9dlTcw95zk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1333&quot; height=&quot;693&quot; data-origin-width=&quot;1333&quot; data-origin-height=&quot;693&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Lava Network에서 공식적으로 지원되는 Docker 이미지가 아직 없기 때문에, 신규 버전이 릴리즈될 때마다 직접 Docker 이미지를 빌드하고 업그레이드를 진행해야 한다. 이 과정을 최대한 자동화시키기 위해서 Github action을 통해 Image를 빌드하여 Registry에 Push하면, Workflow의 마지막 단에서 Helm chart의 tag를 변경하고, ArgoCD에서 최종적으로 배포하는 파이프라인을 구성했다.&lt;/p&gt;
&lt;pre id=&quot;code_1728470983641&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;chains:
  - id: ETH1
    name: ethereum
    nodeRegion: germany
    configYaml: |
      endpoints:
        - chain-id: ETH1
          api-interface: jsonrpc
          network-address:
            address: 0.0.0.0:2200
            disable-tls: true
          node-urls:
            - url: &quot;http://{ ip }:8545&quot;
            - url: &quot;http://{ ip }:8545&quot;
              addons:
                - archive
  - id: SEP1
    name: sepolia
    nodeRegion: germany
    configYaml: |
      endpoints:
        - chain-id: SEP1
          api-interface: jsonrpc
          network-address:
            address: 0.0.0.0:2200
            disable-tls: true
          node-urls:
            - url: &quot;http://{ ip }:8545&quot;
            - url: &quot;http://{ ip }:8545&quot;
              addons:
                - archive&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;values.yaml&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Lava network에서 작성한 Helm chart가 있지만, 아쉽게도 직접 사용해본 결과 Provider 배포에 있어서 에러가 발생했다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Lava network official helm chart : &lt;a href=&quot;https://github.com/lavanet/helm-charts&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/lavanet/helm-charts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1728471450836&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 - lavanet/helm-charts:   Helm charts for Lava services&quot; data-og-description=&quot;  Helm charts for Lava services. Contribute to lavanet/helm-charts development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/lavanet/helm-charts&quot; data-og-url=&quot;https://github.com/lavanet/helm-charts&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/yz7Fx/hyXd5DbFZD/YYHJLEIb7OdiFR0kKNNqTK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/bozyn7/hyXeefQzac/MFiMjB4q0KPK5IH87xGVk0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/lavanet/helm-charts&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/lavanet/helm-charts&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/yz7Fx/hyXd5DbFZD/YYHJLEIb7OdiFR0kKNNqTK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/bozyn7/hyXeefQzac/MFiMjB4q0KPK5IH87xGVk0/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 - lavanet/helm-charts:   Helm charts for Lava services&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;  Helm charts for Lava services. Contribute to lavanet/helm-charts 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;이&amp;nbsp;문제는&amp;nbsp;template/secret.yaml에서&amp;nbsp;config.yml&amp;nbsp;생성&amp;nbsp;시&amp;nbsp;잘못된&amp;nbsp;규칙이&amp;nbsp;적용되어&amp;nbsp;발생한&amp;nbsp;것이었다.&amp;nbsp;이를&amp;nbsp;해결하기&amp;nbsp;위해,&amp;nbsp;나는&amp;nbsp;각&amp;nbsp;프로토콜의&amp;nbsp;전체&amp;nbsp;config를&amp;nbsp;values.yaml에서&amp;nbsp;직접&amp;nbsp;생성할&amp;nbsp;수&amp;nbsp;있도록&amp;nbsp;Helm&amp;nbsp;chart를&amp;nbsp;수정하여,&amp;nbsp;위&amp;nbsp;values.yaml처럼&amp;nbsp;쉽게&amp;nbsp;디버깅할&amp;nbsp;수&amp;nbsp;있게&amp;nbsp;했다.&lt;br /&gt;&lt;br /&gt;또한,&amp;nbsp;config에서&amp;nbsp;노출되는&amp;nbsp;정보가&amp;nbsp;node-url뿐이기&amp;nbsp;때문에,&amp;nbsp;굳이&amp;nbsp;Secret을&amp;nbsp;사용할&amp;nbsp;필요가&amp;nbsp;없어&amp;nbsp;Secret을&amp;nbsp;ConfigMap으로&amp;nbsp;변경했다.&lt;br /&gt;&lt;br /&gt;추가적으로, 노드마다 region과 노드 이름을 기준으로 라벨을 설정하여, Deployment마다 원하는 리전이나 노드에 배포할 수 있도록 Helm chart를 구성했다. 특히, Helm chart에서는 region을 기준으로 구분하고, 하나의 Helm chart에서 여러 프로토콜의 provider를 각기 다른 Config로 배포할 수 있도록 설계했다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2557&quot; data-origin-height=&quot;953&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m1Xr6/btsJ4tCSXjD/rXvb1uXgVeSx07z5RbM66k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m1Xr6/btsJ4tCSXjD/rXvb1uXgVeSx07z5RbM66k/img.png&quot; data-alt=&quot;EU region providers dashboard&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m1Xr6/btsJ4tCSXjD/rXvb1uXgVeSx07z5RbM66k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm1Xr6%2FbtsJ4tCSXjD%2FrXvb1uXgVeSx07z5RbM66k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2557&quot; height=&quot;953&quot; data-origin-width=&quot;2557&quot; data-origin-height=&quot;953&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;EU region providers dashboard&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1644&quot; data-origin-height=&quot;797&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IaEDK/btsJZ9x9fnu/s8hnV3VWNB0FWcf8MnSkzK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IaEDK/btsJZ9x9fnu/s8hnV3VWNB0FWcf8MnSkzK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IaEDK/btsJZ9x9fnu/s8hnV3VWNB0FWcf8MnSkzK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIaEDK%2FbtsJZ9x9fnu%2Fs8hnV3VWNB0FWcf8MnSkzK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1644&quot; height=&quot;797&quot; data-origin-width=&quot;1644&quot; data-origin-height=&quot;797&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;Provider Health check&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과적으로 Provider의 효율적인 운영과 배포가 가능해졌으며, 3가지 QoS 점수도 높이고 있다. 위 Health check는 Lava Testnet이며, 아직 Mainnet에는 Lava와 Cosmos만 지원한다. 앞으로 Lava Provider를 잘 활용하면 비용만 나가는 DevOps 팀에서 직접적으로 많은 수익을 가져올 수 있지 않을까... 하는 생각...을 해본다.&lt;/p&gt;</description>
      <category>DevOps/Kubernetes</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/413</guid>
      <comments>https://tigercoin.tistory.com/413#entry413comment</comments>
      <pubDate>Sun, 6 Oct 2024 16:29:39 +0900</pubDate>
    </item>
    <item>
      <title>Constraint ${attr.consul.version} semver &amp;gt;= 1.8.0 1 nodes excluded by filter 에러 해결 방법</title>
      <link>https://tigercoin.tistory.com/412</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1422&quot; data-origin-height=&quot;350&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cX0SHl/btsHSYk0APF/YcFGswX5JNNPr8nx9KUInK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cX0SHl/btsHSYk0APF/YcFGswX5JNNPr8nx9KUInK/img.png&quot; data-alt=&quot;https://developer.hashicorp.com/nomad/docs/job-specification/service&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cX0SHl/btsHSYk0APF/YcFGswX5JNNPr8nx9KUInK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcX0SHl%2FbtsHSYk0APF%2FYcFGswX5JNNPr8nx9KUInK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1422&quot; height=&quot;350&quot; data-origin-width=&quot;1422&quot; data-origin-height=&quot;350&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://developer.hashicorp.com/nomad/docs/job-specification/service&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;service block은 port와 health check 등 job의 네트워크 서비스 디스커버리 및 헬스체크에 사용되는 것으로 provider의 기본 default값이 consul로 되어있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 nomad를 consul과 통합하여 사용하지 않는다면 아래와 같이 service의 provider에 nomad를 지정할 필요가 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1717829547522&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;      service {
        name = &quot;arbitrum-one&quot;
        port = &quot;http&quot;
        tags = [&quot;http&quot;]
	provider = &quot;nomad&quot;
        check {
          type     = &quot;tcp&quot;
          port     = &quot;http&quot;
          interval = &quot;10s&quot;
          timeout  = &quot;2s&quot;
        }
      }&lt;/code&gt;&lt;/pre&gt;</description>
      <category>DevOps/Nomad x Consul</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/412</guid>
      <comments>https://tigercoin.tistory.com/412#entry412comment</comments>
      <pubDate>Sat, 8 Jun 2024 15:54:55 +0900</pubDate>
    </item>
    <item>
      <title>Nomad 베어메탈 서버에 Arbitrum full node 컨테이너로 배포하기</title>
      <link>https://tigercoin.tistory.com/411</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Nomad는 내가 보기엔 아주 유용한 오케스트레이션 툴이지만, 국내에는 자료가 많이 없다. 직접 Nomad로 현재 운영 중인 베어메탈 서버에 Arbitrum full node를 배포해보는 테스트를 진행하려 한다. 그 과정에서 간단한 개념도 정리하려함.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Nomad install&lt;/h3&gt;
&lt;pre id=&quot;code_1717818373646&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg

echo &quot;deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main&quot; | sudo tee /etc/apt/sources.list.d/hashicorp.list

sudo apt update &amp;amp;&amp;amp; sudo apt install nomad&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1188&quot; data-origin-height=&quot;138&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yTclQ/btsHRHroqLI/9mkLYwil8HaUVtIORCWrT0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yTclQ/btsHRHroqLI/9mkLYwil8HaUVtIORCWrT0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yTclQ/btsHRHroqLI/9mkLYwil8HaUVtIORCWrT0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyTclQ%2FbtsHRHroqLI%2F9mkLYwil8HaUVtIORCWrT0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1188&quot; height=&quot;138&quot; data-origin-width=&quot;1188&quot; data-origin-height=&quot;138&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;dev 환경의 테스트 용이기 때문에 Nomad를 단일 서버에 클러스터를 배포했다. 실제 production 환경에서는 여러 서버를 통해서 가용성을 보장할 필요가 있다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Nomad UI&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nomad는 Web Ui를 제공하여 서버 스펙, Job과 Variable, Evaluation 등 운영에 유용한 정보들을 쉽게 관리하고 확인할 수 있는 Web Ui도 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트의 리소스와 정보까지도 모두 제공되기 때문에 아주 유용하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2944&quot; data-origin-height=&quot;1068&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4knCt/btsHSX0GByL/dSeh5UZrB4j8eW3W8DICE1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4knCt/btsHSX0GByL/dSeh5UZrB4j8eW3W8DICE1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4knCt/btsHSX0GByL/dSeh5UZrB4j8eW3W8DICE1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4knCt%2FbtsHSX0GByL%2FdSeh5UZrB4j8eW3W8DICE1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2944&quot; height=&quot;1068&quot; data-origin-width=&quot;2944&quot; data-origin-height=&quot;1068&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행되고 있는 job도 실시간으로 모니터링할 수 있으며, 컨트롤 가능하다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Two types of jobs&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아비트럼 노드 배포에 앞서서, job에 대해서 알아보자. job의 종류는 2가지다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Service Job: 예외적인 중단이 있을때까지 길게 운영되는 Job&lt;/li&gt;
&lt;li&gt;Batch Job: 작업이 성공적으로 마무리되면 종료되는 단기적인 Job&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 두가지 block을 이용해서 job의 실행을 확장할 수 있다. parameterized block은 필수적인 혹은 선택적인 입력을 통해서 batch 작업을 트리거할 수 있으며, periodic block은 job이 설정된 시간에 실행되도록 예약할 수 있다.(Nomad의 cron job이라고도 함)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;type의 지정은 job type에서 설정된다. 아래를 보면 redis job은 service, setup job은 batch로 정해진 것을 알 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1717819880758&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# redis job

job &quot;pytechco-redis&quot; {
  type = &quot;service&quot;
  group &quot;ptc-redis&quot; {
    count = 1
    network {
      port &quot;redis&quot; {
        to = 6379
      }
    }
    service {
      name     = &quot;redis-svc&quot;
      port     = &quot;redis&quot;
      provider = &quot;nomad&quot;
    }
    task &quot;redis-task&quot; {
      driver = &quot;docker&quot;
      config {
        image = &quot;redis:7.0.7-alpine&quot;
        ports = [&quot;redis&quot;]
      }
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1717819907309&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# setup job

job &quot;pytechco-setup&quot; {
  type = &quot;batch&quot;
  parameterized {
    meta_required = [&quot;budget&quot;]
  }
  group &quot;ptc-setup&quot; {
    count = 1
    task &quot;ptc-setup-task&quot; {
      # Retrieves the .Address and .Port connection values for
      # redis-svc with nomadService and saves them to env vars
      # NOMAD_META_budget is read from the job's meta vars
      template {
        data        = &amp;lt;&amp;lt;EOH
{{ range nomadService &quot;redis-svc&quot; }}
REDIS_HOST={{ .Address }}
REDIS_PORT={{ .Port }}
{{ end }}
PTC_BUDGET={{ env &quot;NOMAD_META_budget&quot; }}
EOH
        destination = &quot;local/env.txt&quot;
        env         = true
      }
      driver = &quot;docker&quot;
      config {
        image = &quot;ghcr.io/hashicorp-education/learn-nomad-getting-started/ptc-setup:1.0&quot;
      }
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 batch job은 job run을 하면 아래와 같이 'registration successful' 이라는 ouput이 나온다. 이는 batch job이 등록되고 필요에 따라 매개변수와 함께 어떤 이벤트를 위해 job을 실행하기 위해서 등록되었다고 보면 된다.&lt;/p&gt;
&lt;pre id=&quot;:r10g:&quot; class=&quot;arduino&quot; style=&quot;background-color: #0d0e12; color: #d5d7db; text-align: left;&quot;&gt;&lt;code&gt;$ nomad job run pytechco-setup.nomad.hclJob registration successful&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;등록된 job을 일회성으로 실행 시키기 위해선 nomad job dispatch 명령어를 사용하면 된다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Server, Client Configuration&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;nomad는 쿠버네티스의 마스터 노드 역할을 하는 '서버'와 워커 노드 역할을 하는 '클라이언트'로 구성된다. 에이전트 실행을 위해 다음과 같은 hcl 을 구성했고, nomad agent -config={{ configuration.hcl }} 로 실행했다.&lt;/p&gt;
&lt;pre id=&quot;code_1717824304013&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Server

server {
  enabled = true
  bootstrap_expect = 3
}

data_dir = &quot;/opt/nomad&quot;
bind_addr = &quot;0.0.0.0&quot;

log_level = &quot;DEBUG&quot;

advertise {
  http = &quot;SERVER_NODE_IP:4646&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1717824293245&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Client

client {
  enabled = true
  servers = [&quot;SERVER_NODE_IP1:4646&quot;]
}

data_dir = &quot;/opt/nomad&quot;
bind_addr = &quot;0.0.0.0&quot;

log_level = &quot;DEBUG&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Deploy Arbitrum full node&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아비트럼 full node는 공식 문서에선 docker로 실행하라고 가이드하고 있다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1952&quot; data-origin-height=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c1JS4l/btsHR3Onq91/K9JTWow5bytnotUuJu2hN0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c1JS4l/btsHR3Onq91/K9JTWow5bytnotUuJu2hN0/img.png&quot; data-alt=&quot;https://docs.arbitrum.io/run-arbitrum-node/run-full-node&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c1JS4l/btsHR3Onq91/K9JTWow5bytnotUuJu2hN0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc1JS4l%2FbtsHR3Onq91%2FK9JTWow5bytnotUuJu2hN0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1952&quot; height=&quot;600&quot; data-origin-width=&quot;1952&quot; data-origin-height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://docs.arbitrum.io/run-arbitrum-node/run-full-node&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;nitro 도커 이미지를 사용하고, 초기화를 위한 snapshot 파일을 위 URL을 통해서 설정하거나 미리 받아서 경로로 설정할 수 있다. snapshot 데이터가 크기 때문에 미리 베어메탈 서버에 다운로드해놓고 실행하는 것이 좋지만, 빠르게 테스트를 하기 위해서 url로 실행과 동시에 받는 걸로 진행하려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;job을 굳이 2가지로 구성해야한다면 service job은 arbitrum full node, batch job은 snapshot을 다운받는 용도로 실행하면 된다. &lt;br /&gt;&lt;br /&gt;하지만 굳이 batch job을 구성할 필요는 없기에 full node를 위한 service job만 실행하겠다. 위 가이드에 맞추고, 다른 서버에서 테스트한 실행 커맨드를 기준으로 아래와 같은 Job을 구성했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-size: 1.25em; letter-spacing: -1px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;Arbitrum full node Service Job&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1717821717768&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;job &quot;arbitrum-one&quot; {
  datacenters = [&quot;dc1&quot;]
  type = &quot;service&quot;

  group &quot;arbitrum-group&quot; {
    count = 1

    network {
      port &quot;http&quot; {
        static = 8547
      }
      port &quot;ws&quot; {
        static = 8548
      }
      port &quot;metrics&quot; {
        static = 6070
      }
    }

    task &quot;arbitrum-task&quot; {
      driver = &quot;docker&quot;

      config {
        image = &quot;offchainlabs/nitro-node:v2.3.4-b4cc111&quot;
        volumes = [
          &quot;/mnt/arbitrum_nitro:/home/user/.arbitrum&quot;
        ]
        args = [
          &quot;--parent-chain.connection.url&quot;, &quot;{{ L1 RPC }}&quot;,
          &quot;--parent-chain.blob-client.beacon-url&quot;, &quot;{{ L1 BEACON RPC }}&quot;,
          &quot;--chain.id&quot;, &quot;42161&quot;,
          &quot;--http.api&quot;, &quot;net,web3,eth,debug,arbtrace&quot;,
          &quot;--http.corsdomain&quot;, &quot;*&quot;,
          &quot;--http.addr&quot;, &quot;0.0.0.0&quot;,
          &quot;--http.vhosts&quot;, &quot;*&quot;,
          &quot;--ws.port&quot;, &quot;8548&quot;,
          &quot;--ws.addr&quot;, &quot;0.0.0.0&quot;,
          &quot;--ws.origins&quot;, &quot;*&quot;,
          &quot;--init.url&quot;, &quot;https://snapshot.arbitrum.foundation/arb1/nitro-pruned.tar&quot;,
          &quot;--metrics&quot;,
          &quot;--metrics-server.addr&quot;, &quot;0.0.0.0&quot;,
          &quot;--http.server-timeouts.read-header-timeout&quot;, &quot;60s&quot;,
          &quot;--http.server-timeouts.read-timeout&quot;, &quot;60s&quot;,
          &quot;--http.server-timeouts.write-timeout&quot;, &quot;60s&quot;,
          &quot;--execution.sequencer.forwarder.connection-timeout&quot;, &quot;60s&quot;,
          &quot;--execution.forwarder.connection-timeout&quot;, &quot;60s&quot;,
          &quot;--execution.rpc.gas-cap&quot;, &quot;600000000&quot;
        ]
      }

      resources {
        cpu    = 2000
        memory = 2048
      }

      service {
        name = &quot;arbitrum-one&quot;
        port = &quot;http&quot;
        tags = [&quot;http&quot;]
	provider = &quot;nomad&quot;
        check {
          type     = &quot;tcp&quot;
          port     = &quot;http&quot;
          interval = &quot;10s&quot;
          timeout  = &quot;2s&quot;
        }
      }

      service {
        name = &quot;arbitrum-one-ws&quot;
        port = &quot;ws&quot;
        tags = [&quot;ws&quot;]
	provider = &quot;nomad&quot;
        check {
          type     = &quot;tcp&quot;
          port     = &quot;ws&quot;
          interval = &quot;10s&quot;
          timeout  = &quot;2s&quot;
        }
      }

      service {
        name = &quot;arbitrum-one-metrics&quot;
        port = &quot;metrics&quot;
        tags = [&quot;metrics&quot;]
	provider = &quot;nomad&quot;
        check {
          type     = &quot;tcp&quot;
          port     = &quot;metrics&quot;
          interval = &quot;10s&quot;
          timeout  = &quot;2s&quot;
        }
      }
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(datacenter는 설정하지 않을경우 *가 default)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1430&quot; data-origin-height=&quot;660&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IXMiV/btsHSsAepSg/Fc1b67HFwK6RqNeT8G0QLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IXMiV/btsHSsAepSg/Fc1b67HFwK6RqNeT8G0QLk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IXMiV/btsHSsAepSg/Fc1b67HFwK6RqNeT8G0QLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIXMiV%2FbtsHSsAepSg%2FFc1b67HFwK6RqNeT8G0QLk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1430&quot; height=&quot;660&quot; data-origin-width=&quot;1430&quot; data-origin-height=&quot;660&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;job을 배포하면 아래와 같은 과정이 진행된다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;job에 트리거되어 evaluation이 시작&lt;/li&gt;
&lt;li&gt;evaluation은 'bb6dd7b3'에서 배포&lt;/li&gt;
&lt;li&gt;'fc1b199f' 노드에 'arbitrum-group'의 allocation 'cef2df96'이 생성&lt;/li&gt;
&lt;li&gt;evaluation은 allocation에 의해서 pending 에서 complete로 상태변경&lt;/li&gt;
&lt;li&gt;'bb6dd7b3' 배포 진행&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;nomad UI를 확인하면 아래와 같이 job이 진행되고 있는 것을 확인할 수 있다. Deployed 상태에서 Desired는 evaluation 트리거, Placed는 allocation의 배치 단계라고 보면 된다. 만약 Placed가 진행되지 않는다면, allocation 과정에서 문제가 발생했을 가능성이 높다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;job을 작성하고(server), 클라이언트에 할당하여 실행(client)하는 이 두 단계의 로그를 확인해볼 필요가 있다.&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;Allocation (할당)&lt;/b&gt;: 작업이 클라이언트 노드에 할당되어 실행되는 과정.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Evaluation (평가)&lt;/b&gt;: Nomad가 작업의 상태를 평가하고, 필요한 변경 사항을 적용하는 과정.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2166&quot; data-origin-height=&quot;1418&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GioHp/btsHRIjw8mw/EV8FDAXj4k8YNh4W3iOzj0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GioHp/btsHRIjw8mw/EV8FDAXj4k8YNh4W3iOzj0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GioHp/btsHRIjw8mw/EV8FDAXj4k8YNh4W3iOzj0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGioHp%2FbtsHRIjw8mw%2FEV8FDAXj4k8YNh4W3iOzj0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2166&quot; height=&quot;1418&quot; data-origin-width=&quot;2166&quot; data-origin-height=&quot;1418&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;allocation은 노드에 할당하여 실행되는 것으로 아래와 같이 allocation의 로그도 확인가능하다. 로그를 보면 snapshot data를 받고 있는 것을 알 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2150&quot; data-origin-height=&quot;1098&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c1iAvr/btsHScRUI2J/ovkakO95GzX19l5xsQzBpk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c1iAvr/btsHScRUI2J/ovkakO95GzX19l5xsQzBpk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c1iAvr/btsHScRUI2J/ovkakO95GzX19l5xsQzBpk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc1iAvr%2FbtsHScRUI2J%2FovkakO95GzX19l5xsQzBpk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2150&quot; height=&quot;1098&quot; data-origin-width=&quot;2150&quot; data-origin-height=&quot;1098&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Container에 할당된 리소스와 사용중인 리소스를 모니터링할 수 있으며, Container 터미널 실행도 web ui에서 가능하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1710&quot; data-origin-height=&quot;146&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tllve/btsHTltm6hS/bmTKakMEG5lkimQslpgX41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tllve/btsHTltm6hS/bmTKakMEG5lkimQslpgX41/img.png&quot; data-alt=&quot;client에서 실행중인 arbitrum full node&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tllve/btsHTltm6hS/bmTKakMEG5lkimQslpgX41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ftllve%2FbtsHTltm6hS%2FbmTKakMEG5lkimQslpgX41%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1710&quot; height=&quot;146&quot; data-origin-width=&quot;1710&quot; data-origin-height=&quot;146&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;client에서 실행중인 arbitrum full node&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1944&quot; data-origin-height=&quot;906&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFmlnT/btsHSUJSujH/6e054Ua6ad6gGOnTfB5kJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFmlnT/btsHSUJSujH/6e054Ua6ad6gGOnTfB5kJ1/img.png&quot; data-alt=&quot;Container logs&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFmlnT/btsHSUJSujH/6e054Ua6ad6gGOnTfB5kJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFmlnT%2FbtsHSUJSujH%2F6e054Ua6ad6gGOnTfB5kJ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1944&quot; height=&quot;906&quot; data-origin-width=&quot;1944&quot; data-origin-height=&quot;906&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Container logs&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트에서 arbitrum의 docker container가 실행되고 있는 것을 알 수 있다. snapshot 모두 받고 초기화가 된다해도 여기서 끝난것은 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;health check와 log의 특정 조건을 통해 프로세스에서 발생하는 문제를 어떻게 대응할지도 고민해야한다. 실제 운영 환경이라면 서버와 프로세스의 health check + event 모니터링을 위해 Consul 지원도 고려해야한다.&lt;/p&gt;</description>
      <category>DevOps/Nomad x Consul</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/411</guid>
      <comments>https://tigercoin.tistory.com/411#entry411comment</comments>
      <pubDate>Sat, 8 Jun 2024 15:45:46 +0900</pubDate>
    </item>
    <item>
      <title>Hashicorp Nomad Scheduling</title>
      <link>https://tigercoin.tistory.com/410</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;하시코프의 Nomad는 Kubernetes에 비해서 간단하며, 다양한 워크로드를 지원, 지속가능한 배포와 확장성이라는 장점을 가진 오케스트레이션 툴이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 현재 몸담고 있는 회사에선 여러 베어메탈 서버와 컨테이너들을 운영하고 있고 Disk 사이즈도 TB 단위로 사용하는 워크로드가 많다. 이런 조건에선 Kubernetes는 적합하지 않다. Kubernetes를 사용하면 자칫 노드당 하나의 컨테이너만 돌려야할 수 도 있고 바이너리로 실행되는 어플리케이션은 매니징하지도 못한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오케스트레이션에 있어 가장 중요한 기능은 리소스를 효율적으로 관리하는 스케쥴링(Scheduling)이라 생각한다. Nomad의 스케쥴링은 어떤 방식으로 진행되고 어떤 요소들이 있는지 살펴보자.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Nomad Scheduling Concept&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2566&quot; data-origin-height=&quot;1104&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JGYwq/btsHPn7GLob/s514EBuDISUr1wKvUE8w90/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JGYwq/btsHPn7GLob/s514EBuDISUr1wKvUE8w90/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JGYwq/btsHPn7GLob/s514EBuDISUr1wKvUE8w90/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJGYwq%2FbtsHPn7GLob%2Fs514EBuDISUr1wKvUE8w90%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2566&quot; height=&quot;1104&quot; data-origin-width=&quot;2566&quot; data-origin-height=&quot;1104&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;nomad에는 4가지 주요 요소가 있다. Evaluation, Allocation, Node, Job&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Job: 실행할 task의 선언적인 디스크립션으로 제약 조건에 맞춰 리소스를 요구하며, nomad 클라이언트를 운영하는 클러스터가 task를 노드에 할당한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1717665603144&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# nginx 컨테이너를 실행하는 job 예시

job &quot;example-service&quot; {
  region = &quot;global&quot;

  datacenters = [&quot;dc1&quot;]

  type = &quot;service&quot;

  group &quot;example-group&quot; {
    count = 3

    task &quot;web&quot; {
      driver = &quot;docker&quot;

      config {
        image = &quot;nginx:latest&quot;
        ports = [&quot;http&quot;]
      }

      resources {
        cpu    = 500
        memory = 256
      }

      service {
        name = &quot;example-service&quot;
        port = &quot;http&quot;

        check {
          type     = &quot;http&quot;
          path     = &quot;/&quot;
          interval = &quot;10s&quot;
          timeout  = &quot;2s&quot;
        }
      }
    }

    network {
      port &quot;http&quot; {
        static = 8080
      }
    }
  }
}&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;Allocation: Job을 노드에 매핑하는 것은 Allocation을 통해서 이뤄지며 특정 노드에서 실행되는 것을 선언하는데 사용된다. 스케쥴링은 적절한 Allocation을 결정하는 프로세스다.&lt;/li&gt;
&lt;li&gt;Evaluation: 외부 상태의 변경, 요청에 따라서 이뤄진다. 원하는 상태(desired state)는 job을 기반으로 새로운 job이 제출되거나 존재하는 job이 업데이트 되거나 제거되었을때 변하게 된다. 또한 비상 상태(Emergent state)는 클라이언트 노드에 의한 것으로 시스템에서 클라이언트의 실패를 다뤄야하는 상태다.&lt;/li&gt;
&lt;li&gt;Node: Node는 클러스터에 의해서 job을 스케쥴링 받아 실질적으로 task를 수행하는 클라이언트다.&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;902&quot; data-origin-height=&quot;1606&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/be8AmW/btsHRwuTJGl/l00zJpX5U8JwdxTZ8uNk90/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/be8AmW/btsHRwuTJGl/l00zJpX5U8JwdxTZ8uNk90/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/be8AmW/btsHRwuTJGl/l00zJpX5U8JwdxTZ8uNk90/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbe8AmW%2FbtsHRwuTJGl%2Fl00zJpX5U8JwdxTZ8uNk90%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;902&quot; height=&quot;1606&quot; data-origin-width=&quot;902&quot; data-origin-height=&quot;1606&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Evaluation의 라이프사이클은 다음과 같다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Evaluation 트리거&lt;/li&gt;
&lt;li&gt;Evaluation 생성&lt;/li&gt;
&lt;li&gt;Evaluation 큐에 추가&lt;/li&gt;
&lt;li&gt;스케쥴러 서버에 의해 처리&lt;/li&gt;
&lt;li&gt;Allocation 생성&lt;/li&gt;
&lt;li&gt;Allocation 배포 및 실행&lt;/li&gt;
&lt;li&gt;Evaluation 완료&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. Evaluation 트리거&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Evaluation은 다양한 이벤트에 의해 트리거된다. 여기에는 job 제출, 구성 변경, 노드 상태 변경 및 기타 내부 트리거가 포함된다.&lt;br /&gt;새로운 job 제출, 기존 작업 업데이트 또는 노드 장애가 발생하면 Evaluation이 트리거된다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. Evaluation 생성&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트리거 발생하면 Nomad는 새로운 Evaluation을 생성한다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3. Evaluation Queue에 추가&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성된 Evaluation은 스케쥴링을 위해서 Evaluation 브로커의 Queue에 추가된다. 우선순위에 따라서 Evaluation을 정렬하여 처리된다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4. 스케쥴러 서버에 의해서 처리&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스케쥴러는 Evaluation 브로커로부터 Evaluation을 가져와 처리한다. 스케쥴러는 job의 요구사항에 맞춰 job이 가능한 최적의 노드를 찾고 리소스 할당을 결정한다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5. Allocation 생성&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스케쥴러가 적절한 노드를 찾으면 job을 해당 노드에 할당하기 위해서 Allocation을 생성한다. Allocation은 job이 실제로 실행될 수 있는 구체적인 리소스의 할당 단위라고 보면 된다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;6. Allocation 배포 및 실행&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성된 Allocation은 노드에 배포되고 Nomad 클라이언트에 의해서 실행된다.&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;7. Evaluation 완료&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;job이 성공적으로 실행되거나 실패하면 Evaluation은 완료상태가 된다. 완료된 Evaluation은 시스템에서 정리된다. 필요에 따라 로그에 기록된다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Scheduling Placement&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;allocation을 실행할 클라이언트를 선정하는 과정을 Allocation Placement라고 한다. 이 부분은 어플리케이션의 목표 달성을 위한 복원력과 높은 가용성에 중요한 프로세스다.&lt;br /&gt;&lt;br /&gt;Nomad는 기본적으로 모든 노드를 고려하여 Allocation Placement를 진행한다. 이 과정은 에이전트 및 job 구성 파일을 통해 정해진다. Placement의 옵션은 다음과 같다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Affinity &amp;amp; Contraint&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;선호도(Affinity): Affinity는 특정 노드 속성에 대한 Soft Requirement를 정의한다. Placemnet는 affinity 규칙을 따르지만, 규칙을 충족하지 못할 경우 다른 노드에도 배치될 수 있다.&lt;/li&gt;
&lt;li&gt;제약 조건(Constraint): Constraint는 Hard Requirement를 정의한다. 조건을 충족시키지 못하면 job Placemnet가 실패된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Node Class&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;노드 클래스는 노드를 그룹화하는 데 사용된다. 클라이언트 구성 파일의 node_class 매개변수를 통해 설정된다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Node metadata&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;노드 메타데이터는 클라이언트 구성 파일의 meta 매개변수를 통해 지정되거나 nomad node meta 명령 및 /v1/client/metadata API 엔드포인트를 통해 동적으로 지정된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Datacenter&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터센터는 특정 지역의 지리적 위치를 나타내며, &lt;span style=&quot;background-color: #ffffff; color: #3b3d45; text-align: start;&quot;&gt;fault tolerance와&lt;/span&gt;&amp;nbsp;인프라 격리를 위해 사용된다. 에이전트 구성 파일의 datacenter 매개변수를 통해 정의된다. 데이터센터는 job에서 선택적으로 사용된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Node Pool&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;노드 풀은 job의 격리를 위해 노드를 그룹화한다. 에이전트 구성 파일의 node_pool 속성을 통해 구성된다. 노드 풀은 특정 작업에 대해 특정 노드를 사용할 수 있도록 제한하는 데 사용된다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.hashicorp.com/nomad/docs/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://developer.hashicorp.com/nomad/docs/&lt;/a&gt;&lt;/p&gt;</description>
      <category>DevOps/Nomad x Consul</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/410</guid>
      <comments>https://tigercoin.tistory.com/410#entry410comment</comments>
      <pubDate>Thu, 6 Jun 2024 18:18:16 +0900</pubDate>
    </item>
    <item>
      <title>Cardano EUTXO(Extended Unspent Transaction Output)와 Script</title>
      <link>https://tigercoin.tistory.com/409</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;스마트 컨트랙트를 지원하는 대부분의 체인들이 Account 모델인 web3 업계에서, 카르다노는 UTXO 모델을 확장한 EUTXO 모델을 개발하여 새로운 기술과 유스케이스를 만들어가고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비트코인의 UTXO 모델은 단순히 balance의 전송만 가능하지만, 카르다노는 datum, redeemer, context와 같은 구성요소를 접목해 스마트 컨트랙트에 필요한 조건과 검증 매커니즘을 구현했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UTXO 기반에서 트랜잭션의 실행과 스마트컨트랙트의 작동이 어떤 방식으로 이뤄지는지 살펴보려한다.&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;EUTXO&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EUTXO는 UTXO 모델의 확장버전으로, '&lt;b&gt;UTXO model&lt;/b&gt; + &lt;b&gt;Expressiveness of programmability&lt;/b&gt; '이다. 비트코인에서도 간순한 스크립트를 지원하는 데, 카르다노에서는 더 확장된, 다양한 로직을 구현할 수 있는 스크립트를 지원한다고 보면된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카르다노의 개발자 공식문서에서도 ' &lt;span style=&quot;color: #1c1e21; text-align: start;&quot;&gt;Smart contracts are more or less just a piece of code that you write to validate the movement of UTXOs locked in your contract's address.'라는 언급이 있다. 카르다노에서 스마트 컨트랙트는 UTXO의 이동을 검증하는 코드 조각일 뿐이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 카르다노에서는 'smart contract'라기보다 'validator scripts'라고 표현하는 것이 적절할 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EUTXO 모델은 Account 모델에 비해서 &lt;b&gt;더 높은 보안과 수수료 예측가능성, 로컬 검증이 가능, 파편화된 블록체인 상태&lt;/b&gt;라는 특징을 가진다. 이런 특징 덕분에 트랜잭션의 병렬처리가 가능하며, 스마트 컨트랙트가 독립적으로 실행될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스마트 컨트랙트가 처리될 때, 블록 내 순서는 중요하지 않으며, 블록 내 다른 컨트랙트 실행결과가 독립적이기 때문에 공격할 수 있는 여지가 적다. 이게 가능한 것은 다음과 같은 EUTXO의 특징 덕분이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1492&quot; data-origin-height=&quot;524&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Oqu9f/btsHCRGyvoP/VLVUPmWLUZTgMMUnxUOHF0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Oqu9f/btsHCRGyvoP/VLVUPmWLUZTgMMUnxUOHF0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Oqu9f/btsHCRGyvoP/VLVUPmWLUZTgMMUnxUOHF0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOqu9f%2FbtsHCRGyvoP%2FVLVUPmWLUZTgMMUnxUOHF0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1492&quot; height=&quot;524&quot; data-origin-width=&quot;1492&quot; data-origin-height=&quot;524&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;EUTXO Consumption Rules&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;두 에이전트가 같은 EUTXO를 소비하는 것은 불가능함. 경쟁 조건이 발생할 경우, 하나의 트랜잭션만 승인되고 나머지는 거부됨.&lt;/li&gt;
&lt;li&gt;여러 에이전트가 동시에 여러 EUTXO를 소비하는 것이 가능함.&lt;/li&gt;
&lt;li&gt;하나의 EUTXO는 여러 트랜잭션에서 참조될 수 있으나 소비는 한번만 가능함.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비트코인 UTXO 모델에서는 노드가 트랜잭션의 유효성을 먼저 검사한다.&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;노드가 요청된 작업을 수행할 수 있는가&lt;/li&gt;
&lt;li&gt;트랜잭션 작성자가 관련한 data와 input을 제공했는가&lt;/li&gt;
&lt;li&gt;트랜잭션 작성자가 프라이빗키로 디지털 서명을 제공했는가&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 EUTXO는&lt;b&gt; '스크립트 주소로 잠긴 EUTXO를 사용하려는 트랜잭션 유효성을 검사'&lt;/b&gt;하는 추가과정이 진행된다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1435&quot; data-origin-height=&quot;960&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tjFm4/btsHBz8c7vI/1rKAaJLsfU9vQ2N6xleJI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tjFm4/btsHBz8c7vI/1rKAaJLsfU9vQ2N6xleJI1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tjFm4/btsHBz8c7vI/1rKAaJLsfU9vQ2N6xleJI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtjFm4%2FbtsHBz8c7vI%2F1rKAaJLsfU9vQ2N6xleJI1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1435&quot; height=&quot;960&quot; data-origin-width=&quot;1435&quot; data-origin-height=&quot;960&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크립트는 EUTXO를 사용하는 트랜잭션에 권한이 있는지 여부를 결정하는 코드 조각으로, 트랜잭션 유효성 검사를 위해 노드는 스크립트를 번역하고 실행할 수 있는 Plutus script interpreter를 호출한다. Interpreter는 UTXO가 잠긴 주소로 해시가 형성된 스크립트를 실행하게된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;여기서 '해시'는 스크립트의 주소(위에서 Script address)이며, EUTXO가 이 스크립트에 잠겨있다고 볼 수 있다. 그리고, 트랜잭션이 실행될 때 새 EUTXO를 동일한 스크립트 주소에서 잠기게된다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, plutus script에 의해서 EUTXO가 잠기면 해당 EUTXO의 스크립트 코드가 해당 주소와 연결된다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;EUTXO&amp;nbsp;모델의&amp;nbsp;주요&amp;nbsp;구성&amp;nbsp;요소&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Datum: EUTXO에 추가할 수 있는 임의의 데이터로, 스크립트에 상태와 유사한 역할을 한다. 이 상태는 특정 UTXO와 연관되어 있다.&lt;/li&gt;
&lt;li&gt;Redeemer: 트랜잭션이 전달할 수 있는 유저의 argument로, 트랜잭션 작성자가 UTXO를 어떻게 사용할지에 대한 의도이다.&lt;/li&gt;
&lt;li&gt;Context: 트랜잭션에 대한 정보를 나타내는 데이터(inputs, outputs, minted value, redemers, info data, tx fees)&amp;nbsp;&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;1459&quot; data-origin-height=&quot;753&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wMsCP/btsHBewFna8/E9OKlu3iMhqBVcJEiYU81k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wMsCP/btsHBewFna8/E9OKlu3iMhqBVcJEiYU81k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wMsCP/btsHBewFna8/E9OKlu3iMhqBVcJEiYU81k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwMsCP%2FbtsHBewFna8%2FE9OKlu3iMhqBVcJEiYU81k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1459&quot; height=&quot;753&quot; data-origin-width=&quot;1459&quot; data-origin-height=&quot;753&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크립트에 잠긴 EUTXO가 있고, 스크립트는 datum, redeemer, context라는 input 데이터를 기반으로 트랜잭션이 EUTXO를 사용할 수 있는지 여부를 결정하게 된다. 이를 순서대로 더 자세히 정리하면 아래와 같다.&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;Plutus 스크립트 실행과정&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 트랜잭션 작성&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;개발자는 Plutus 스크립트를 작성하여 스마트 컨트랙트 로직을 정의&lt;/li&gt;
&lt;li&gt;작성된 스크립트는 필요한 Datum, Redeemer, Context를 포함하는 트랜잭션과 함께 패키징&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 트랜잭션 제출&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;트랜잭션 작성자는 노드에 트랜잭션을 제출&lt;/li&gt;
&lt;li&gt;트랜잭션에는 스크립트 주소로 잠긴 EUTXO와 관련된 데이터가 포함됨&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 노드 수신 및 검증&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;노드는 제출된 트랜잭션을 수신하여 기본 검증 수행&lt;/li&gt;
&lt;li&gt;트랜잭션 형식이 올바른지, 유효한 서명인지, 필요한 데이터가 있는지 확인&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. Plutus script interpreter 호출&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;노드는 트랜잭션 유효성 검증을 위해 Plutus script interpreter 호출&lt;/li&gt;
&lt;li&gt;트랜잭션에서&amp;nbsp;제공된&amp;nbsp;Datum,&amp;nbsp;Redeemer,&amp;nbsp;Context를&amp;nbsp;입력으로&amp;nbsp;받아&amp;nbsp;Plutus&amp;nbsp;Script를&amp;nbsp;실행&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5. Plutus Script 실행&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Interpreter는 Plutus Script를 실행하여 트랜잭션이 유효한지 검사&lt;/li&gt;
&lt;li&gt;이&amp;nbsp;과정에서&amp;nbsp;스크립트는&amp;nbsp;트랜잭션이&amp;nbsp;EUTXO를&amp;nbsp;사용할&amp;nbsp;권한이&amp;nbsp;있는지,&amp;nbsp;조건을&amp;nbsp;만족하는지를&amp;nbsp;평가&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;6. 리소스 소비 추적 및 수수료 계산&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스크립트 실행 중 리소스 소비가 추적됨&lt;/li&gt;
&lt;li&gt;예상된 리소스 소비량을 초과하면 스크립트 실행이 중지되고 트랜잭션은 거부됨&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;7. 트랜잭션 승인 또는 거부 &lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스크립트가 성공적으로 실행되고 모든 조건을 만족하면, 트랜잭션은 유효하다고 판단되어 블록에 포함됨&lt;/li&gt;
&lt;li&gt;스크립트가 실패하면 트랜잭션은 거부됨&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;8. 트랜잭션이 블록체인에 포함됨&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;유효성이 검증된 트랜잭션은 블록체인에 포함됨&lt;/li&gt;
&lt;li&gt;EUTXO는 소비되고, 새로운 UTXO가 생성되어 블록체인 상태가 업데이트됨&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;9. 트랜잭션 결과 배포 &lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;블록이 네트워크에 전파되면서 모든 참여 노드는 새로운 블록을 수신하고 상태를 업데이트함&lt;/li&gt;
&lt;li&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;1417&quot; data-origin-height=&quot;1004&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EOaHh/btsHDi4UnEN/KZkPy3oDmIBD0Qgf67KqWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EOaHh/btsHDi4UnEN/KZkPy3oDmIBD0Qgf67KqWK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EOaHh/btsHDi4UnEN/KZkPy3oDmIBD0Qgf67KqWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEOaHh%2FbtsHDi4UnEN%2FKZkPy3oDmIBD0Qgf67KqWK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1417&quot; height=&quot;1004&quot; data-origin-width=&quot;1417&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;개발자는 plutus on-chain 코드를 작성하여 패키징한다음, plutus 스크립트가 포함된 트랜잭션을 생성하고 블록체인에 보낸다. 트랜잭션이 블록체인에 저장되면, 다른 트랜잭션을 전송하여 스크립트를 실행할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 스크립트 검증의 경우, 일반 트랜잭션 검증보다 더 많은 리소스를 요구하는데, 카르다노에서는 스크립트 실행에 대한 정확한 수수료를 미리 로컬에서 계산할 수 있다. Script interpreter는 스크립트 실행 중 리소스 소비를 추적하여, 실행 에산이 모두 소진되면 스크립트 평가가 중지되어 결과는 false가 된다. false는 EUTXO가 소비되지 않았다는 것을 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Plutus script는 EUTXO와 연관된 상태와 트랜잭션으로받은 데이터에 작동되며, 그 외엔 전혀 영향을 받지 않는다.&amp;nbsp; 전역 수준, 원장 관점에서 변경되는것은 그저 새 블록이 있을때 주소에서 다른 주소로 EUTXO가 이동되는 것 뿐이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국, 카르다노 기반의 유동성 풀 개념이 있는 어플리케이션은 에이전트들이 풀의 EUTXO를 두고 경쟁하지 않을 수 있도록 하는 것이 중요하다. EUTXO를 소비하는 트랜잭션은 독립적으로 실행되지만, 다른 에어전트가 동일한 EUTXO를 소비하는 경우 충돌이 발생할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빌더들은 이 부분을 고려해 EUTXO를 효율적으로 분할하고 관리하는 전략이 필요하며, EUTXO를 동시에 소비하려는 경쟁 조건을 최소화해야한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developers.cardano.org/docs/smart-contracts/#introduction&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://developers.cardano.org/docs/smart-contracts/#introduction&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://cexplorer.io/article/understanding-utxo-spending-through-a-script&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://cexplorer.io/article/understanding-utxo-spending-through-a-script&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://cardanians.io/en/understanding-cardano-extended-utxo-200&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://cardanians.io/en/understanding-cardano-extended-utxo-200&lt;/a&gt;&lt;/p&gt;</description>
      <category>Cardano</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/409</guid>
      <comments>https://tigercoin.tistory.com/409#entry409comment</comments>
      <pubDate>Sun, 26 May 2024 00:37:01 +0900</pubDate>
    </item>
    <item>
      <title>Cardano CIP-0014 ~ 0068 - Token Standard</title>
      <link>https://tigercoin.tistory.com/408</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;CIP-14, CIP-25, CIP-27, CIP-68는 카르다노의 개선 제안(CIP)에서 token으로 분류되는 것으로, 모두 active 상태기 때문에 알아두면 카르다노 Native token의 표준을 이해하는데 도움이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단히 하나씩 살펴보면,&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1708&quot; data-origin-height=&quot;663&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LlFBy/btsGOKOAJ7b/jHPt6DmKrTGZuUj9V5kwi0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LlFBy/btsGOKOAJ7b/jHPt6DmKrTGZuUj9V5kwi0/img.png&quot; data-alt=&quot;https://cips.cardano.org/?category=Tokens&amp;amp;amp;status=Active&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LlFBy/btsGOKOAJ7b/jHPt6DmKrTGZuUj9V5kwi0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLlFBy%2FbtsGOKOAJ7b%2FjHPt6DmKrTGZuUj9V5kwi0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1708&quot; height=&quot;663&quot; data-origin-width=&quot;1708&quot; data-origin-height=&quot;663&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://cips.cardano.org/?category=Tokens&amp;amp;status=Active&lt;/figcaption&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;CIP-14: 발행되는 네이티브 토큰을 식별하는 고유값인 'Asset Fingerprint'를 도입하는 것&lt;/li&gt;
&lt;li&gt;CIP-25: 네이티브 토큰의 메타데이터 표준을 정의&lt;/li&gt;
&lt;li&gt;CIP-27: 메타데이터를 이용해 세컨 마켓의 로열티 배분 관련된 표준을 정의&lt;/li&gt;
&lt;li&gt;CIP-68: CIP-25의 메타데이터 표준의 한계를 해결하는 것으로, 메타데이터를 위한 reference NFT를 도입&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;CIP-0014 User-Facing Asset Fingerprint&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;asset_fingerprint는 policy id와 asset name을 연결하여 bech32로 인코딩 되어 생성되는 native asset의 고유값이다.&lt;/p&gt;
&lt;pre id=&quot;code_1713584552441&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;- policy_id: 1e349c9bdea19fd6c147626a5260bc44b71635f398b67c59881df209
  asset_name: 504154415445
  asset_fingerprint: asset1hv4p5tv2a837mzqrst04d0dcptdjmluqvdx9k3&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;Mary 에라를 통해 Native asset을 지원하고 나서 policy id와 asset name으로 자산을 식별하는데 한계가 있어 도입되었다. 아래는 asset_fingerprint 생성하는 haskell 코드다.&lt;/p&gt;
&lt;pre id=&quot;code_1713584958497&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;newtype PolicyId = PolicyId ByteString
newtype AssetName = AssetName ByteString
newtype AssetFingerprint = AssetFingerprint Text
 
mkAssetFingerprint :: PolicyId -&amp;gt; AssetName -&amp;gt; AssetFingerprint
mkAssetFingerprint (PolicyId policyId) (AssetName assetName)
    = (policyId &amp;lt;&amp;gt; assetName)
    &amp;amp; convert . hash @_ @Blake2b_160
    &amp;amp; Bech32.encodeLenient hrp . Bech32.dataPartFromBytes
    &amp;amp; AssetFingerprint
  where
    hrp = [humanReadablePart|asset|]&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;CIP-0025 Media Token Metadata Standard&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카르다노 네이티브 토큰을 위한 토큰 메타데이터의 표준을 정의하는 제안이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이더리움의 토큰은 컨트랙트에 종속적인 개념으로, 해당 컨트랙트로 메타데이터를 정의하지만, 카르다노는 ledger의 일부로 transfer는 컨트랙트를 거치지 않으며 개별적인 메타데이터를 정의해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카르다노는 트랜잭션에서 메타데이터를 추가할 수 있기 때문에, 토큰과 메타데이터의 링크를 만드는 것이 가능하다. 고유한 링크 생성을 위해서 토큰이 생성되는 트랜잭션에서 같이 추가해야 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1713585218600&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;721&quot;: {
    &quot;&amp;lt;policy_id&amp;gt;&quot;: {
      &quot;&amp;lt;asset_name&amp;gt;&quot;: {
        &quot;name&quot;: &amp;lt;string&amp;gt;,
        &quot;image&quot;: &amp;lt;uri | array&amp;gt;,
        &quot;mediaType&quot;: image/&amp;lt;mime_sub_type&amp;gt;,
        &quot;description&quot;: &amp;lt;string | array&amp;gt;,
        &quot;files&quot;: [{
          &quot;name&quot;: &amp;lt;string&amp;gt;,
          &quot;mediaType&quot;: &amp;lt;mime_type&amp;gt;,
          &quot;src&quot;: &amp;lt;uri | array&amp;gt;,
          &amp;lt;other_properties&amp;gt;
        }],
        &amp;lt;other properties&amp;gt;
      }
    },
    &quot;version&quot;: &amp;lt;version_id&amp;gt;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적인 구조는 위와 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;transaction_metadatum_label: 721&lt;/li&gt;
&lt;li&gt;policy_id: v1은 text 포맷이지만, v2는 raw byte 지원&lt;/li&gt;
&lt;li&gt;asset_name: v1은 utf-8 인코딩 값, v2는 raw byte 지원&lt;/li&gt;
&lt;li&gt;imgae: 리소스를 가리키는 유효 URI&lt;/li&gt;
&lt;li&gt;description: 설명란, 선택값&lt;/li&gt;
&lt;li&gt;files: 선택값&lt;/li&gt;
&lt;li&gt;version: 지정하지 않으면 v1&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;CIP-0027 CNFT Community Royalties Standard&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카르다노 커뮤니티는 asset의 재판매가 이뤄질 경우 세컨드 마켓을 통해 분배되는 로열티에 많은 니즈가 있으나, 로얄티 배분을 위한 매커니즘, 표준이 정의되지 않은 상태였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CIP-0027는 크리에이터의 로열티 배분에 관련된 제안으로, 스마트 컨트랙트 없이 메타데이터만 가지고도 실행할 수 있 관련 표준을 정의한다.&lt;/p&gt;
&lt;pre id=&quot;code_1713586132002&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{ &quot;777&quot;: 
	{ &quot;rate&quot;: &quot;0.2&quot;, 
		&quot;addr&quot;: &quot;addr1v9nevxg9wunfck0gt7hpxuy0elnqygglme3u6l3nn5q5gnq5dc9un&quot; 
	} 
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;CIP-0027 가이드라인&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CIP-0027의 구현을 위해 새로운 policy 사용이 필요함&lt;/li&gt;
&lt;li&gt;로얄티 태그는 이름 없는 토큰에 쓰여야 하며, 적용될 자산에 사용될 정책을 이용함&lt;/li&gt;
&lt;li&gt;최초로 발행된 명령어 세트만 인정되며, 향후 업데이트되는 것은 무시됨. 크리에이터가 로열티 변경하는 것을 방지하기 위함&lt;/li&gt;
&lt;li&gt;777 태그를 통해 로열티 요청 비율을 나타내는 rate, 로열티를 배분할 주소를 나타내는 addr로 구성됨&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;CIP-0068 Datum&amp;nbsp;Metadata&amp;nbsp;Standard&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CIP-0068은 모든 asset 클래스에 대한 output datum을 사용하는 native token의 metadata 표준 정의하는 것으로, CIP-25 메타데이터 한계를 개선한 제안이다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;CIP-25 문제&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로그래밍이 어려움&lt;/li&gt;
&lt;li&gt;어려운 metadata 업데이트&lt;/li&gt;
&lt;li&gt;plutus validator 검사가 불가능함&lt;/li&gt;
&lt;li&gt;metadata 스푸핑 문제가 발생&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 문제를 해결하기 위해서 CIP-0068은 두 가지 user token, reference NFT asset을 발행해서 활용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;user token은 NFT, FT와 같은 asset 클래스로 전송가능하거나, 어떤 가치를 내재한 것이며, reference NFT는 user token의 참조하여, 잠겨있는 output datum이 user token의 metadata를 포함하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 user token은 사용자의 wallet에 들어있는 자산이고, reference NFT는 해당 자산의 메타데이터를 가지고 있어 참조된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 방법의 장점은 발행자는 reference NFT가 포함된 output datum을 관리하고 락업 할 수 있으며, Plutus v2 스크립트에 의해서 컨트롤될 수 있다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;reference NFT의 ouptut datum&lt;/h4&gt;
&lt;pre id=&quot;code_1713587199272&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;big_int = int / big_uint / big_nint
big_uint = #6.2(bounded_bytes)
big_nint = #6.3(bounded_bytes)
metadata =
  { * metadata =&amp;gt; metadata }
  / [ * metadata ]
  / big_int
  / bounded_bytes
version = int
; Custom user defined plutus data.
; Setting data is optional, but the field is required
; and needs to be at least Unit/Void: #6.121([])
extra = plutus_data
datum = #6.121([metadata, version, extra])&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;metadata: user token의 metadata&lt;/li&gt;
&lt;li&gt;version: version number&lt;/li&gt;
&lt;li&gt;extra: 임의의 plutus data&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Contraints and condtions&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;user token과 reference NFT는 같은 Policy를 가져야 함&lt;/li&gt;
&lt;li&gt;user token은 하나의 reference NFT만 가지고 있음&lt;/li&gt;
&lt;li&gt;user token의 reference NFT는 정해진 네이밍 패턴을 지켜야 함&lt;/li&gt;
&lt;li&gt;두 asset의 asset name에는 asset_name_label에 정의된 패턴이 뒤따름.&lt;/li&gt;
&lt;li&gt;user token과 reference NFT는 동일한 트랜잭션에서 생성될 필요가 없으며, 블록 생성 순서도 중요하지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 언급되는 asset_name_label은 3가지 종류의 토큰을 지정할 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;222: NFT&lt;/li&gt;
&lt;li&gt;333: FT&lt;/li&gt;
&lt;li&gt;444: RFT&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;NFT 예시, Space Pugs #5792&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2154&quot; data-origin-height=&quot;772&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bF94Dd/btsGOfnFIkb/StDwviKH9jKwP83JkAIsg0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bF94Dd/btsGOfnFIkb/StDwviKH9jKwP83JkAIsg0/img.png&quot; data-alt=&quot;https://cexplorer.io/asset/asset1y5vny0we4qnyuy0v6g5ceyjrfsf9tm7sx7lm42/preview#data&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bF94Dd/btsGOfnFIkb/StDwviKH9jKwP83JkAIsg0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbF94Dd%2FbtsGOfnFIkb%2FStDwviKH9jKwP83JkAIsg0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2154&quot; height=&quot;772&quot; data-origin-width=&quot;2154&quot; data-origin-height=&quot;772&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://cexplorer.io/asset/asset1y5vny0we4qnyuy0v6g5ceyjrfsf9tm7sx7lm42/preview#data&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ceplorer에서 임의로 찾은 NFT로, 나와 전혀 관계없음. 위 그림에서 보면 Fingerprint와 policy id를 확인할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1916&quot; data-origin-height=&quot;1061&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhl3Kg/btsGMJQ3a2L/UMcX5YJdWqNjY17FsuShDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhl3Kg/btsGMJQ3a2L/UMcX5YJdWqNjY17FsuShDK/img.png&quot; data-alt=&quot;https://cardanoscan.io/transaction/f3a097e350ac605d0530c3ac6af2343bb3a18a722ff909afddb849b808737413?tab=metadata&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhl3Kg/btsGMJQ3a2L/UMcX5YJdWqNjY17FsuShDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbhl3Kg%2FbtsGMJQ3a2L%2FUMcX5YJdWqNjY17FsuShDK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/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;1061&quot; data-origin-width=&quot;1916&quot; data-origin-height=&quot;1061&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://cardanoscan.io/transaction/f3a097e350ac605d0530c3ac6af2343bb3a18a722ff909afddb849b808737413?tab=metadata&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 Space Pugs는 CIP-0025로 발행되었기 때문에, 메타데이터를 확인하려면 발행했던 트랜잭션의 메타데이터를 봐야 한다. 위 링크를 들어가면 Space Pugs의 #4901과 #5792 가 같이 발행된 것을 알 수 있으며, 아래와 같은 메타데이터를 721 label기준으로 확인이 가능하다.&lt;/p&gt;
&lt;pre id=&quot;code_1713587462069&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#721 label
{
    &quot;afe2e7cdf682ce7b604d2ad30b1171a3eb5867126f066f0eb6a498ef&quot;: {
        &quot;Space Pugs #4901&quot;: {
            &quot;Body&quot;: &quot;Chrome&quot;,
            &quot;Eyes&quot;: &quot;Infra Red Detector&quot;,
            &quot;Head&quot;: &quot;No Head Trait&quot;,
            &quot;Suit&quot;: &quot;Armed and Ready&quot;,
            &quot;name&quot;: &quot;Space Pugs #4901&quot;,
            &quot;Mouth&quot;: &quot;Binary Beam&quot;,
            &quot;files&quot;: [
                {
                    &quot;src&quot;: &quot;ipfs://QmdhfkTkfFr7qVj8SaR1NDqYVGfcWM6WjDKgp62aUww74i&quot;,
                    &quot;name&quot;: &quot;Space Pugs #4901.png&quot;,
                    &quot;mediaType&quot;: &quot;image/png&quot;
                }
            ],
            &quot;image&quot;: &quot;ipfs://QmdhfkTkfFr7qVj8SaR1NDqYVGfcWM6WjDKgp62aUww74i&quot;,
            &quot;Weapon&quot;: &quot;Temporal Rift Generator&quot;,
            &quot;Division&quot;: &quot;Seven&quot;,
            &quot;mediaType&quot;: &quot;image/png&quot;,
            &quot;Background&quot;: &quot;Pink Noir&quot;
        },
        &quot;Space Pugs #5792&quot;: {
            &quot;Body&quot;: &quot;Purple Kaleida&quot;,
            &quot;Eyes&quot;: &quot;Astral Spectrum Analyzer&quot;,
            &quot;Head&quot;: &quot;Pathway&quot;,
            &quot;Suit&quot;: &quot;Jet Pack&quot;,
            &quot;name&quot;: &quot;Space Pugs #5792&quot;,
            &quot;Mouth&quot;: &quot;Playful Snarl&quot;,
            &quot;files&quot;: [
                {
                    &quot;src&quot;: &quot;ipfs://QmZ8wvNic1NufEUZL9yKJ9YCNPn5wRrDt67tt24bd16Dh1&quot;,
                    &quot;name&quot;: &quot;Space Pugs #5792.png&quot;,
                    &quot;mediaType&quot;: &quot;image/png&quot;
                }
            ],
            &quot;image&quot;: &quot;ipfs://QmZ8wvNic1NufEUZL9yKJ9YCNPn5wRrDt67tt24bd16Dh1&quot;,
            &quot;Weapon&quot;: &quot;Ion Storm Generator&quot;,
            &quot;Division&quot;: &quot;Seven&quot;,
            &quot;mediaType&quot;: &quot;image/png&quot;,
            &quot;Background&quot;: &quot;Cherry Red&quot;
        }
    }
}&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;2103&quot; data-origin-height=&quot;1064&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dF9fBj/btsGNcSTn5C/RKNAGhkJUA9RQzekEPZkwK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dF9fBj/btsGNcSTn5C/RKNAGhkJUA9RQzekEPZkwK/img.png&quot; data-alt=&quot;https://www.jpg.store/asset/afe2e7cdf682ce7b604d2ad30b1171a3eb5867126f066f0eb6a498ef53706163652050756773202335373932&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dF9fBj/btsGNcSTn5C/RKNAGhkJUA9RQzekEPZkwK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdF9fBj%2FbtsGNcSTn5C%2FRKNAGhkJUA9RQzekEPZkwK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2103&quot; height=&quot;1064&quot; data-origin-width=&quot;2103&quot; data-origin-height=&quot;1064&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.jpg.store/asset/afe2e7cdf682ce7b604d2ad30b1171a3eb5867126f066f0eb6a498ef53706163652050756773202335373932&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Cardano</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/408</guid>
      <comments>https://tigercoin.tistory.com/408#entry408comment</comments>
      <pubDate>Sat, 20 Apr 2024 13:37:57 +0900</pubDate>
    </item>
    <item>
      <title>Cardano Improvement Proposals(CIP) 카르다노 개선 제안</title>
      <link>https://tigercoin.tistory.com/407</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;Cardano Improvement Proposal&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1936&quot; data-origin-height=&quot;1134&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bUU0bm/btsGCnUkXzY/BuagWGV68Tr04EJGPwhVp1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bUU0bm/btsGCnUkXzY/BuagWGV68Tr04EJGPwhVp1/img.png&quot; data-alt=&quot;https://cips.cardano.org/?category=&amp;amp;amp;search=1&amp;amp;amp;sort=number&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bUU0bm/btsGCnUkXzY/BuagWGV68Tr04EJGPwhVp1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbUU0bm%2FbtsGCnUkXzY%2FBuagWGV68Tr04EJGPwhVp1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1936&quot; height=&quot;1134&quot; data-origin-width=&quot;1936&quot; data-origin-height=&quot;1134&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://cips.cardano.org/?category=&amp;amp;search=1&amp;amp;sort=number&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카르다노에는 CIP(Cardano Improvement Proposals)라는 카르다노 개선 제안 프로세스가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카르다노 생태계 프로세스와, 환경에 대한 변경 및 제안 사항을 간결하게 기술적 내용들을 설명하는 문서다. 카르다노 CIP는 80여개 밖에 되지않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카르다노에 대한 기술적인 혹은 구조적인 내용들은 쉽게 접하기 힘든데, 이 80개의 CIP만 확인하더라도 카르다노의 지갑과 원장, 토큰에 대한 기술적 지식은 쉽게 쌓을 수 있다고 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CIP-1에 목적과 구조, state와 프로세스, 참여자에 대한 세부 사항들이 정리되어있는데, 관련 내용을 간단히 정리해보자. (참고로 CIP-9999은 CIP-1의 확장안으로, 새로운 타입의 문서인 CPS의 정의와 확장된 버전의 CIP 동기부여 섹션이 포함되어 있다)&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Cardano Improvement Proposals #1&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1247&quot; data-origin-height=&quot;668&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b7Sbt4/btsGBsoxDmO/L35H7CFrGyh0iyBFlPHCf1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b7Sbt4/btsGBsoxDmO/L35H7CFrGyh0iyBFlPHCf1/img.png&quot; data-alt=&quot;https://cips.cardano.org/cip/CIP-0001#editors&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b7Sbt4/btsGBsoxDmO/L35H7CFrGyh0iyBFlPHCf1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb7Sbt4%2FbtsGBsoxDmO%2FL35H7CFrGyh0iyBFlPHCf1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1247&quot; height=&quot;668&quot; data-origin-width=&quot;1247&quot; data-origin-height=&quot;668&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://cips.cardano.org/cip/CIP-0001#editors&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CIP는 두 가지 과제를 해결하는 것을 목표로 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 다양한 참여자가 상호운용성을 높이기 위한 도구나 인터페이스의 공통된 접근&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 프로토콜 혹은 생태계의 관행에 대한 변경에 대한 논의와 제안&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 두 과제를 해결하는데 있어서, CIP 프로세스가 어떤 변경사항에 대한 구현과 배포 프로세스까지 관리하는 것은 아니다. 결국 커뮤니티 중심의 거버넌스 의사결정과 합의를 위한 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;838&quot; data-origin-height=&quot;468&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfkwRb/btsGCrWxVXh/DnNReaD2lFmhftrmCoitXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfkwRb/btsGCrWxVXh/DnNReaD2lFmhftrmCoitXK/img.png&quot; data-alt=&quot;Cardano Academy&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfkwRb/btsGCrWxVXh/DnNReaD2lFmhftrmCoitXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfkwRb%2FbtsGCrWxVXh%2FDnNReaD2lFmhftrmCoitXK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;838&quot; height=&quot;468&quot; data-origin-width=&quot;838&quot; data-origin-height=&quot;468&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Cardano Academy&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CIP의 프로세스는 위와같이 진행된다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Authors는 CIP 제안서를 기준에 맞춰 작성하여 제안한다.&lt;/li&gt;
&lt;li&gt;제안서는 Editor에 의해서 검토된다.&lt;/li&gt;
&lt;li&gt;내용에 대한 피드백이 진행되거나 기준에 충족하면 받아들여지며 아니면 Inactive 상태로 결정된다.&lt;/li&gt;
&lt;li&gt;Active 상태로 통과되면 Implementors에 의해서 제안서가 구현된다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Editor, Reviewer&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CIP Editor는 CIP 프로세스의 관리자 역할을 담당한다. 제안서의 동기와 정당성, 근거와 포맷을 통해 검토하며, 번호를 할당하고 문구, 문법을 조정하는 요청을 한다. 또한, 제안서를 기준으로 커뮤니티와 위 그림에서 Reviewer는 제안에 대한 기술 피드백을 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Documnet Structure&lt;/h3&gt;
&lt;pre id=&quot;code_1713099417232&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;---
CIP: 1
Title: Cardano Improvement Proposals
Status: Active
Category: Meta
Authors:
    - Frederic Johnson &amp;lt;frederic.johnson@cardanofoundation.org&amp;gt;
    - Sebastien Guillemot &amp;lt;sebastien@dcspark.io&amp;gt;
    - Matthias Benkort &amp;lt;matthias.benkort@cardanofoundation.org&amp;gt;
    - Duncan Coutts &amp;lt;duncan.coutts@iohk.io&amp;gt;
Implementors: N/A
Discussions:
    - https://github.com/cardano-foundation/cips/pulls/1
Created: 2020-03-21
License: CC-BY-4.0
---&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;CIP: 제안 번호&lt;/li&gt;
&lt;li&gt;Title: 설명이 포함된 간결한 제목&lt;/li&gt;
&lt;li&gt;Status: 제안의 상태&lt;/li&gt;
&lt;li&gt;Category: 생태계 카테고리&lt;/li&gt;
&lt;li&gt;Authors: 작성자의 실명 및 이메일 주소&lt;/li&gt;
&lt;li&gt;Implementors: 해당 제안을 구현하기로한 implementors&lt;/li&gt;
&lt;li&gt;Discussions: 해당 제안에 관련된 기술 논의 링크 목록&lt;/li&gt;
&lt;li&gt;Created: 제안이 생성된 날짜&lt;/li&gt;
&lt;li&gt;Licence: 승인된 라이센스&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 구성 중에서 CIP를 읽기전에 알아두면 좋을 Status와 Category에 대해서 더 확인해보자.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Status&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1231&quot; data-origin-height=&quot;1003&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8twRZ/btsGBz152eh/e33yRlznG1vavI0prWBNs1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8twRZ/btsGBz152eh/e33yRlznG1vavI0prWBNs1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8twRZ/btsGBz152eh/e33yRlznG1vavI0prWBNs1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8twRZ%2FbtsGBz152eh%2Fe33yRlznG1vavI0prWBNs1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1231&quot; height=&quot;1003&quot; data-origin-width=&quot;1231&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;CIP는 3가지 상태를 가진다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Proposed: CIP의 필수적인 기준을 충족하는 CIP지만, 아직 Active는 아닌 단계다. Editor의 판단에 의해서 내용의 퀄리티가 통과되어야한다. 기술적인 관점에서 전문가의 검토와 우려사항 해결이 필요할 수 있다.&lt;/li&gt;
&lt;li&gt;Inactive: 더이상 사용되지 않거나, 대체되거나 혹은 폐기된 상태를 말한다.&lt;/li&gt;
&lt;li&gt;Active: 구현 및 출시를 통해서 혹은, 프로토콜이 메인넷에 반영되는 완전한 것으로 간주된다. 필요에 따라 새로운 제안에 의해서 챌린지가 진행될 수도 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Active는 2가지 하위섹션으로 나뉜다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Acceptance Criteria: 제안이 active가 될 수 있는 기준 목록을 정의한다. 기준은 확인가능한 메트릭이거나 결과물 혹은 Editor나 프로젝트 관리자에 의해서 검토되는 것이어야 한다.&lt;/li&gt;
&lt;li&gt;Implementation Plan: 제안이 받아들일 수 있는 기준을 만족하는 계획을 정의한다. 구현에는 하나 이상의 Implementator를 나타낼 수 있으며 게획에 서명하고 문서 서문에 언급되어야한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Category&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CIP는 몇가지의 범주로 분류된다. 추후에 추가되거나 변경될 수 있지만, 현재는 다음과 같이 나뉘어진다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Wallet: 지갑의 하드웨어와 노드 관련 표준화&lt;/li&gt;
&lt;li&gt;Token: 토큰(Fungible, Non-fungible) 및 일반적인 발행 정책에 대한 설명&lt;/li&gt;
&lt;li&gt;Metadata: 메타데이터에 대한 제안&lt;/li&gt;
&lt;li&gt;Tool: 생태계 도구의 광범위한 카테고리&lt;/li&gt;
&lt;li&gt;Plutus: CIP-35에 설명된 Plutus에 대한 변경과 추가&lt;/li&gt;
&lt;li&gt;Ledger: CIP-84에 설명된 카르다노 Ledger에 관련된 것&lt;/li&gt;
&lt;li&gt;Catalyst: Project Catalyst의 프로젝트에 영향을 미치는 제안&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;p data-ke-size=&quot;size16&quot;&gt;카르다노를 이해하는데 CIP를 참고하면 아주 도움이 많이 된다. 참고하면 좋을 만한 카테고리인 Token, Wallet, Metadata, Tool, Ledger 를 기준으로 하나씩 티스토리에 정리해보려고 한다.&lt;/p&gt;</description>
      <category>Cardano</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/407</guid>
      <comments>https://tigercoin.tistory.com/407#entry407comment</comments>
      <pubDate>Sun, 14 Apr 2024 22:44:00 +0900</pubDate>
    </item>
    <item>
      <title>Cardano Rewards Mechanisms(보상 원리)</title>
      <link>https://tigercoin.tistory.com/406</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;블록체인 네트워크를 안정적으로 유지하기 위해서 가장 중요한 요소 중 하나는 보상 메커니즘이라 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카르다노는 Proof of Stake 방식을 활용하기 때문에, 보상 매커니즘을 적절히 유지하기 위해 $ADA 의 인플레이션, Pledge, 최대 스테이킹 지분을 조절할 수 있는 포화도(k), Treasury 배분 정도 등 여러 파라미터가 사용된다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Untitled.png&quot; data-origin-width=&quot;1670&quot; data-origin-height=&quot;994&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgh2Jc/btsF6hUOLxK/Yf95eNON4T3Ury820bPcHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgh2Jc/btsF6hUOLxK/Yf95eNON4T3Ury820bPcHK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgh2Jc/btsF6hUOLxK/Yf95eNON4T3Ury820bPcHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbgh2Jc%2FbtsF6hUOLxK%2FYf95eNON4T3Ury820bPcHK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1670&quot; height=&quot;994&quot; data-filename=&quot;Untitled.png&quot; data-origin-width=&quot;1670&quot; data-origin-height=&quot;994&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스테이킹 풀이 블록을 생성해서 받은 보상은 위와같은 로직으로 이루어진다. 이 글에서 살펴볼 것은 아래와 같이 보상에 영향을 주는 파라미터로 결정되는 요소들이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ADA Reserve&lt;/li&gt;
&lt;li&gt;ADA Treasury&lt;/li&gt;
&lt;li&gt;Pldege Influence Factor&lt;/li&gt;
&lt;li&gt;Stake Pool Saturation&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;840&quot; data-origin-height=&quot;357&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsaBcz/btsF6F2sD1C/ajCYZibE8n0eASAK3YDCk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsaBcz/btsF6F2sD1C/ajCYZibE8n0eASAK3YDCk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsaBcz/btsF6F2sD1C/ajCYZibE8n0eASAK3YDCk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsaBcz%2FbtsF6F2sD1C%2FajCYZibE8n0eASAK3YDCk1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;840&quot; height=&quot;357&quot; data-origin-width=&quot;840&quot; data-origin-height=&quot;357&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스테이킹 풀에 분배되는 보상의 원천은 위와 같이 트랜잭션 수수료(Transaction fee)와 ADA 리저브로부터 제공된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션은 수수료는 말그대로, 유저들이 네트워크에서 트랜잭션 실행에 지불하는 수수료다. ADA 리저브는 새로운 ADA가 유통되는 예비금이다. 이는 카르다노의 통화 정책(Monetary Policy)을 통해서 결정된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;The Cardano Monetary Policy&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카르다노 내에서 ADA의 발행과, 배포 관리를 결정하는 프로토콜 규칙이다. ADA의 총 공급량과 리저브에서 새 ADA가 방출되는 비율과 Treasury와 수수료 징수 및 스테이킹 보상 메커니즘과 같은 측면이 포함된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1597&quot; data-origin-height=&quot;971&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8hOzj/btsF4X3ScYd/e6ThCQK6t3LP3MtV4Z0XYk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8hOzj/btsF4X3ScYd/e6ThCQK6t3LP3MtV4Z0XYk/img.png&quot; data-alt=&quot;Initail Supply of ADA&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8hOzj/btsF4X3ScYd/e6ThCQK6t3LP3MtV4Z0XYk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8hOzj%2FbtsF4X3ScYd%2Fe6ThCQK6t3LP3MtV4Z0XYk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1597&quot; height=&quot;971&quot; data-origin-width=&quot;1597&quot; data-origin-height=&quot;971&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Initail Supply of ADA&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카르다노의 총 발행량은 450억 개로 그 이상 발행되지 않는다. 리저브에 있는 ADA가 모두 유통되면 새로운 ADA가 생성될 수 없다. 이는 비트코인과 마찬가지로, 보상을 위해 유통량은 늘어나지만 수량에 제한이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ADA는 2015년 10월부터 2017년 1월까지 4단계에 걸쳐 아시아에서 배포되었고, 퍼블릭 세일 기간 동안 57.5%가 판매되었다. Cardano Foundation 1.4%, IOHK 5.5%, Emurgo 4.6%가 분배되었고, 나머지 30.9%는 리저브에 투입되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리저브에 투입된 수량은 약 140억 개의 ADA이다. 메인넷 출시후 보상이 시작되었고, 시대가 전환되는 사이에 점차적으로 고갈되어 23년 11월에는 86억 6천만 개의 ADA가 남아있었다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;ADA Reserve x Transaction fee&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;인플레이션은 매개변수 p에 의해서 결정된다.&lt;/b&gt; &lt;b&gt;현재 0.3%로 설정되어 있으며, 매 에포크마다 리저브에서 0.3%가 virtual pot에 지급된다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1667&quot; data-origin-height=&quot;125&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqNjoB/btsF8bzx2K3/qajhzFwSpmJmIaGp9YlvA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqNjoB/btsF8bzx2K3/qajhzFwSpmJmIaGp9YlvA1/img.png&quot; data-alt=&quot;https://beta.explorer.cardano.org/en/protocol-parameters/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqNjoB/btsF8bzx2K3/qajhzFwSpmJmIaGp9YlvA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqNjoB%2FbtsF8bzx2K3%2FqajhzFwSpmJmIaGp9YlvA1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1667&quot; height=&quot;125&quot; data-origin-width=&quot;1667&quot; data-origin-height=&quot;125&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://beta.explorer.cardano.org/en/protocol-parameters/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;징수되는 트랜잭션 수수료는 매번 다를 수 있는데, 카르다노 네트워크의 사용자가 많을수록 당연히 더 많은 수수료가 징수된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;The Cardano Treasury&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;928&quot; data-origin-height=&quot;330&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nXV8X/btsF8mARsJb/TtpKIwpwwUfHQ8kmGpCJQk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nXV8X/btsF8mARsJb/TtpKIwpwwUfHQ8kmGpCJQk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nXV8X/btsF8mARsJb/TtpKIwpwwUfHQ8kmGpCJQk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnXV8X%2FbtsF8mARsJb%2FTtpKIwpwwUfHQ8kmGpCJQk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;928&quot; height=&quot;330&quot; data-origin-width=&quot;928&quot; data-origin-height=&quot;330&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ADA Treasury는 카르다노 네트워크의 개발 및 운영에 사용되는 펀드로, 트랜잭션 수수료의 일정비율로 자금을 조달한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1669&quot; data-origin-height=&quot;104&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wzYPR/btsF77Rr2d7/luhoZKPEUVXmYdSlkcBoFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wzYPR/btsF77Rr2d7/luhoZKPEUVXmYdSlkcBoFK/img.png&quot; data-alt=&quot;https://beta.explorer.cardano.org/en/protocol-parameters/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wzYPR/btsF77Rr2d7/luhoZKPEUVXmYdSlkcBoFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwzYPR%2FbtsF77Rr2d7%2FluhoZKPEUVXmYdSlkcBoFK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1669&quot; height=&quot;104&quot; data-origin-width=&quot;1669&quot; data-origin-height=&quot;104&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://beta.explorer.cardano.org/en/protocol-parameters/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;여기서 T 매개변수가 Treasury에 지급되는 Virtual Pot의 ADA 비율이 결정된다. 현재 T 매개변수는 20%로 설정되어 있어, 나머지 80%가 스테이킹 보상으로 분배된다.&amp;nbsp;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카르다노 개발자의 마케팅과 운영, 급여 등의 비용으로 사용되며, 구체적인 자금 사용은 Voltaire 시대 이후부터 거버넌스 시스템을 통해서 투표로 결정된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1723&quot; data-origin-height=&quot;679&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DhA7q/btsF64VhSGY/vuEuWuIFXvBVRoDKVTsObK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DhA7q/btsF64VhSGY/vuEuWuIFXvBVRoDKVTsObK/img.png&quot; data-alt=&quot;https://projectcatalyst.io/funds&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DhA7q/btsF64VhSGY/vuEuWuIFXvBVRoDKVTsObK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDhA7q%2FbtsF64VhSGY%2FvuEuWuIFXvBVRoDKVTsObK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1723&quot; height=&quot;679&quot; data-origin-width=&quot;1723&quot; data-origin-height=&quot;679&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://projectcatalyst.io/funds&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 카르다노의 주요 프로젝트를을 지원하는 Project Catalyst 프로그램은 이 카르다노 Treasury의 자금으로 지원된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Pledge Influence Factor&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pledge는 스테이크 풀에 담보되는 일정량의 ADA다. 이 담보인 Pledge는 필수는 아니지만, 담보된 ADA가 많을수록 지급되는 보상도 높아지기 때문에, 스테이커들 입장에선 풀을 선택하는 기준이 될 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1670&quot; data-origin-height=&quot;127&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDp6Yh/btsF5BGhrA8/pRnjwTixv0NRYmQZywFtdk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDp6Yh/btsF5BGhrA8/pRnjwTixv0NRYmQZywFtdk/img.png&quot; data-alt=&quot;https://beta.explorer.cardano.org/en/protocol-parameters/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDp6Yh/btsF5BGhrA8/pRnjwTixv0NRYmQZywFtdk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDp6Yh%2FbtsF5BGhrA8%2FpRnjwTixv0NRYmQZywFtdk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1670&quot; height=&quot;127&quot; data-origin-width=&quot;1670&quot; data-origin-height=&quot;127&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://beta.explorer.cardano.org/en/protocol-parameters/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;a0 이라는 매개변수가 이 Pledge의 영향력을 정의한다. 현재 30%로 정해져 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Stake Pool Saturation&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스테이크 풀에 네트워크의 이상보다 더 많은 지분이 위임되었을 경우를 대비해 사용되는 것으로, 파라미터 k는 이상적인 스테이킹 풀의 수를 정의한다. 현재 500으로 설정되어 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1687&quot; data-origin-height=&quot;149&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KeE1A/btsF5HsTcZv/gOg9DMU6bqs3rCKvHojmKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KeE1A/btsF5HsTcZv/gOg9DMU6bqs3rCKvHojmKk/img.png&quot; data-alt=&quot;https://beta.explorer.cardano.org/en/protocol-parameters/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KeE1A/btsF5HsTcZv/gOg9DMU6bqs3rCKvHojmKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKeE1A%2FbtsF5HsTcZv%2FgOg9DMU6bqs3rCKvHojmKk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1687&quot; height=&quot;149&quot; data-origin-width=&quot;1687&quot; data-origin-height=&quot;149&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://beta.explorer.cardano.org/en/protocol-parameters/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Saturation 메커니즘은 위임자가 다른 스테이크 풀에 위임하도록 장려하여 지분의 중앙 집중화를 방지하는 데에 목적이 있다. 결국 파라미터 k는 ADA 스테이커와 스테이킹 풀 운영자 모두에게 이익을 보호하고, 특정 단일 풀이 지나치게 커지는 것을 방지할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1865&quot; data-origin-height=&quot;740&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cTIWsD/btsF4XJAAK7/u2RYzstcjXDXMGnnZhSws1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cTIWsD/btsF4XJAAK7/u2RYzstcjXDXMGnnZhSws1/img.png&quot; data-alt=&quot;https://forum.cardano.org/t/k-150-500-1000-visualized/41984&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cTIWsD/btsF4XJAAK7/u2RYzstcjXDXMGnnZhSws1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcTIWsD%2FbtsF4XJAAK7%2Fu2RYzstcjXDXMGnnZhSws1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1865&quot; height=&quot;740&quot; data-origin-width=&quot;1865&quot; data-origin-height=&quot;740&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://forum.cardano.org/t/k-150-500-1000-visualized/41984&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;k가 500일 경우, 단일 풀은 최대 6,400만 ADA를 스테이킹할 수 있다. 그 이상이 위임될 경우 ROS는 위 파란색 곡선과 같이 빠르게 감소하여, 풀의 보상이 줄어든다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Protocol Parameters&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2256&quot; data-origin-height=&quot;1162&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cpGPKC/btsF8xCl3PQ/mBG5K8uf5d9B6wXDGJtvG0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cpGPKC/btsF8xCl3PQ/mBG5K8uf5d9B6wXDGJtvG0/img.png&quot; data-alt=&quot;https://beta.explorer.cardano.org/en/protocol-parameters/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cpGPKC/btsF8xCl3PQ/mBG5K8uf5d9B6wXDGJtvG0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcpGPKC%2FbtsF8xCl3PQ%2FmBG5K8uf5d9B6wXDGJtvG0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2256&quot; height=&quot;1162&quot; data-origin-width=&quot;2256&quot; data-origin-height=&quot;1162&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://beta.explorer.cardano.org/en/protocol-parameters/&lt;/figcaption&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;위 파라미터들에 의해서 풀에 지급되는 보상량이 결정되고, 풀의 고정 수수료(epoch fee)와 가변 수수료(variable fee)에 따라서 수수료가 징수되고 최종적으로 스테이커에게 지불되는 스테이킹 보상이 결정된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2092&quot; data-origin-height=&quot;673&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/q62So/btsF3UM6CQf/qTSTQk6sKh1nvXW7DbhYt0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/q62So/btsF3UM6CQf/qTSTQk6sKh1nvXW7DbhYt0/img.png&quot; data-alt=&quot;https://pooltool.io/pool/bf7908ea0ef61c441e4dca0e756f335c33459bb8f2779cb8f6caf8eb/epochs&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/q62So/btsF3UM6CQf/qTSTQk6sKh1nvXW7DbhYt0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fq62So%2FbtsF3UM6CQf%2FqTSTQk6sKh1nvXW7DbhYt0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2092&quot; height=&quot;673&quot; data-origin-width=&quot;2092&quot; data-origin-height=&quot;673&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://pooltool.io/pool/bf7908ea0ef61c441e4dca0e756f335c33459bb8f2779cb8f6caf8eb/epochs&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 pooltool에서 확인할 수 있듯이 해당 수수료의 고정량과 비율은 직접 explorer를 통해서 확인해야 한다. 결국, 프로토콜에서 결정하는 파라미터와, 스테이킹 풀 운영자의 수수료에 의해서 최종 보상이 결정된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 카르다노의 볼테르 시대 이후부터는 거버넌스에 의해 프로토콜 파라미터들이 결정되기 때문에, 이런 리워드 메커니즘도 사실상 탈중앙화되어 결정된다고 보면 된다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.moonpay.com/learn/cryptocurrency/what-is-cardano&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.moonpay.com/learn/cryptocurrency/what-is-cardano&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.cardano.org/explore-cardano/monetary-policy/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.cardano.org/explore-cardano/monetary-policy/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://cexplorer.io/article/understanding-cardano-monetary-policy&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://cexplorer.io/article/understanding-cardano-monetary-policy&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Cardano</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/406</guid>
      <comments>https://tigercoin.tistory.com/406#entry406comment</comments>
      <pubDate>Tue, 26 Mar 2024 22:49:23 +0900</pubDate>
    </item>
    <item>
      <title>Ouroboros Consensus Algorithms(우로보로스 합의 알고리즘)</title>
      <link>https://tigercoin.tistory.com/405</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;블록체인 네트워크의 핵심이자, 중요한 기술은 노드 간의 높은 보안과 효율을 보장하는 합의 알고리즘이라고 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카르다노는 Ouroboros 합의 알고리즘을 자체 개발했으며, 기술 수준이 아주 뛰어나다고 알려져 있으나 쉽게 기술된 자료가 없어서 정리해보려 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 합의 알고리즘의 시작인 비트코인의 PoW(Proof of Work) 합의 알고리즘에서부터 Ouroboros 까지 탄생한 과정과 개념에 대해서 간단히 정리해 보자.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Bitcoin Consensus Algorithm&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비트코인은 Public Permissionless Distributed Ledger로, 누구나 허가 없이 참여할 수 있는 네트워크다. 이 네트워크가 공유하는 두 가지 펀더멘탈 속성(Fundamental Property)는 Safety와 Liveness다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Safety: 지난 트랜잭션은 불변해야 하며, 시간이 지남에 따라 Certainty 정도는 높아진다.&lt;/li&gt;
&lt;li&gt;Liveness: 새로운 트랜잭션은 원장에 추가된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 비트코인이 Eventual Consensus를 이뤘다고 한다. 이는 시간이 지나면서 불변하며, 참일 확률이 높아지는 것을 말한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1030&quot; data-origin-height=&quot;590&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tdIGa/btsF3lPLWCT/d8KMscLzGnN1lCWnUAnRi0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tdIGa/btsF3lPLWCT/d8KMscLzGnN1lCWnUAnRi0/img.png&quot; data-alt=&quot;https://medium.com/coinmonks/cardano-ouroboros-consensus-protocol-a-novel-innovation-c460713708b6&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tdIGa/btsF3lPLWCT/d8KMscLzGnN1lCWnUAnRi0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtdIGa%2FbtsF3lPLWCT%2Fd8KMscLzGnN1lCWnUAnRi0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1030&quot; height=&quot;590&quot; data-origin-width=&quot;1030&quot; data-origin-height=&quot;590&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://medium.com/coinmonks/cardano-ouroboros-consensus-protocol-a-novel-innovation-c460713708b6&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 위해 비트코인은 본질적으로 해시파워(hashing power)를 증가시키는 경쟁에 의존한다. 이 경쟁은 지속가능하지 않기 때문에 많은 사람들은 대안을 찾고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 PoW는 참여자들이 확률적으로 그들의 해시파워를 통해 선택되는 선거 메커니즘이다. 카르다노의 Outoboros는 이 해시파워를 다른 리소스로 대체하는 것으로 시작된다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Proof of Work와 Randomness&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작업 증명에서의 무작위성(Randomness)은 적절한 hash 후보를 찾는 것은 암호학적 난이도에서 온다. hashing function은 주로 '추측'에 대해 저항력이 있도록 설계되었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 hashing power에 비례하여 공정한 선출 과정이 이뤄질 수 있게 반복해서 시도하는 것 외에는 다른 방법이 없다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Ouroboros Consensus Algorithm&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;881&quot; data-origin-height=&quot;507&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WZXR4/btsF16siJje/yAgw85WYpJwJWjxSil5HG0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WZXR4/btsF16siJje/yAgw85WYpJwJWjxSil5HG0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WZXR4/btsF16siJje/yAgw85WYpJwJWjxSil5HG0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWZXR4%2FbtsF16siJje%2FyAgw85WYpJwJWjxSil5HG0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;881&quot; height=&quot;507&quot; data-origin-width=&quot;881&quot; data-origin-height=&quot;507&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우로보로스 합의 알고리즘은 Proof of Stake 프로토콜로, Liveness와 Safety를 Byzantine 알고리즘을 기반으로 제공한다. 정직한 노드들이 대부분의 자원을 보유하고 있다는 가정하에 모든 Block Producer로 알려진 리더를 기반으로 작동한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Block Producer는 그들의 지분(스테이킹된 수량)에 비례하여 특정 슬롯에 선출된다. Stake delegation은 우로보로스의 핵심적인 지분으로 이는 확장성에도 필수적인 요소다.&lt;/p&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;586&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/boaKaW/btsF3mVxJmq/i3kvFDdCxwmOYF8m3oWaHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/boaKaW/btsF3mVxJmq/i3kvFDdCxwmOYF8m3oWaHK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/boaKaW/btsF3mVxJmq/i3kvFDdCxwmOYF8m3oWaHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FboaKaW%2FbtsF3mVxJmq%2Fi3kvFDdCxwmOYF8m3oWaHK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/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;586&quot; data-origin-width=&quot;1264&quot; data-origin-height=&quot;586&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 Ouroboros 프로토콜은 시간기반이며, 동기적으로 동작하며, Long chain rule을 선택하여 가장 긴 체인이 정당하다고 결정한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Provable security&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우로보로스는 명시적인 보안 보증(explicit security guarantees)을 제공하며, 수학적으로 증명가능한 프로토콜이다. 이는 프로토콜과 프로토콜이 이뤄야 할 목표를 설명하는 정의된 모델을 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모델 내에서 허용되는 임의의 적대적 행위를 고려해서 그 목표를 달성하는 것을 수학적 증명이 가능하며, 이전 버전에 이서 더욱 강화되고 개선된 새로운 메커니즘이 필요하기 때문에 여러 버전의 우로보로스 알고리즘이 존재한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Fundamental Properties&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;크게 세 가지의 속성을 통해서 Ouroboros 기반의 블록체인 네트워크는 safety와 liveness를 달성한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Common Prefix: 어떠한 정직한 참여자 간에 공통적인 Prefix가 존재한다. 어떤 숫자 k가 존재하여 만약 두 체인에서 k개의 블록을 제거하면 같은 부분의 체인이 남겨져있다는 속성&lt;/li&gt;
&lt;li&gt;Chain Quality: 어떤 숫자 k가 존재하여, 정직한 참여자가 소유한 체인에 대해서 최근 k개의 블록 중 적어도 하나는 정직하게 생성되었다는 속성&lt;/li&gt;
&lt;li&gt;Chain Growth: 어떤 숫자 k와 t가 있어 정직한 참여자가 소유한 체인에 대해서 t x k개의 블록이 k개의 슬롯에 걸쳐 존재한다는 속성&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Common Prefix는 블록체인의 일관성을 유지, Chain Quality는 블록 생성과정의 정당성, Chain Growth는 시스템이 지속적으로 블록을 추가하여 성장하는 것을 보장한다고 보면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 세 속성을 통해서 블록체인은 보안 측면에서 더 신뢰할 수 있는 구조를 유지한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Ouroboros Classic&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최초로 발표된 Ouroboros 프로토콜로, Proof of stake에 대한 증명가능한 보안을 제시하는 기본 프레임워크다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;복잡한 Multi-party Computation이 필요하며, 노드 간 Randomness의 좋은 소스를 제공해야 했으며 Proof of stake의 주요 과제는 좋은 Randomness의 source을 찾고, 편향 없는 리더 선출을 보장하는 것이다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ouroboros Classic은 비트코인의 Security Guarantees 수준과 동일한 Proof of Stake 프로토콜을 구성할 수 있음을 보여줬다. 그러나 Peer 간 완전한 동기화 통신과 같은 몇 가지 한계가 있는 가정에 의존하는 단점이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공격자가 자신의 이익을 위해서 조작할 수 없고, 더 지속가능한 편향 없는 randomness의 source를 찾는 것은 어렵기 때문이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Ouroboros Praos&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;paros는 더욱 강력한 Security Gurantees를 갖춘 Outoboros classic 버전으로, 적에게 더 많은 파워를 부여해도 시스템을 더욱 안전하게 보호할 수 있다. 시스템의 Provable Security를 유지하는 수학적인 증명을 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;노드는 전체 네트워크를 위험에 빠뜨리지 않아도 짧은 시간 동안 오프라인 상태에 놓일 수 있다. 이것은 VRF(Verifiable Random Functions)와 forward-secure KES(Key-Evoving signature Schemes)를 이용해서 이뤄진다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Ouroboros Genesis&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Praos와 Classic에서 새로운 노드는 네트워크에 참여할 때, 정직한 노드로부터 초기 데이터를 받아야 한다. 만약 악의적인 노드로부터 부트스트랩하게 될 경우, 공격자로부터 잘못된 데이터를 받아 전파하는 리스크가 발생할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 악의적인 노드는 체인을 위조해서 네트워크에 참여하는 새로운 Peer에게 체인 데이터를 전송할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;O&lt;b&gt;uroboros Genesis는 이 신뢰할 수 있는 인프라에 의존해야 할 필요성을 줄여 더 높은 탈중앙화를 실현한다.&lt;/b&gt; 가장 긴 체인을 선택하는 것뿐만 아니라 체인의 성장을 고려하여, 체인 선택 규칙(The chain selection rule)을 확장하여 작동한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Ouroboros Crypsinous&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대부분의 프라이버시 프로토콜(Privacy-preserving Protocol)은 트랜잭션 처리 단계에서 프라이버시 보호에 중점을 둔다. 그러나 Ouroborous Crypsinous는 프로토콜 레벨에서 프라이버시 보호를 처리한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Ouroboros Chronos&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 우로보로스 프로토콜은 노드가 동기화된 시간(Synchronizing clocks)을 공유한다는 것을 가정한다. Synchronizing clocks는 분산된 컴퓨팅 환경에서 오랜 기간 알려진 어려운 문제다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NTP(Network Time Protocol)과 같은 메커니즘은 이러한 문제를 해결하기 위해 오늘날까지 사용되며, NTP는 인터넷 프로토콜로 몇 가지 작동하는 인프라에 의존한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ouroboros Chronos는 외부 서비스에 의존하지 않고, 프로토콜 내에서 동기화된 시간을 계산한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Ouroboros Leios (Input Endorsers)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카르다노는 분산화된 시스템이며, 노드들은 그들의 스케줄에 일치한 블록을 공유하여 합의에 도달한다. 더 많은 지분을 보유할수록, 선택될 확률이 더 높아진다. 블록은 약 20초마다 생성되며 최대한 빨리 네트워크에 전파한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 노드는 대부분 시간 동안 일을 하고 있지 않다. &lt;b&gt;즉, 블록이 생성되는 20초라는 모든 시간에 블록을 검증하고 있지않다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 CPU 사용량은 오직 짧은 시간에 증가하는 것을 확인할 수 있다. 이처럼, 리소스는 현재 노드에서 활용도가 낮은 상태다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Leios는 내가 이전에 포스팅했던 Input Endorsers를 포함하는 프로토콜로, 유휴 리소스(Idle Resource)를 활용하여 체인의 구축을 더 병렬적으로 만드는 것에 대한 것이다. 여기서 블록은 3가지의 새로운 유형으로 나눈다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1230&quot; data-origin-height=&quot;672&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9xeT2/btsF1cGYSg6/bKM19gH2sFf3FGtI2eFNW0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9xeT2/btsF1cGYSg6/bKM19gH2sFf3FGtI2eFNW0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9xeT2/btsF1cGYSg6/bKM19gH2sFf3FGtI2eFNW0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9xeT2%2FbtsF1cGYSg6%2FbKM19gH2sFf3FGtI2eFNW0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1230&quot; height=&quot;672&quot; data-origin-width=&quot;1230&quot; data-origin-height=&quot;672&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;Ranking Blocks(진정한 합의)&lt;/li&gt;
&lt;li&gt;Endorsement Blocks(높은 신뢰 합의)&lt;/li&gt;
&lt;li&gt;Input Blocks(가장 빈번한)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 접근 방식은 카르다노가 UTxO 모델기반으로 트랜잭션이 실제 Concurrent를 가지고 있기에 효과적으로 적용할 수 있다. 대부분의 트랜잭션은 원장이 서로 충돌하지 않는 것들을 다루기 때문에 UTxO 모델의 두 트랜잭션의 Concurrent를 재기 쉽다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Leios는 근본적으로 Optimistic Consensus Algorithm이며, 더 연속적(Sequentail)이며 비관적인(Pessimistic) 모드로 전환하는 방법을 포함하여 Praos와 유사하게 작동한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Input Endorsers에 대한 지난 포스팅&lt;br /&gt;&lt;a href=&quot;https://tigercoin.tistory.com/402&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://tigercoin.tistory.com/402&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1711282959254&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;Cardano Input Endorsers 개념 이해하기&quot; data-og-description=&quot;최근에 Input Endorsers가 카르다노 커뮤니티에서 많이 언급되었다. 가장 기대하는 업데이트 중 하나로 손꼽히지만, 개념이 쉽지않다. 여러 자료를 참고해서 이해하기 쉽게 풀어보자. 기존 시스템 Ca&quot; data-og-host=&quot;tigercoin.tistory.com&quot; data-og-source-url=&quot;https://tigercoin.tistory.com/402&quot; data-og-url=&quot;https://tigercoin.tistory.com/402&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bE0nQS/hyVDvwxDUv/6hvWLqNGOXXMuJGTDpdm00/img.png?width=800&amp;amp;height=538&amp;amp;face=0_0_800_538,https://scrap.kakaocdn.net/dn/bl14RW/hyVDuK9bIt/CRISPFhg9h7c8U2t6nQ5Vk/img.png?width=800&amp;amp;height=538&amp;amp;face=0_0_800_538,https://scrap.kakaocdn.net/dn/iFp7C/hyVDIo6VKi/MxcaRTPsxopGHXzwCONIn1/img.jpg?width=878&amp;amp;height=880&amp;amp;face=0_0_878_880&quot;&gt;&lt;a href=&quot;https://tigercoin.tistory.com/402&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://tigercoin.tistory.com/402&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bE0nQS/hyVDvwxDUv/6hvWLqNGOXXMuJGTDpdm00/img.png?width=800&amp;amp;height=538&amp;amp;face=0_0_800_538,https://scrap.kakaocdn.net/dn/bl14RW/hyVDuK9bIt/CRISPFhg9h7c8U2t6nQ5Vk/img.png?width=800&amp;amp;height=538&amp;amp;face=0_0_800_538,https://scrap.kakaocdn.net/dn/iFp7C/hyVDIo6VKi/MxcaRTPsxopGHXzwCONIn1/img.jpg?width=878&amp;amp;height=880&amp;amp;face=0_0_878_880');&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;Cardano Input Endorsers 개념 이해하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;최근에 Input Endorsers가 카르다노 커뮤니티에서 많이 언급되었다. 가장 기대하는 업데이트 중 하나로 손꼽히지만, 개념이 쉽지않다. 여러 자료를 참고해서 이해하기 쉽게 풀어보자. 기존 시스템 Ca&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;tigercoin.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://academy.cardanofoundation.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://academy.cardanofoundation.org/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=PF1SW7e137A&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=PF1SW7e137A&lt;/a&gt;&lt;/p&gt;</description>
      <category>Cardano</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/405</guid>
      <comments>https://tigercoin.tistory.com/405#entry405comment</comments>
      <pubDate>Sun, 24 Mar 2024 17:10:19 +0900</pubDate>
    </item>
    <item>
      <title>Cardano Address 주소의 구성</title>
      <link>https://tigercoin.tistory.com/404</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Cardano는 고유한 address 구조를 가지고 있고, 이는 Payment address와 Stake address로 구분된다. 이 Stake address는 Rewards address라고도 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Payment address: 사용가능한 자산을 보관하는 주소&lt;/li&gt;
&lt;li&gt;Stake address: Payment address의 자금이 스테이킹에 사용되지는 지 여부와 방법을 정의&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;1644&quot; data-origin-height=&quot;482&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkZwhQ/btsFoe5Eqbs/dJpDHiMwJqojHVAERkyFz1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkZwhQ/btsFoe5Eqbs/dJpDHiMwJqojHVAERkyFz1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkZwhQ/btsFoe5Eqbs/dJpDHiMwJqojHVAERkyFz1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkZwhQ%2FbtsFoe5Eqbs%2FdJpDHiMwJqojHVAERkyFz1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1644&quot; height=&quot;482&quot; data-origin-width=&quot;1644&quot; data-origin-height=&quot;482&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ADA는 항상 Payment address에 속한다. 각 Payment address는 선택적으로 Stake address를 참조할 수 있다. Payment address에 있는 모든 ADA의 스테이킹 권한은 이 Stake address와 연관되어있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ADA를 스테이킹 풀에 위임되는 것은 두단계로 이뤄진다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;wallet의 사용자는 위임할 스테이킹 풀을 선택하여 transaction을 통해 블록체인에 전송한다.&lt;/li&gt;
&lt;li&gt;Stake address를 통해서 선택한 스테이킹 풀에 ADA를 위임하는 스테이킹 인증서가 백그라운드에 생성된다.&lt;/li&gt;
&lt;li&gt;위임 과정에서 시스템이 스테이킹 보상을 축적하는 reward account가 생성된다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 Payment address가 아닌 Stake address가 등록된다. 지금부터 생성되는 모든 Payment address도 이 한번의 등록으로 모두 스테이킹되며 자금 활용이 가능하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2222&quot; data-origin-height=&quot;578&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dWhaBH/btsFodliEtb/UlZSQOMsQj1KhGSuY7ShV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dWhaBH/btsFodliEtb/UlZSQOMsQj1KhGSuY7ShV0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dWhaBH/btsFodliEtb/UlZSQOMsQj1KhGSuY7ShV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdWhaBH%2FbtsFodliEtb%2FUlZSQOMsQj1KhGSuY7ShV0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2222&quot; height=&quot;578&quot; data-origin-width=&quot;2222&quot; data-origin-height=&quot;578&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카르다노에는 3가지 address가 있다.&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;Byron address:&lt;/b&gt; Byron 주소로 접두사가 없고 Base58로 인코딩되어있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Payment address:&lt;/b&gt; Shelly 주소로 addr이라는 접두사로 시작하며, bech32로 인코딩된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Stake address:&lt;/b&gt; stake라는 접두사로 시작하며 bech32로 인코딩된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Stake Address Reference&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1254&quot; data-origin-height=&quot;987&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dK4pm9/btsFocUi89F/87QIu9PVlLhT8J2dJr2ElK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dK4pm9/btsFocUi89F/87QIu9PVlLhT8J2dJr2ElK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dK4pm9/btsFocUi89F/87QIu9PVlLhT8J2dJr2ElK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdK4pm9%2FbtsFocUi89F%2F87QIu9PVlLhT8J2dJr2ElK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/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;987&quot; data-origin-width=&quot;1254&quot; data-origin-height=&quot;987&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Shelly payment 주소의 Stake address reference에는 value와, 검증키의 hash(staking key) 또는 validator script가 포함될 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1774&quot; data-origin-height=&quot;460&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c7fCVF/btsFkUtuUaJ/PZX4fHtim8vAu3EseKnSK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c7fCVF/btsFkUtuUaJ/PZX4fHtim8vAu3EseKnSK1/img.png&quot; data-alt=&quot;value&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c7fCVF/btsFkUtuUaJ/PZX4fHtim8vAu3EseKnSK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc7fCVF%2FbtsFkUtuUaJ%2FPZX4fHtim8vAu3EseKnSK1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1774&quot; height=&quot;460&quot; data-origin-width=&quot;1774&quot; data-origin-height=&quot;460&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;value&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Staking key는 모든 Payment address에 대한 스테이킹 권한을 제어하는데 사용하며, 일반적으로 Payment address를 소유한 주체가 가지고 있지만, 항상 그렇진않다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1899&quot; data-origin-height=&quot;579&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d4fTQf/btsFoF9RdlA/qIbsK6JBLywyky0DdTl3E1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d4fTQf/btsFoF9RdlA/qIbsK6JBLywyky0DdTl3E1/img.png&quot; data-alt=&quot;pointer&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d4fTQf/btsFoF9RdlA/qIbsK6JBLywyky0DdTl3E1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd4fTQf%2FbtsFoF9RdlA%2FqIbsK6JBLywyky0DdTl3E1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1899&quot; height=&quot;579&quot; data-origin-width=&quot;1899&quot; data-origin-height=&quot;579&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;pointer&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Payment address의 소유자가 아닌 다른 사람이 스테이킹 권한을 제어할 수 있다. 이 주소를 Hybrid address라고 한다.&lt;b&gt;여기서 reference에 포인터가 포함되어 포인터 주소가 될 수 있는데, 이 경우에는 스테이킹 키는 포인터를 통해서 간접적으로 참조된다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;reference는 Staking Certificate가 저장되는 위치를 가리키며, 스테이킹 키는 Staking Certificate에 저장된다. 여기서 포인터는 스테이킹 키보다 작은 크기를 차지한다.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;reference에는 null 값이 포함될 수 있는데, 이는 'enterprise address'라고 한다. 이렇게 되면 &lt;b&gt;Payment의 자금은 스테이킹 권한과 연결될 수 없어 ADA 스테이킹될 수 없다. 이는 ADA를 스테이킹 하지 않을 것을 분명히 해야하는 거래소같은 조직이 사용한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단히 요약하면,&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;value: payment address 소유자만 자신의 ADA 스테이킹 권한을 컨트롤하는 staking key&lt;/li&gt;
&lt;li&gt;pointer: payment address 소유자 외에 다른 이가 스테이킹 권한을 컨트롤할 수 있도록 Staking Certificate의 위치를 가리키게 해주는 staking key&lt;/li&gt;
&lt;li&gt;null: 스테이킹 권한이 없어 ADA 스테이킹이 불가&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 추가적으로, reward address라는 개념도 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Reward address(Stake address)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보상 주소는 주소의 퍼블릭 스테이킹 키의 해시값이며, 스테이킹 보상을 분배하는데 사용된다. Payment address는 UTxO 모델이지만, Reward address는 Account 모델을 사용하며, 보상이 지급되면 Account Balance가 늘어난다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 사용자가 트랜잭션을 통해서 reward를 인출하면 balance에서 새 UTxO가 생성된다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고 :&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://cexplorer.io/article/understanding-cardano-addresses&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://cexplorer.io/article/understanding-cardano-addresses&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Cardano</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/404</guid>
      <comments>https://tigercoin.tistory.com/404#entry404comment</comments>
      <pubDate>Fri, 1 Mar 2024 22:00:14 +0900</pubDate>
    </item>
    <item>
      <title>Cardano EUTxO와 트랜잭션 구성 및 실행 프로세스</title>
      <link>https://tigercoin.tistory.com/403</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;카르다노의 UTxO 회계모델은 스마트 컨트랙트와 다양한 자산을 지원한다. 지난 글에서 이런 UTxO의 특징을 정리했다면 이번 글에는 어떻게 사용되는지, 스크립트를 통해서 어떻게 실행되는 지 정리해보자.&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;UTxO&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UTxO 모델은 Account 모델과는 다르게, UTxO 형태로 원장에 기록되어, 주소의 잔액이 모든 UTxO 값의 합으로 계산된다. 그래서 Account 모델은 하나의 주소를 가지고 있지만, &lt;b&gt;UTxO 모델의 일반적인 유저의 계정에는 여러 주소를 가지고 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;UTxO는 한 번만 사용될 수 있으며, 트랜잭션에 대한 입력으로 사용된다. 새 UTxO는 트랜잭션의 출력으로 생성되며, 이 UTxO는 다시 새로운 트랜잭션의 입력으로 사용된다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력으로 사용된 하나의 UTxO는 여러 UTxO를 출력으로 생성될 수 도 있다. 그리고 생성된 UTxO들은 다른 수신자에게 전송될 수 도 있다. A라는 사람이 100 ADA를 가지고 있는데, B라는 사람에게 20 ADA를 전송하려고 할 때, 80 ADA의 UTxO는 B에게, 나머지 20 ADA 는 A에게 전송된다고 보면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;그래서 UTxO 모델에서 트랜잭션은 비상태성을 가지고 있다. 이전의 기록이나 전역 state에 전혀 영향을 받지 않는다. 거래가 유효하기 위해서는 입력과 출력, 수수료, 증인만 제공되면 된다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;'witness'은 자산의 소유자가 거래를 승인했음을 나타내는 데이터&lt;/b&gt;로, 서명(key credential의 증명) 이거 스크립트 실행(script credential 증명) 둘 중 하나다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Shelly Address의 UTxO Spending&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2256&quot; data-origin-height=&quot;618&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmdtsp/btsFoKh7R4t/zVk1KvXJ77D5jUVzOoQKy1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmdtsp/btsFoKh7R4t/zVk1KvXJ77D5jUVzOoQKy1/img.png&quot; data-alt=&quot;Shelly address에서 UTxO Spending&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmdtsp/btsFoKh7R4t/zVk1KvXJ77D5jUVzOoQKy1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbmdtsp%2FbtsFoKh7R4t%2FzVk1KvXJ77D5jUVzOoQKy1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2256&quot; height=&quot;618&quot; data-origin-width=&quot;2256&quot; data-origin-height=&quot;618&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Shelly address에서 UTxO Spending&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단일 Shelly address에는 여러 UTxO가 존재할 수 있으며, Shelly 주소는 Header와 Payload로 구성된다. Payload는 Payment Credential과 Stake address Reference가 포함되어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Payment Credential: 주소에 있는 자금을 소유한 사람을 식별하는 Shelly address의 요소로, Key Credential 이거나 Script Credential 중 하나다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UTxO는 특정 주소에서 사용되거나, 같은 주소가 새 UTxO를 수신할 수 있는지 확인해야한다. UTxO는 발신자 address로부터 수신자의 address로 이동한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1439&quot; data-origin-height=&quot;760&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZAh3A/btsFkXpwlH1/1bKo5Zuc0yd2hu5Z0KeX6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZAh3A/btsFkXpwlH1/1bKo5Zuc0yd2hu5Z0KeX6k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZAh3A/btsFkXpwlH1/1bKo5Zuc0yd2hu5Z0KeX6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZAh3A%2FbtsFkXpwlH1%2F1bKo5Zuc0yd2hu5Z0KeX6k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1439&quot; height=&quot;760&quot; data-origin-width=&quot;1439&quot; data-origin-height=&quot;760&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UTxO는 Identifier와 value로 구성된 구조로 이뤄져있다. 여기서 Identifier(식별자)는 Outpoint를 말한다,&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Outpoint: UTxO의 위치를 가리키는 Pointer 역할을 담당. 이전 트랜잭션 ID와 UTxO를 생성한 트랜잭션의 Output Index로 구성됨&lt;/li&gt;
&lt;li&gt;Fund: UTxO가 보유한 코인 혹은 토큰의 value&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새 UTxO는 트랜잭션을 통해서 생성된다. 즉, 트랜잭션은 입력 UTxO를 사용해서 새 UTxO를 생성한다. 거래에서 Destination address와 Fund를 가진 새로운 출력 UTxO가 생성된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션의 입력은 UTxO지만, 기술적으론 블록체인에서 UTxO를 식별하는 Outpoint다. Outpoint는 이전 트랜잭션 ID와 UTxO를 생성한 트랜잭션의 Output Index로 구성되는데, 이 Output Point를 제공하여 거래는 UtxO에서 자금을 청구하고 이를 새 거래에 대한 입력으로 사용할 수 있게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력 UTxO는 witness를 제공해야하는 주소(현재 소유자의 주소)를 나타낸다. 이는 Outpoint가 블록체인의 UTxO 위치를 가리키고 UTxO에 Destination address가 있기 때문이다. Destination address에는 주소의 자금을 보유한 사람을 식별하는 Key Credential 또는 Script Credential인 Payment Credential이 있다. 그래서 거래가 UTxO를 사용하기 위해선 Destination address의 Payment Credential의 유효한 Witness를 제공해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;UTxO를 사용하면 새 Destination Address와 연결되는 새 UTxO가 생성되고, UTxO를 입력으로 사용하는 트랜잭션은 Destination 주소와 새 UTxO의 값을 지정하는 하나 이상의 출력도 제공해야만 한다. 그리고 여기서 새 UTxO는 Destination address의 Payment Credential과 연결된다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 Credential 소유자만 향후 거래에서 이 UTxO를 사용할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2256&quot; data-origin-height=&quot;504&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BOHpb/btsFiuuCiGV/y7SWK48udz8yKgtt83NdQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BOHpb/btsFiuuCiGV/y7SWK48udz8yKgtt83NdQ1/img.png&quot; data-alt=&quot;1 Input UTxO, 2 Output Transaction&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BOHpb/btsFiuuCiGV/y7SWK48udz8yKgtt83NdQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBOHpb%2FbtsFiuuCiGV%2Fy7SWK48udz8yKgtt83NdQ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2256&quot; height=&quot;504&quot; data-origin-width=&quot;2256&quot; data-origin-height=&quot;504&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;1 Input UTxO, 2 Output Transaction&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 보이는 것과 같이 트랜잭션에는 하나의 Input UTxO와 두개의 Output UTxO가 있으며, Fee, Transaction ID 그리고 Witness가 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;fee: 사용자가 트랜잭션 처리를 위해 네트워크에 지불하는 ADA 수수료&lt;/li&gt;
&lt;li&gt;witness: 트랜잭션이 자금 소유자에 의해 승인되었음을 증명하는 일련의 witness가 포함됨. 트랜잭션은 각 Input address(발행 정책 ID, 출금 보상 계정, 인증서 작성자의 Credential)에 대한 witness를 제공해야함. 위 트랜잭션에서는 Input UTxO가 하나만 있기에 유효성 검사에서 witness가 하나만 필요함.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 투입물의 총 value는 output value와 fee의 총 가치와 같거나 커야만 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2256&quot; data-origin-height=&quot;1071&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OL7hD/btsFmlcjm4i/qpnlwku93R8ypeKKQWkvqK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OL7hD/btsFmlcjm4i/qpnlwku93R8ypeKKQWkvqK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OL7hD/btsFmlcjm4i/qpnlwku93R8ypeKKQWkvqK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOL7hD%2FbtsFmlcjm4i%2Fqpnlwku93R8ypeKKQWkvqK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2256&quot; height=&quot;1071&quot; data-origin-width=&quot;2256&quot; data-origin-height=&quot;1071&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 이미지를 통해서 Alice가 800 ADA를 Bob에게 보내는 프로세스를 설명해본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[Alice는 1000 ADA의 UTxO를 사용하며, Alice는 Bob의 Public key를 기반으로 Key Credential이 있는 Bob의 address로 800 ADA를 전송한다]&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Alice의 주소를 대상으로 거래 수수료 1 ADA를 제외한 199 ADA를 보내는 첫번쨰 UTxO를 생성한다.&lt;/li&gt;
&lt;li&gt;Bob의 주소를 대상으로 하여 800 ADA를 보내는 두번째 UTxO를 생성한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 트랜잭션이 네트워크에서 확정되면 Bob은 Private key를 사용하여 자신의 주소에서 800 ADA를 거래할 수 있게 된다. 물론 Alice도 동일하다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://cexplorer.io/article/understanding-utxo-spending&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://cexplorer.io/article/understanding-utxo-spending&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Cardano</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/403</guid>
      <comments>https://tigercoin.tistory.com/403#entry403comment</comments>
      <pubDate>Tue, 27 Feb 2024 23:42:12 +0900</pubDate>
    </item>
    <item>
      <title>Cardano Input Endorsers 개념 이해하기</title>
      <link>https://tigercoin.tistory.com/402</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;최근에 Input Endorsers가 카르다노 커뮤니티에서 많이 언급되었다. 가장 기대하는 업데이트 중 하나로 손꼽히지만, 개념이 쉽지않다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 자료를 참고해서 이해하기 쉽게 풀어보자.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기존 시스템&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Cardano는 여러 노드의 PoS 합의 알고리즘을 기반으로 네트워크가 구성된다. 평균 20초마다 블록이 생성되는데, 블록 생성 노드는 무작위로 추첨되어 블록을 생성한다. 여기서 블록 검증은 50~100 밀리초 정도 소요된다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그러나 이 알고리즘의 계산은 네트워크의 대역폭을 낭비한다고 여겨진다. 노드가 블록 생성하고 검증하는 이 짧은 시간을 제외하곤 대부분 노드 CPU가 유휴 상태가 되기 때문이다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;네트워크 리소스는 병렬적으로 사용될 수 있으나, 알고리즘은 순차적이다. 병렬 시스템에 순차적인 알고리즘은 자원을 비효율적으로 사용할 수 밖에 없다. 여기서 순차적인 것은 블록 생산에만 적용된다. 블록 검증이 동시에 이뤄질 순 없다. 모두가 통일된 전역 상태를 이루기 위해선 일정 데이터가 동기화가 되는 통신이 필수적이다. 그렇다고 확장성을 높이기 위해서 블록 생성 빈도를 줄이거나, 블록 크기를 높이는 것은 확장성을 높이는 좋은 해결책이 아니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;간단히 말해서 기존 시스템에는&amp;nbsp;자원의 비효율적인 사용과 한정된 트랜잭션 처리량, 그리고 순차적 데이터 처리로 인한 문제가 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;다행히도 카르다노는 UTxO 모델을 사용하기 때문에, 충돌하는 트랜잭션을 구별하는 것은 간단하다. 그래서 검증 결과에 관계없이, 다른 순서 혹은 병렬로 검증될 수 있기 때문에 동시성과 병렬화로 알고리즘을 만드는 것이 비교적 쉽다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;여기서 Input Endorsers가 병렬적으로 데이터 검증을 가능하게 해주는 알고리즘이라고 볼 수 있다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Input Endorsers&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Input Endorsers는 블록 생성 사이에 존재하는 유휴 시간에 3가지 유형의 블록을 활용하여 트랜잭션 처리에 병렬성과 동시성을 모두 달성할 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;병렬성: 여러 작업이 동시에 실행&lt;/li&gt;
&lt;li&gt;동시성: 여러 작업이 겹치는 기간에 진행&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 트랜잭션이 서로 다른 노드에 의해서 동시에 검증되고, 보증될 수 있도록 하여 병렬성을 구현한다. 이어서 각 슬롯에서 여러 블록이 생성되고 전파되도록 하여 동시성도 구현하여 네트워크의 처리량과 퍼포먼스를 높인다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Input Endorsers의 세 가지 블록&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IE라고 부르자. IE는 입력 블록(Input Block), 보증 블록(&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;Endorsement Blocks&lt;/span&gt;) 그리고 순위 블록(Ranking Block)이라는 세 유형의 블록을 사용한다. 블록 생성에 있어 카르다노는 무작위 프로세스를 사용하기 때문에, 일부 블록 유형이 하나의 슬롯에서 병렬적으로 생성될 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 블록 유형엔 서로 다른 주조 빈도가 설정된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;입력 블록: 0.2~2초&lt;/li&gt;
&lt;li&gt;보증 블록: 5~10초&lt;/li&gt;
&lt;li&gt;순위 블록: 15~30초&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/z5wOQ/btsEuCNM2Ds/deIdT40XHV3BYSz9gt8MXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/z5wOQ/btsEuCNM2Ds/deIdT40XHV3BYSz9gt8MXK/img.png&quot; data-origin-width=&quot;1592&quot; data-origin-height=&quot;427&quot; data-is-animation=&quot;false&quot; style=&quot;width: 58.8515%; margin-right: 10px;&quot; data-widthpercent=&quot;59.54&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/z5wOQ/btsEuCNM2Ds/deIdT40XHV3BYSz9gt8MXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fz5wOQ%2FbtsEuCNM2Ds%2FdeIdT40XHV3BYSz9gt8MXK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1592&quot; height=&quot;427&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAiEPh/btsEtncfqMj/0I2NTnTT3mjSSkgIY79100/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAiEPh/btsEtncfqMj/0I2NTnTT3mjSSkgIY79100/img.png&quot; data-origin-width=&quot;955&quot; data-origin-height=&quot;377&quot; data-is-animation=&quot;false&quot; style=&quot;width: 39.9857%;&quot; data-widthpercent=&quot;40.46&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAiEPh/btsEtncfqMj/0I2NTnTT3mjSSkgIY79100/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAiEPh%2FbtsEtncfqMj%2F0I2NTnTT3mjSSkgIY79100%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;955&quot; height=&quot;377&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정확한 시간은 결정되지 않았으나, 필요에 따라 조정될 것이다. 위에서 언급했던 것처럼, 유휴 상태에 이뤄지는 프로세스는 다음과 같다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;IE를 사용하면 새 트랜잭션이 보류중인 모든 트랜잭션이 이동하는 mempool에 들어간다.&lt;/li&gt;
&lt;li&gt;노드는 여러 트랜잭션을 그룹화하고 초당 여러 Input Block을 생성한다.&lt;/li&gt;
&lt;li&gt;다른 노드는 Input Block을 병렬로 검증하고 Endorsement Block을 생성한다. (이 과정은 20초의 빈 시간동안 병렬적으로 이뤄짐)&lt;/li&gt;
&lt;li&gt;다른 노드는 Endorsement Block을 검증하고 보증 리포트를 생성한다.&lt;/li&gt;
&lt;li&gt;하나의 Endorsement Block 에 대한 리포트가 생성되면 노드는 이를 통해 현재 순차적 모델이 작동하는 방식과 유사한 최종 Ranking Block을 생성하여 체인에 추가한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 각 블록의 역할은 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;956&quot; data-origin-height=&quot;643&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BtEF8/btsEwGu5FeW/1U8Yf6stOXkS5J0NRh2nY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BtEF8/btsEwGu5FeW/1U8Yf6stOXkS5J0NRh2nY1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BtEF8/btsEwGu5FeW/1U8Yf6stOXkS5J0NRh2nY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBtEF8%2FbtsEwGu5FeW%2F1U8Yf6stOXkS5J0NRh2nY1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;956&quot; height=&quot;643&quot; data-origin-width=&quot;956&quot; data-origin-height=&quot;643&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Input Block&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;트랜잭션의 신속한 처리: Input Block은 네트워크에 발생하는 트랜잭션을 빠르게 포착하고 블록에 포함시켜 처리 이는 트랜잭션을 빠르게 네트워크에 전파하고 검증하는 데 중점&lt;/li&gt;
&lt;li&gt;멤풀(mempool) 비우기: 노드는 자신의 멤풀에 있는 트랜잭션을 Input Block에 포함시켜 멤풀을 효율적으로 관리하고, 네트워크의 대기 시간을 줄임&lt;/li&gt;
&lt;li&gt;트랜잭션의 병렬 처리 지원: 다수의 Input Block이 동시에 생성되고 처리될 수 있어, 네트워크는 더 많은 트랜잭션을 동시에 처리할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Endorsement&amp;nbsp;Block&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;트랜잭션의 검증 및 승인: Endorsement Block은 Input Block에 포함된 트랜잭션들이 유효하고 네트워크에 의해 승인되었음을 나타냄. 이 과정을 통해 트랜잭션의 정확성을 보증&lt;/li&gt;
&lt;li&gt;네트워크 합의 가속화: Endorsement Block은 여러 Input Block을 참조할 수 있으며, 이를 통해 트랜잭션에 대한 네트워크의 합의를 더 빠르게 이룰 수 있음.&lt;/li&gt;
&lt;li&gt;블록간 연결 구성: 여러 Endorsement Block이 서로를 참조하여 트리와 같은 구조를 형성할 수 있으며, 이는 네트워크의 트랜잭션 처리 및 검증 과정을 더욱 효율적으로 만들게 해줌&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Ranking&amp;nbsp;Block&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;네트워크 합의 및 최종성 확보: Ranking Block은 네트워크 합의의 기반을 형성하며, 트랜잭션의 최종성을 확보함. 이는 블록체인의 전통적인 선형 구조를 유지하며 네트워크 전체의 합의 상태를 반영&lt;/li&gt;
&lt;li&gt;Endorsement Block 참조: Ranking Block은 하나 이상의 Endorsement Block을 참조하며, 이를 통해 트랜잭션이 유효하고 네트워크에 의해 승인되었음을 최종적으로 확정&lt;/li&gt;
&lt;li&gt;블록체인의 선형성 유지: Ranking Block은 이전 Ranking Block을 참조함으로써 블록체인의 연속성과 선형성을 보장함. 이 과정은 더블 스펜딩(double spending) 공격을 방지하고 전체 블록체인의 정확성을 유지하는 데 필수적임&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;확장성 향상을 위해서 이더리움 네트워크는 Sharding을 솔루션으로 제시했으나, 카르다노는 UTxO를 활용한 Input Endorsers를 구현했다. 샤딩의 경우엔 복사본을 여러개 생성했을 때 샤드 간 동기화와 통신의 오버헤드 문제가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 IE는 UTxO 모델을 기반으로, 트랜잭션 선택과 블록 생성을 분리할 수 있어, 병렬 처리와 동시성 구현이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 구조적인 문제에 놓인 이더리움에선 구현할 수 없는 솔루션이기 때문에 더욱 관심이 간다. 앞으로 확장성 향상에 얼마나 영향을 끼칠지 지켜봐야겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://cexplorer.io/article/understanding-input-endorsers&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://cexplorer.io/article/understanding-input-endorsers&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.linkedin.com/pulse/input-endorsers-simple-possible-lucas-macchiavelli-cujff/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.linkedin.com/pulse/input-endorsers-simple-possible-lucas-macchiavelli-cujff/&lt;/a&gt;&lt;/p&gt;</description>
      <category>Cardano</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/402</guid>
      <comments>https://tigercoin.tistory.com/402#entry402comment</comments>
      <pubDate>Wed, 7 Feb 2024 00:04:37 +0900</pubDate>
    </item>
    <item>
      <title>Cardano DEX에서 사용하는 Batcher</title>
      <link>https://tigercoin.tistory.com/401</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Batcher는 기존 이더리움 L2에서 Tx의 묶음인 batch를 L1에 기록하는 인스턴스를 의미하지만, 카르다노에서는 다르게 사용된다. 최근 Cardano의 디파이 생태계가 꾸준히 성장하는 만큼, UTXO 모델에 의해 사용되는 Batcher라는 개념을 스터디겸 정리해보려 한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Batcher&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배처는 카르다노의 몇몇 DEX에서 유저의 주문을 수집하고 스왑하기 위해서 사용하는 개념으로, Cardano 네트워크에서 노드를 실행하여 DEX의 스크립트를 호출하는 Tx를 생성하고 submit하는 개체라고 보면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단히 말해서, 블록체인에서 처리해야하는 트랜잭션 수를 줄이게 되어 DEX의 확장성, 효율성을 높이는 역할을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 역할을 위해서 다음과 같은 작업이 오프체인에서 진행되는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) 유저의 주문을 수집&lt;br /&gt;2) 자금의 락업과 관련된 거래 생성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 모든 유저의 주문을 일치시키고, 오프체인에서 다시 발생하는 거래를 생성해 스왑을 수행하게 된다. 여기서 Batcher는 우선순위와 가격에 따라서 유저 Tx를 정렬하기 때문에 충돌과 실패를 방지한다. 이 대가로 유저는 Tx 네트워크 비용 + Batcher의 스왑 비용을 지불하여 Batcher는 생성한 거래에 보상을 받게된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1805&quot; data-origin-height=&quot;997&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nnK5c/btsEqU1jlcC/IwK0CQxqBWqdW7MUfJ4M10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nnK5c/btsEqU1jlcC/IwK0CQxqBWqdW7MUfJ4M10/img.png&quot; data-alt=&quot;https://cexplorer.io/article/understanding-cardano-batchers&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nnK5c/btsEqU1jlcC/IwK0CQxqBWqdW7MUfJ4M10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnnK5c%2FbtsEqU1jlcC%2FIwK0CQxqBWqdW7MUfJ4M10%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1805&quot; height=&quot;997&quot; data-origin-width=&quot;1805&quot; data-origin-height=&quot;997&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://cexplorer.io/article/understanding-cardano-batchers&lt;/figcaption&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;1) Bob은 카르다노의 A라는 네이티브 토큰을 ADA로 스왑하려고 하고, Alice는 ADA로 A 토큰을 스왑하려고 한다.&lt;br /&gt;2) Alice와 Bob은 그들이 신뢰하는 Batcher를 찾아 스왑을 진행하려고 한다. (이는 DEX에 의해서 자동으로 수행되거나 선택가능)&lt;br /&gt;3) Batcher가 선택되면 Alice와 Bob이 거래에 사용할 자산이 락업된다. (스왑은 Batcher가 해당 자산을 컨트롤할 수 있는 경우에만 가능)&lt;br /&gt;4) Bob은 Batcher가 제어하는 스크립트 주소로 A 토큰을 전송한다.&lt;br /&gt;5) Batchcer는 락업 스크립트를 포함, Tx 생성 역할을 담당하며, 유저는 개인키로 거래에 서명한다. (Batcher는 유저의 개인키 접근이 안되며, 스왑 조건 불충분시 해당 자산 활용 불가능)&lt;br /&gt;6) 유저는 개인키 서명 전에 Batcher에서 제공하는 Tx를 확인한다.&lt;br /&gt;7) Alice도 Bob과 동일하게 ADA를 Batcher가 제어하는 스크립트 주소에 락업된다.&lt;br /&gt;8) Batcher는 두 거래를 단일 atomic 거래로 Cardano 네트워크에 제출한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 과정들을 통해서 Batcher를 활용하게 되면, 아래와 같은 이점이 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;노드에서 검증하고 저장할 Tx가 줄어들며 DEX의 처리량을 높일 수 있다.&lt;/li&gt;
&lt;li&gt;유저 입장에서는 일괄적으로 거래하기 때문에 수수료가 낮아지며, 더 빠르고 안정적이기 때문에 사용자 경험이 향상된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반대로, 단점도 존재한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Batcher가 악의적인 의도가 있다면 Tx를 조작, 검열할 수 있어 DEX의 탈중앙화와 보안을 감소시킬 수 있다.&lt;/li&gt;
&lt;li&gt;유저는 Batcher를 신뢰해야하므로, 리스크가 증가한다.&lt;/li&gt;
&lt;li&gt;유저가 주문 실행을 위해 Batcher 노드의 가용성과 성능에 의존해야한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Batcher는 대체로 SPO가 담당하여, 신뢰성을 보장받는 상황이다. 만약 SPO가 악의적인 행위를 했을 경우에 스테이커에게 신뢰를 잃기 때문에 현재까진 SPO가 스테이킹 풀 운영의 신뢰도를 이용해서 이 역할을 대신하는 것으로 보인다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;EUTxO와 Batcher&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이더리움에는 없는 Batcher라는 독특한 노드가 존재하는 것은 역시, UTXO 모델이기 때문이다. UTXO 기반이기 때문에 Tx의 실행이 독립적이라 로컬에서 실행이 가능하다. 이 점 덕분에 개별 Batcher가 DEX의 Tx를 처리할 수 있으며, 카르다노 네트워크에서 병렬처리가 가능한 이유다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개별 네트워크(L2)로 분기되는 방식으로 확장성을 높이는 이더리움에 비해서, 자산의 파편화를 막고 보안도 높이며, L1의 병렬처리가 카르다노에선 가능하다. 특히, 카르다노 생태계에선 SPO와 같은 노드들의 역할이 생각보다 다양한 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/lenfiLabs/batcher_example&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/lenfiLabs/batcher_example&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1707135607623&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 - lenfiLabs/batcher_example: These are batcher off-chain code that you can refer when building your own private batcher&quot; data-og-description=&quot;These are batcher off-chain code that you can refer when building your own private batcher - GitHub - lenfiLabs/batcher_example: These are batcher off-chain code that you can refer when building y...&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/lenfiLabs/batcher_example&quot; data-og-url=&quot;https://github.com/lenfiLabs/batcher_example&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ZH6H3/hyVgcRllcQ/FvnKK3Ex1qNqmpWgKeTK11/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/lenfiLabs/batcher_example&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/lenfiLabs/batcher_example&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ZH6H3/hyVgcRllcQ/FvnKK3Ex1qNqmpWgKeTK11/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 - lenfiLabs/batcher_example: These are batcher off-chain code that you can refer when building your own private batcher&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;These are batcher off-chain code that you can refer when building your own private batcher - GitHub - lenfiLabs/batcher_example: These are batcher off-chain code that you can refer when building y...&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;카르다노 생태계에서 주요 디파이 프로젝트 중 하나인 Lenfi에서도 Batcher를 활용하고 있다. 타입스크립트로 구현되었기 때문에 한번 살펴보면 좋을 듯..&lt;/p&gt;</description>
      <category>Cardano</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/401</guid>
      <comments>https://tigercoin.tistory.com/401#entry401comment</comments>
      <pubDate>Mon, 5 Feb 2024 21:19:12 +0900</pubDate>
    </item>
    <item>
      <title>Cardano Native Token(네이티브 토큰)과 ERC-20 비교</title>
      <link>https://tigercoin.tistory.com/399</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이더리움의 대표적인 Fungible Token인 ERC-20이 사용되듯이, 카르다노에서도 비슷한 역할을 하는 네이티브 토큰이라는 개념이 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카르다노에서 $ADA 는 네트워크 수수료로 사용되는 카르다노의 Principle Token다. 먼저, Native Token과는 몇가지 차이가 있다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 131px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;ADA&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;Native Token&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;트랜잭션 전송이 되는가&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px; text-align: center;&quot;&gt;YES&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px; text-align: center;&quot;&gt;YES&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;UTXO 출력에 저장되는가&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px; text-align: center;&quot;&gt;YES&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px; text-align: center;&quot;&gt;YES&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;스크립트 출력으로 잠금이 가능한가&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px; text-align: center;&quot;&gt;YES&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px; text-align: center;&quot;&gt;YES&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;거래소 주소로 전송되는가&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px; text-align: center;&quot;&gt;YES&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px; text-align: center;&quot;&gt;YES&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;mint와 burn이 되는가&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;NO&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;YES&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;네트워크 수수료로 지불하거나 보상으로 받는 것이 가능한가&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;YES&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;NO&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;위 표에서 보듯이, Natvie Token은 ADA처럼 트랜잭션을 통해 전송이 가능하며, 컨트랙트를 지원한다. 특히, ERC-20처럼, mint, burn이 가능하지만, 네트워크 수수료로 사용되는 것은 불가능하다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Cardano Native Token&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1843&quot; data-origin-height=&quot;938&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bq0uDQ/btsDKbWDHMP/9bSxZdRuQKyFDWLQGFehp0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bq0uDQ/btsDKbWDHMP/9bSxZdRuQKyFDWLQGFehp0/img.png&quot; data-alt=&quot;카르다노의 밈토큰인 SNEK&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bq0uDQ/btsDKbWDHMP/9bSxZdRuQKyFDWLQGFehp0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbq0uDQ%2FbtsDKbWDHMP%2F9bSxZdRuQKyFDWLQGFehp0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1843&quot; height=&quot;938&quot; data-origin-width=&quot;1843&quot; data-origin-height=&quot;938&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;카르다노의 밈토큰인 SNEK&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;토큰은 짧은 단어로 asset token이라고 불리며, 온체인 상의 어느 자산을 의미한다. 이 asset은 unique identifier인 ID로 표시되며, 발행되는 Policy ID와 asset name에 의해서 fingerprint가 생성된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Policy ID: 어떤 상황에서 새 토큰을 mint 하거나 기존 토큰을 burn 하는지를 정의하는 일련의 규칙으로 통화 정책을 결정함. 토큰 발행자는 정책이 생성된 후에 정책을 변경하거나, 토큰을 새 정책과 연결할 수 없게됨&lt;/li&gt;
&lt;li&gt;Asset name: 동일한 발행 Policy 내에서 식별하기 위한 불변의 속성값임.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Policy ID와 Asset name이 동일해야만 서로 대체가 가능하다. 동일한 이름을 가진 두개의 자산이 존재하더라도, 서로 다른 Policy ID를 가지고 있다면 대체할 수 없다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 동일한 Policy ID 하에서 서로 다른 Asset name이 존재하는 것은 카르다노에선 NFT로 활용된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Cardano Native Token vs ERC-20&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이더리움의 ERC-20은 가장 많이 사용되는 토큰으로 전송과 교환, 보상과 거버넌스 투표 등 다양한 유틸리티를 목적으로 사용된다. 카르다노의 Native Token은 추적과 회계가 모두 ledger에서 지원한다.(ERC-20은 스마트 컨트랙트에서 이루어짐)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1023&quot; data-origin-height=&quot;1015&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/spi5o/btsDJkfukkX/G0h7zY6RyxaK2UOiEd7rN1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/spi5o/btsDJkfukkX/G0h7zY6RyxaK2UOiEd7rN1/img.png&quot; data-alt=&quot;중간에 Contract를 거치지않고 mint/burn/transfer/recieve 가 가능함&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/spi5o/btsDJkfukkX/G0h7zY6RyxaK2UOiEd7rN1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fspi5o%2FbtsDJkfukkX%2FG0h7zY6RyxaK2UOiEd7rN1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1023&quot; height=&quot;1015&quot; data-origin-width=&quot;1023&quot; data-origin-height=&quot;1015&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;중간에 Contract를 거치지않고 mint/burn/transfer/recieve 가 가능함&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Natvie Token은 스마트 컨트랙트를 거치지 않고 tranfer가 가능하며, 다른 토큰과 함께 전송도 가능하다는 장점이 있다. 또한, transfer를 위한 특별한 수수료를 요구하지 않으며, 추가적인 이벤트 핸들링 로직(트랜잭션을 트래킹할)도 요구하지 않는다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 400px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 17px;&quot;&gt;ERC- 20&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 17px;&quot;&gt;Native Token&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;블록체인과의 관계&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 20px;&quot;&gt;Contract Standard로 유저의 복붙 코드&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 20px;&quot;&gt;표준이 아닌 원장에 내장되어 있음.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 38px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 38px;&quot;&gt;컨트롤 주체&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 38px;&quot;&gt;솔리디티 스마트 컨트랙트&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 38px;&quot;&gt;카르다노가 지원하는 언어의 Policy Script&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 41px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 41px;&quot;&gt;스마트 컨트랙트 mint / burn 을 실행 가능한가&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 41px;&quot;&gt;YES&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 41px;&quot;&gt;YES&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;mInt 로직 커스터마이징 가능한가&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 20px;&quot;&gt;YES&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 20px;&quot;&gt;YES&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 41px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 41px;&quot;&gt;스마트 컨트랙트가 Transfer해야만 하는가&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 41px;&quot;&gt;YES&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 41px;&quot;&gt;NO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 41px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 41px;&quot;&gt;다른 스마트 컨트랙트가 특별한 지원없이 사용할 수 있는가&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 41px;&quot;&gt;NO&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 41px;&quot;&gt;YES&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;다른 토큰과 함께 전송되는가&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 20px;&quot;&gt;NO&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 20px;&quot;&gt;YES&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;Transfer 로직이 제공되는 것&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 20px;&quot;&gt;ERC20 템플릿의 복붙 코드&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 20px;&quot;&gt;카르다노 렛저&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;Transfer 로직이 커스터아밍되는가&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 20px;&quot;&gt;YES&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 20px;&quot;&gt;NO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 41px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 41px;&quot;&gt;Transfer 를 위해 특별한 수수료가 요구되는가&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 41px;&quot;&gt;YES&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 41px;&quot;&gt;NO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 41px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 41px;&quot;&gt;Transfer를 위한 추가적인 이벤트 핸들링이 필요한가&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 41px;&quot;&gt;YES&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 41px;&quot;&gt;NO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;non-fungible token을 지원하는가&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 20px;&quot;&gt;NO&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 20px;&quot;&gt;YES&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;Readable 메타데이터&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 20px;&quot;&gt;스마트 컨트랙트에 의해서 제공&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 20px;&quot;&gt;off-chain의 메타데이터 서버에서 제공&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ERC-20은 사실상 스마트 컨트랙트의 내부에서 Account의 value를 관리하는 구조라고 본다면, 카르다노 Native token은 원장에서 지원하기 때문에 스마트 컨트랙트의 보유량 확인과 같은 이벤트 핸들링이 필요하지 않으며, 동시에 여러 기능도 지원한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 카르다노 네이티브 토큰은 Security 측면에서 더 우수하다고 판단한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ERC-20은 보안에 취약하다. Contract Standard를 따르기 때문에 발행되는 ERC-20은 코드 상으로 다른 차이가 존재할 수 있으며, 이로인해 예기치 못한 오류와 버그가 발생할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카르다노 네이티브 토큰은 토큰 생성과 거래에 Ledger가 로직을 처리하기 때문에 ERC-20의 overflow나 underflow같은 취약성은 제거된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;즉, Standard 코드를 활용하는 과정에서 발생하는 코드 상의 오류, overflow와 underflow 취약점 그리고 gas price 공격과 같은 리스크는 카르다노 네이티브 토큰에선 존재할 수 없다.&lt;/b&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네이티브 토큰 발행은 아래 링크를 통해서 진행하면 된다. Monentary Policy 스크립트만 준비되면 cardano-cli를 통해서 mint할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developers.cardano.org/docs/native-tokens/minting/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://developers.cardano.org/docs/native-tokens/minting/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1705841799150&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;Minting Native Assets | Cardano Developer Portal&quot; data-og-description=&quot;How to mint native tokens on Cardano.&quot; data-og-host=&quot;developers.cardano.org&quot; data-og-source-url=&quot;https://developers.cardano.org/docs/native-tokens/minting/&quot; data-og-url=&quot;https://developers.cardano.org/docs/native-tokens/minting&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cUdhQ1/hyU8W8ySyq/sKYkjreniL2wIYpbbHEcAK/img.png?width=2400&amp;amp;height=1258&amp;amp;face=0_0_2400_1258,https://scrap.kakaocdn.net/dn/XZd3G/hyU8V2TkW4/z2zW2rwPg7Zn6lwGcvoOMK/img.png?width=2400&amp;amp;height=1258&amp;amp;face=0_0_2400_1258,https://scrap.kakaocdn.net/dn/broaaq/hyU8WOgEkc/68ANy9qjf2dHAokxSo8ayK/img.png?width=4379&amp;amp;height=1126&amp;amp;face=0_0_4379_1126&quot;&gt;&lt;a href=&quot;https://developers.cardano.org/docs/native-tokens/minting/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developers.cardano.org/docs/native-tokens/minting/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cUdhQ1/hyU8W8ySyq/sKYkjreniL2wIYpbbHEcAK/img.png?width=2400&amp;amp;height=1258&amp;amp;face=0_0_2400_1258,https://scrap.kakaocdn.net/dn/XZd3G/hyU8V2TkW4/z2zW2rwPg7Zn6lwGcvoOMK/img.png?width=2400&amp;amp;height=1258&amp;amp;face=0_0_2400_1258,https://scrap.kakaocdn.net/dn/broaaq/hyU8WOgEkc/68ANy9qjf2dHAokxSo8ayK/img.png?width=4379&amp;amp;height=1126&amp;amp;face=0_0_4379_1126');&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;Minting Native Assets | Cardano Developer Portal&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;How to mint native tokens on Cardano.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developers.cardano.org&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;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고 자료&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developers.cardano.org/docs/native-tokens/minting/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://developers.cardano.org/docs/native-tokens/minting/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://forum.cardano.org/t/native-custom-tokens-on-cardano-the-anatomy-and-why-its-better-than-erc-tokens/59744&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://forum.cardano.org/t/native-custom-tokens-on-cardano-the-anatomy-and-why-its-better-than-erc-tokens/59744&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/IntersectMBO/cardano-ledger/blob/master/doc/explanations/features.rst&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/IntersectMBO/cardano-ledger/blob/master/doc/explanations/features.rst&lt;/a&gt;&lt;/p&gt;</description>
      <category>Cardano</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/399</guid>
      <comments>https://tigercoin.tistory.com/399#entry399comment</comments>
      <pubDate>Sun, 21 Jan 2024 21:30:22 +0900</pubDate>
    </item>
    <item>
      <title>Crossplane, Terraform을 대체할 수 있을까. 개념과 비교해보기</title>
      <link>https://tigercoin.tistory.com/398</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Crossplane은&amp;nbsp;쿠버네티스&amp;nbsp;익스텐션&amp;nbsp;오픈소스다.&amp;nbsp;K8S&amp;nbsp;API를&amp;nbsp;통해서&amp;nbsp;쿠버네티스를&amp;nbsp;포함한&amp;nbsp;모든&amp;nbsp;리소스를&amp;nbsp;매니징할&amp;nbsp;수&amp;nbsp;있게&amp;nbsp;해준다. &lt;br /&gt;&lt;br /&gt;Cloud&amp;nbsp;Native&amp;nbsp;Compute&amp;nbsp;Foundation(CNCF)의&amp;nbsp;프로젝트로,&amp;nbsp;현재&amp;nbsp;AWS,&amp;nbsp;Azure와&amp;nbsp;같은&amp;nbsp;클라우드&amp;nbsp;리소스&amp;nbsp;매니징에&amp;nbsp;많이&amp;nbsp;사용된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2066&quot; data-origin-height=&quot;632&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dPz6p5/btsDC62VGXu/PSHEAj3BZtk0vPiWbtT9L1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dPz6p5/btsDC62VGXu/PSHEAj3BZtk0vPiWbtT9L1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dPz6p5/btsDC62VGXu/PSHEAj3BZtk0vPiWbtT9L1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdPz6p5%2FbtsDC62VGXu%2FPSHEAj3BZtk0vPiWbtT9L1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2066&quot; height=&quot;632&quot; data-origin-width=&quot;2066&quot; data-origin-height=&quot;632&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Crossplane?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;쿠버네티스 클러스터로부터 외부, non-쿠버네티스 리소스와 연결하고 이 리소스를 활용하는데 사용됨&lt;/li&gt;
&lt;li&gt;Kubernetes CRD로 만들어져 쿠버네티스 오브젝트의 external 리소스다.&lt;/li&gt;
&lt;li&gt;external resource의 state를 감시하고, state를 적용하는 쿠버네티스 컨트롤러 역할을 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Crossplane Components&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Crossplane의&amp;nbsp;강점은&amp;nbsp;Composition에&amp;nbsp;있다.&amp;nbsp;다른&amp;nbsp;유형의&amp;nbsp;리소스를&amp;nbsp;결합해서&amp;nbsp;새로운&amp;nbsp;유형의&amp;nbsp;리소스&amp;nbsp;구축이&amp;nbsp;가능하다.&amp;nbsp;예를&amp;nbsp;들면&amp;nbsp;kubernetes&amp;nbsp;cluster와&amp;nbsp;nodepool를&amp;nbsp;만들거나,&amp;nbsp;DB&amp;nbsp;인스턴스와&amp;nbsp;스키마,&amp;nbsp;유저를&amp;nbsp;만들&amp;nbsp;때&amp;nbsp;등등&amp;nbsp;효율적인&amp;nbsp;매니징이&amp;nbsp;가능하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1067&quot; data-origin-height=&quot;252&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdVFC4/btsDCTJtFeI/Sy816w1FZkqHQOfUm5WLok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdVFC4/btsDCTJtFeI/Sy816w1FZkqHQOfUm5WLok/img.png&quot; data-alt=&quot;https://prune998.medium.com/playing-with-crossplane-for-real-f591e66065ae&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdVFC4/btsDCTJtFeI/Sy816w1FZkqHQOfUm5WLok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdVFC4%2FbtsDCTJtFeI%2FSy816w1FZkqHQOfUm5WLok%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1067&quot; height=&quot;252&quot; data-origin-width=&quot;1067&quot; data-origin-height=&quot;252&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://prune998.medium.com/playing-with-crossplane-for-real-f591e66065ae&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가&amp;nbsp;만약&amp;nbsp;Postresql&amp;nbsp;인스턴스를&amp;nbsp;claim&amp;nbsp;하면,&amp;nbsp;Composite&amp;nbsp;Resource를&amp;nbsp;참조하고&amp;nbsp;CloudSQLInstance와&amp;nbsp;Firewall&amp;nbsp;Rule을&amp;nbsp;생성하게된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1067&quot; data-origin-height=&quot;695&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GqzEv/btsDA4ELN8w/tTsdANKcePmSdcCOq6YSK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GqzEv/btsDA4ELN8w/tTsdANKcePmSdcCOq6YSK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GqzEv/btsDA4ELN8w/tTsdANKcePmSdcCOq6YSK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGqzEv%2FbtsDA4ELN8w%2FtTsdANKcePmSdcCOq6YSK0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1067&quot; height=&quot;695&quot; data-origin-width=&quot;1067&quot; data-origin-height=&quot;695&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위&amp;nbsp;과정을&amp;nbsp;좀&amp;nbsp;더&amp;nbsp;세부적으로&amp;nbsp;접근하면,&amp;nbsp;다음과&amp;nbsp;같다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;CRD(Custom Resource Definition) 생성: 프로바이더는 각 클라우드 리소스를 관리하기 위해 CRD를 생성. (노란 박스의 CRD)&lt;/li&gt;
&lt;li&gt;XRD(CompositeResourceDefinition) 생성: 인프라 팀은 XRD를 생성하여 지정된 매개변수를 조정 인터페이스를 생성.&lt;/li&gt;
&lt;li&gt;Crossplane에 의한 CRD 생성 및 관리: Crossplane은 XRD를 기반으로 두 가지 새로운 CRD를 생성하고 maintain함. (하나는 Claim, 다른 하나는 CompositeResource(XR, 초록박스)임) Crossplane은 이 CRD를 기반으로 CR(CustomResource)를 관찰하고 조정함&lt;/li&gt;
&lt;li&gt;Composition 생성: 인프라 팀은 Composition을 생성함. 이 Composition은 원본 XRD와 CRD 목록을 참조하여 리소스를 생성. 이 과정은 XRD 인터페이스에서 값을 가져와 리소스를 템플릿화하는 것과 유사함.&lt;/li&gt;
&lt;li&gt;리소스 클레임: 개발 팀은 리소스(다이어그램의 보라색 박스)를 Claim하게됨. Claim은 Crossplane이 유지 관리하는 특정 유형의 CustomResource.&lt;/li&gt;
&lt;li&gt;CompositeResource(XR) 생성: Crossplane은 Claim을 기반으로 XR을 생성.&lt;/li&gt;
&lt;li&gt;CustomResource(CR) 생성: Crossplane은 CompositeResource(XR)의 내용에 기반하여 제공자의 리소스 인스턴스인 CR을 생성&lt;/li&gt;
&lt;li&gt;리소스 조정: 제공자는 관리하는 리소스를 조정하고, GCP(Google Cloud Platform) API를 호출하여 CR에 선언된 리소스를 생성. &amp;nbsp;&amp;nbsp;&lt;br /&gt;&lt;br /&gt;더 쉬운 이해를 위해 비유를 하자면,&lt;/li&gt;
&lt;/ol&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Provider: 레스토랑에서 요리를 만들기 위해 재료를 공급하는 공급업체&lt;/li&gt;
&lt;li&gt;CRD(Custom Resource Definition): 레스토랑에서 사용하는 재료의 레시피로, 주방장이 이 CRD를 보고 요리를 할 수있음&lt;/li&gt;
&lt;li&gt;XRD(Composite Resource Definition): 여러 레시피를 하나의 메뉴로 만드는 것임. 하나의 메뉴라고 보면됨.&lt;/li&gt;
&lt;li&gt;Claim과 XR(Composite Resource): Claim은 손님이 주문으로 원하는 요리를 요청하는 것. XR은 주방에서 실제로 요리를 준비하는 과정임.&lt;/li&gt;
&lt;li&gt;CR(Custom Resource): 요리가 완성되면 개별 접시에 담아 제공됨. 하나의 메뉴에 여러 접시에 담긴 요리가 있음. 이 개별 접시 요리가 CR이며, 클라우드 리소스 단위임.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Terraform&amp;nbsp;vs&amp;nbsp;Crossplane&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;테라폼은&amp;nbsp;크로스플레인의&amp;nbsp;주요&amp;nbsp;비교대상이다.&amp;nbsp; &lt;br /&gt;&lt;br /&gt;공통적으로&amp;nbsp;둘다&amp;nbsp;엔지니어가&amp;nbsp;인프라를&amp;nbsp;선언적으로&amp;nbsp;구성할&amp;nbsp;수&amp;nbsp;있으며,&amp;nbsp;Provider&amp;nbsp;Plugin을&amp;nbsp;지원하기&amp;nbsp;때문에&amp;nbsp;다양한&amp;nbsp;인프라&amp;nbsp;관리가&amp;nbsp;가능하다.&amp;nbsp;특히&amp;nbsp;적극적인&amp;nbsp;커뮤니티가&amp;nbsp;있다.&amp;nbsp;물론&amp;nbsp;Crossplane이&amp;nbsp;좀&amp;nbsp;더&amp;nbsp;작다. &lt;br /&gt;&lt;br /&gt;차이점은 Crossplane이 Control plane이라면 Terraform은 Control plane에 대한 Interface가 CLI 라는 것이다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Collaboration&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;협업에 있어 Terraform은 작업 중에 state 파일에 의존하며, 전체 인프라 구성을 적용하는 동안에 다른 변경이 불가능함. Crossplane은 XRM으로 리소스의 느슨한 결합으로 결과 일관성을 가지기 때문에 협업 확장에 도움이됨.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Self Servie&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Terraform은 모듈로 자체 서비스 모델을 지원하기에 협업 제약에 종속됨. Crossplane은 API 엔드포인트로 노출되는 Composite Resource를 통해 더 높은 수준의 접근 제어 추상화가 제공됨.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Integration and Automation&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Terraform은&amp;nbsp;자체&amp;nbsp;API&amp;nbsp;제공이&amp;nbsp;안되며&amp;nbsp;주로&amp;nbsp;CI/CD&amp;nbsp;파이프라인을&amp;nbsp;통해서&amp;nbsp;자동화됨.&amp;nbsp;Crssplane은&amp;nbsp;지속적으로&amp;nbsp;인프라를&amp;nbsp;감시하고&amp;nbsp;변경이&amp;nbsp;있으면&amp;nbsp;자동으로&amp;nbsp;조정됨.&amp;nbsp;특히&amp;nbsp;API&amp;nbsp;제공하기&amp;nbsp;때문에&amp;nbsp;자동화에&amp;nbsp;유리함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Terraform는 관리할 리소스의 사이즈가 커질 수록 복잡해지며, tfstate 관리가 쉽지않다. 특히, Terraform으로 생성한 리소스가 콘솔 상에서 수정이 일어나면 곤란한 상황도 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 부분에선 확실히 Crossplane이 우위를 가지고 있다. 둘은 공식 문서에서도 나와있듯이 대체재보단, 보완재로 활용되어도 좋을 것같다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;직접 테스트해본 결과, 쿠버네티스 기반의 Gitops + ArgoCD로 CD 파이프라인을 활용한다면, crossplane은 아주 유용할 것같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2064&quot; data-origin-height=&quot;490&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bX9QXl/btsDGrzQLTd/7G0cyVIjehk3f0XT200r0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bX9QXl/btsDGrzQLTd/7G0cyVIjehk3f0XT200r0K/img.png&quot; data-alt=&quot;https://marketplace.upbound.io/providers&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bX9QXl/btsDGrzQLTd/7G0cyVIjehk3f0XT200r0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbX9QXl%2FbtsDGrzQLTd%2F7G0cyVIjehk3f0XT200r0K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2064&quot; height=&quot;490&quot; data-origin-width=&quot;2064&quot; data-origin-height=&quot;490&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://marketplace.upbound.io/providers&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Crossplane은 어플리케이션의 클라우드 리소스와 쿠버네티스 리소를 패키징 + 상태 유지할 수 있다. 심지어 unbound marketplace에 가면, 기본적으로 aws, gcp, azure는 모두 지원하며 종류가 생각보다 많으며 문서도 잘 정리되어 있어 쉽게 적용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실무에 조금씩 활용해보면서, 시간나면 후기를 정리해보려 한다.&lt;/p&gt;</description>
      <category>DevOps/Opensource</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/398</guid>
      <comments>https://tigercoin.tistory.com/398#entry398comment</comments>
      <pubDate>Thu, 18 Jan 2024 21:29:51 +0900</pubDate>
    </item>
    <item>
      <title>Cardano EUTXO 핸드북 한글판</title>
      <link>https://tigercoin.tistory.com/397</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://forum.cardano.org/t/eutxo/115363&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://forum.cardano.org/t/eutxo/115363&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1704889036292&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;  EUTXO 핸드북 (통합본)&quot; data-og-description=&quot;EUTXO 핸드북 소개 블록체인 회계 모델이란 무엇인가? UTXO 모델 vs 계정/잔고 모델: 간략한 개요 UTXO UTXO 모델의 &amp;lsquo;거스름돈&amp;rsquo; 개념 UTXO 모델의 장점 계정/잔고 모델 EUTXO 모델 트랜잭션에 대해 해야&quot; data-og-host=&quot;forum.cardano.org&quot; data-og-source-url=&quot;https://forum.cardano.org/t/eutxo/115363&quot; data-og-url=&quot;https://forum.cardano.org/t/eutxo/115363&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/h0oAn/hyU2kJaYv5/IM2SBrW0juAFiAV6eN35U1/img.png?width=1024&amp;amp;height=331&amp;amp;face=0_0_1024_331,https://scrap.kakaocdn.net/dn/dgNTYh/hyU2qiiv1z/H0kb2YyN9ocy8VKfbOzxo1/img.png?width=1024&amp;amp;height=331&amp;amp;face=0_0_1024_331,https://scrap.kakaocdn.net/dn/cJkEdh/hyU2iq3Q2s/HnkKn2lA2uoMKQKlr7BkW0/img.png?width=602&amp;amp;height=253&amp;amp;face=0_0_602_253&quot;&gt;&lt;a href=&quot;https://forum.cardano.org/t/eutxo/115363&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://forum.cardano.org/t/eutxo/115363&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/h0oAn/hyU2kJaYv5/IM2SBrW0juAFiAV6eN35U1/img.png?width=1024&amp;amp;height=331&amp;amp;face=0_0_1024_331,https://scrap.kakaocdn.net/dn/dgNTYh/hyU2qiiv1z/H0kb2YyN9ocy8VKfbOzxo1/img.png?width=1024&amp;amp;height=331&amp;amp;face=0_0_1024_331,https://scrap.kakaocdn.net/dn/cJkEdh/hyU2iq3Q2s/HnkKn2lA2uoMKQKlr7BkW0/img.png?width=602&amp;amp;height=253&amp;amp;face=0_0_602_253');&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;  EUTXO 핸드북 (통합본)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;EUTXO 핸드북 소개 블록체인 회계 모델이란 무엇인가? UTXO 모델 vs 계정/잔고 모델: 간략한 개요 UTXO UTXO 모델의 &amp;lsquo;거스름돈&amp;rsquo; 개념 UTXO 모델의 장점 계정/잔고 모델 EUTXO 모델 트랜잭션에 대해 해야&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;forum.cardano.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EUTXO에 대해서 간단히 정리한 글을 포스팅했지만, 위 카르다노 포럼에서 세부적인 내용들이 잘 정리되어 있다. 참고!&lt;/p&gt;</description>
      <category>Cardano</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/397</guid>
      <comments>https://tigercoin.tistory.com/397#entry397comment</comments>
      <pubDate>Wed, 10 Jan 2024 21:18:27 +0900</pubDate>
    </item>
    <item>
      <title>Cardano의 회계 모델, Extended-UTXO(EUTXO)</title>
      <link>https://tigercoin.tistory.com/396</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;카르다노의 회계 모델인 EUTXO는 카르다노 네트워크의 대표적인 장점 중 하나다. 현재 다양한 레이어들이 저마다 생태계를 만들고 있지만, UTXO 방식을 사용하는 레이어는 수많은 프로젝트들 중에 비트코인과 카르다노뿐 인것으로 알고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카르다노는 UTXO의 확장 모델인 Extended-UTXO를 개발하여 체인의 보안과 병렬 처리를 통한 확장성을 높였다. UTXO, EUTXO가 이더리움의 Account 모델과 비교해 어떤 특징과 장점이 있는지 정리해보려 한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;UTXO(Unspent Transaction Output)와 Account 모델&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1547&quot; data-origin-height=&quot;751&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c0kTCi/btsDiREAxcS/r48XZLNNhjdD4brgXvR2tK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c0kTCi/btsDiREAxcS/r48XZLNNhjdD4brgXvR2tK/img.png&quot; data-alt=&quot;https://www.horizen.io/academy/utxo-vs-account-model/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c0kTCi/btsDiREAxcS/r48XZLNNhjdD4brgXvR2tK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc0kTCi%2FbtsDiREAxcS%2Fr48XZLNNhjdD4brgXvR2tK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1547&quot; height=&quot;751&quot; data-origin-width=&quot;1547&quot; data-origin-height=&quot;751&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.horizen.io/academy/utxo-vs-account-model/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UTXO는 미사용 거래 출력(Unspent Transaction Output)의 약자로, 거래가 실행된 후 남아있는 통화의 양을 나타낸다. Account 모델은 유저의 잔액을 추적한다. 둘은 쉽게 말해서 장부를 처리하는 방식의 차이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 말하는 장부는 state를 기록하고 하나의 state가 다른 state로 전환한다.&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;Account Model&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;대부분의 블록체인 네트워크가 사용하는 모델이다. 은행 계좌와 유사하다. 주소의 현재 잔액만 유지되기 때문에 일일이 한 주소에서 자산을 빼고 더하고를 통해 글로벌 상태를 업데이트한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;903&quot; data-origin-height=&quot;814&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/K6z56/btsDhTJk4Ff/aDdWJQ5s6z7CCdyF5p49f1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/K6z56/btsDhTJk4Ff/aDdWJQ5s6z7CCdyF5p49f1/img.png&quot; data-alt=&quot;https://cardanians.io/en/understanding-cardano-extended-utxo-200&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/K6z56/btsDhTJk4Ff/aDdWJQ5s6z7CCdyF5p49f1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FK6z56%2FbtsDhTJk4Ff%2FaDdWJQ5s6z7CCdyF5p49f1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;903&quot; height=&quot;814&quot; data-origin-width=&quot;903&quot; data-origin-height=&quot;814&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://cardanians.io/en/understanding-cardano-extended-utxo-200&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Account 모델에서 글로벌 상태는 모든 계정의 데이터베이스와 다양한 자산의 현재 잔액으로 볼 수 있다. Account 모델은 거래 내역을 기반으로 계산된다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;UTXO&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처리된 트랜잭션 후에 남아있는 디지털 자산의 수를 UTXO라고 말하며, UTXO는 자산의 이동이 주소 간 DAG(방향성 비순환 그래프)로 기록된다. DAG는 거래 출력은 한 번만 등장하지만 순환 구조가 허용되지 않는 것을 말한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1481&quot; data-origin-height=&quot;969&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oHqlQ/btsDh8fxaNn/AkqiNHVNkmM3XJdxcJwdlk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oHqlQ/btsDh8fxaNn/AkqiNHVNkmM3XJdxcJwdlk/img.png&quot; data-alt=&quot;https://cardanians.io/en/understanding-cardano-extended-utxo-200&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oHqlQ/btsDh8fxaNn/AkqiNHVNkmM3XJdxcJwdlk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoHqlQ%2FbtsDh8fxaNn%2FAkqiNHVNkmM3XJdxcJwdlk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1481&quot; height=&quot;969&quot; data-origin-width=&quot;1481&quot; data-origin-height=&quot;969&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://cardanians.io/en/understanding-cardano-extended-utxo-200&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 유저 계정의 잔액은 주소에 연결된 미사용 UTXO를 합산하여 계산된다. 그래서, 각 거래의 출력을 독립적인 단위로 처리하며, 유저의 잔액은 출력들의 집합으로부터 도출된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그림을 보면 알겠지만, 사용되지 않은 파란색 UTXO를 합산하여 계정의 잔액이 계산된다. 파란색의 UTXO는 다른 말로, 사용가능한 거래 출력이라고도 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 State N + 5의 상태가 현재라고 간주한다면, 파란색의 UTXO를 기준으로 전체 네트워크의 글로벌 상태가 구성된다고 보면 된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Extended-UTXO&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카르다노는 다중자산과 스마트 컨트랙트 지원을 위해 UTXO의 한 단계 발전된 EUTXO를 개발하여 사용한다. 이는 Alonzo 업그레이드에 도입되었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UTXO 모델을 두 가지 방식으로 확장했다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1) 스크립트 지원&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;잠금을 공개 키로, 키를 서명으로 제한하여 EUTXO 모델의 address에 스크립트가 포함된다. 노드가 트랜잭션 검증할 때, 노드는 트랜잭션이 특정 출력을 입력으로 사용할 수 있는지 여부를 결정한다. 사용가능하다면 스크립트를 실행한다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2) 임의의 데이터 전달&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출력에 주소와 값 외에 임의의 데이터를 전달할 수 있도록 하여 state 정보를 활용할 수 있게 되었다. 이는 스크립트를 훨씬 더 유용하게 만들어 준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국, 출력 주소에 복잡한 논리를 포함할 수 있게 되어 잠금 해제가 가능한 트랜잭션을 결정하고 모든 출력에 유저 정의 데이터를 추가하여 UTXO의 기능을 확장했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국, Account 모델 기반의 Dapp에서 작동하는 디자인 패턴은 Cardano에선 구현이 불가능하다. 데이터의 기본 표현이 달라, 새로운 디자인 패턴이 요구된다. 하지만 여러 UTXO를 사용하여 더 많은 병렬 처리가 가능하며, 확장 측면에서 장점이 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;EUTXO의 장점&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) 거래 유효성 검증&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션 검증의 성공과 실패 여부는 트랜잭션 자체와 입력에만 달려있다. 결국, 거래가 이루어지기 전에 거래의 유효성을 오프체인에서 확인이 가능하다. (Account 모델에서는 스크립트 실행에서 트랜잭션 실패 확률이 있음)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) 높은 수준의 병렬화&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;검증이 오프체인, Local에서 가능하기 때문에 높은 수준의 병렬 처리가 가능하다. 노드는 트랜잭션을 병렬로 검증할 수 있으며, 효율성과 추론 측면에서 훌륭한 퍼포먼스를 보여줄 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) 수수료 예측&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EUTXO는 결정적 트랜잭션의 특성과 함께 오프체인에서 검증이 가능하기 때문에 거래에 필요한 수수료를 거래 전에 정확하게 예측이 가능하다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고&lt;br /&gt;&lt;a href=&quot;https://docs.cardano.org/learn/eutxo-explainer/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.cardano.org/learn/eutxo-explainer/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://iohk.io/en/blog/posts/2021/03/11/cardanos-extended-utxo-accounting-model/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://iohk.io/en/blog/posts/2021/03/11/cardanos-extended-utxo-accounting-model/&lt;/a&gt;&lt;/p&gt;</description>
      <category>Cardano</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/396</guid>
      <comments>https://tigercoin.tistory.com/396#entry396comment</comments>
      <pubDate>Wed, 10 Jan 2024 21:14:23 +0900</pubDate>
    </item>
    <item>
      <title>Cardano Staking pool Wiki 정리</title>
      <link>https://tigercoin.tistory.com/394</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;현재 수 많은 블록체인 네트워크가 있지만, 그 중에 개인적으로 미래가 가장 기대되는 프로젝트는 카르다노다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;합의 알고리즘인 Ouroboros, EUTXO 모델과 함수형 언어인 Haskell 기반의 네트워크기 때문에 보안성, 탈중앙화, 확장성 이 세가지 블록체인 트릴레마 최대한 해결하고 있다고 생각한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;996&quot; data-origin-height=&quot;547&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cm46b6/btsC1pgZBCV/PiNMVhwpvBEg2KGo8c4u9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cm46b6/btsC1pgZBCV/PiNMVhwpvBEg2KGo8c4u9k/img.png&quot; data-alt=&quot;blockchain&amp;amp;amp;nbsp;trilemma&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cm46b6/btsC1pgZBCV/PiNMVhwpvBEg2KGo8c4u9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcm46b6%2FbtsC1pgZBCV%2FPiNMVhwpvBEg2KGo8c4u9k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;996&quot; height=&quot;547&quot; data-origin-width=&quot;996&quot; data-origin-height=&quot;547&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;blockchain&amp;amp;nbsp;trilemma&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 현재 DevOps 엔지니어로 일하고 있는 만큼, 네트워크의 보안과 분산화에 기여하는 카르다노의 스테이킹 풀에 대해서 관심이 있다. 관련된 기본적인 정보들을 간단히 정리해보려고 한다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;스테이킹(staking)?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스테이킹은 카르다노 네트워크의 분산화와 보안에 참여하는 프로세스라고 보면 된다. $ADA 홀더들은 스테이킹을 통해서 보상을 받는다. 자신의 월렛에 있는 ADA를 풀에 위임하면, 풀은 늘어난 지분을 통해 블록 생성 가능성이 높아진다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1866&quot; data-origin-height=&quot;637&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cY1nqK/btsC4dAmc2v/rXP7OOYXDri1ckoLzY0lWk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cY1nqK/btsC4dAmc2v/rXP7OOYXDri1ckoLzY0lWk/img.png&quot; data-alt=&quot;현재 운영 중인 풀들&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cY1nqK/btsC4dAmc2v/rXP7OOYXDri1ckoLzY0lWk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcY1nqK%2FbtsC4dAmc2v%2FrXP7OOYXDri1ckoLzY0lWk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1866&quot; height=&quot;637&quot; data-origin-width=&quot;1866&quot; data-origin-height=&quot;637&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;현재 운영 중인 풀들&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대표적인 PoS 체인인 이더리움은 스테이킹하면 ETH가 락업된다. 그러나 카르다노에선 풀에 스테이킹하더라도 락업되지 않으며, 자유롭게 사용가능하다. 풀 운영자의 운영 실수로 인해 스테이커의 ADA가 슬래시될 위험도 없다. 5일이라는 에포크 단위의 스냅샷 기준으로 위임을 인정받기 때문에 스냅샷 시점만 지키면 된다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Pool saturation?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카르다노의 장점은 높은 탈중앙성이다. 특정 풀에 지분이 집중되는 것을 방지하기 위해서 saturation이라는 매개변수를 사용한다. 스테이킹된 ADA가 saturation 수준을 초과하면 스테이커와 풀 운영자에게 지급되는 보상이 줄어들게 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1869&quot; data-origin-height=&quot;739&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sHxZm/btsC4tXjXxe/U0Ren6Oi9XAUWZZncSXK9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sHxZm/btsC4tXjXxe/U0Ren6Oi9XAUWZZncSXK9K/img.png&quot; data-alt=&quot;https://forum.cardano.org/t/k-150-500-1000-visualized/41984&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sHxZm/btsC4tXjXxe/U0Ren6Oi9XAUWZZncSXK9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsHxZm%2FbtsC4tXjXxe%2FU0Ren6Oi9XAUWZZncSXK9K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1869&quot; height=&quot;739&quot; data-origin-width=&quot;1869&quot; data-origin-height=&quot;739&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://forum.cardano.org/t/k-150-500-1000-visualized/41984&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 매개변수를 통해서 스테이커가 다른 스테이킹 풀에 위임하도록 유도하며 탈중앙성을 유지한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 매개변수 k는 이상적인 것으로 간주되는 기존 풀의 수를 결정한다. 유통 중인 ADA 수를 K로 나누어 포화점을 계산하게 된다. 내가 현재 글을 쓰는 지금은 saturation이 약 70m 정도다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Epoch&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카르다노에서는 시간이 5일 단위로 구분된다. epoch 사이에 ADA의 잔액을 스캔하는 스냅샷이 발생한다. 에포크는 보상이 지급되는 회계 기간으로 사용되며, 풀 운영자와 스테이커에게 보상을 주기 위해 이 스냅샷을 활용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 epoch는 432,000초가 있으며, 이는 새 블록이 생성될 수 있는 슬롯 수에 해당한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Cardano</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/394</guid>
      <comments>https://tigercoin.tistory.com/394#entry394comment</comments>
      <pubDate>Thu, 4 Jan 2024 00:14:16 +0900</pubDate>
    </item>
    <item>
      <title>Promtail - Loki을 이용하여 쿠버네티스 Container 로그파일 모니터링하기</title>
      <link>https://tigercoin.tistory.com/393</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;우리 팀에선 Loki-Prometheus-Grafana 스택으로 서비스 로그와 메트릭을 Grafana에 통합하여 모니터링하고 있다. 특히, Loki는 Container의 stdout, stderr 로그를 생성된 파드 기준으로 Promtail을 통해 수집하는데, debug 로그는 컨테이너 내부에서. log 파일 형태로 저장한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1342&quot; data-origin-height=&quot;575&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Icbx6/btsCMzcSuk2/PUWfJZ8Y5JSxdJ46XlBFr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Icbx6/btsCMzcSuk2/PUWfJZ8Y5JSxdJ46XlBFr1/img.png&quot; data-alt=&quot;디버그 로그파일인 service.log&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Icbx6/btsCMzcSuk2/PUWfJZ8Y5JSxdJ46XlBFr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIcbx6%2FbtsCMzcSuk2%2FPUWfJZ8Y5JSxdJ46XlBFr1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1342&quot; height=&quot;575&quot; data-origin-width=&quot;1342&quot; data-origin-height=&quot;575&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;디버그 로그파일인 service.log&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서비스 로그 레벨은 3으로 설정되어 있어, 문제가 생길 때마다 컨테이너에 있는 debug 파일을 확인하는게 아주 번거롭다. 그렇다고 로그레벨 수정을 위해 실행 중인 서비스를 재실행할 수 도 없었기에,&amp;nbsp; retention을 최대한 줄이더라도 debug 로그를 수집할 필요가 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;이 로그 파일을 로깅하기 위해서 고민했던 방식은 크게 3가지였다.&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;hostpath로 노드에 컨테이너 로그 파일을 저장하여 Promtail로 로깅&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;PVC를 활용하여 로그 파일 저장하여 Promtail로 로깅&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;emptydir로 로그 파일 저장하여 같은 파드 내의 Promtail sidecar로 로깅&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫번째는 Promtail이 기본적으로 노드 별로 추가적인 scrapeConfig 설정이 가능했기 때문에 고민했던 방법이다. 그러나 hostpath로 마운트된 노드 볼륨에 로그파일을 적재하면, 파드의 라이프사이클에 맞춰 삭제하는 테스크가 필요했다. 만약 삭제가 되지 않을 경우에 노드의 볼륨 문제가 발생할 수 있어 주의해야 했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 번째는 외부 볼륨을 통한 로그 파일 관리가 가능하다면, 노드에 영향을 주지 않고도 로그 파일을 한 곳에 적재할 수 있겠다는 판단이 들었다. 그러나, Promtail의 PV 접근이 까다롭고 클러스터 내에서 해결할 수 있는 문제가 아니었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국, 세번째 방법인 파드의 emptydir 볼륨을 이용해서 로그파일을 저장하고, Promtail을 sidecar 컨테이너로 실행하여 로깅하는 것으로 결정했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이 방법은 emptydir 볼륨은 파드의 라이프사이클과 동일하기에, 파드와 함께 삭제될 수 있었고 같은 파드 내에서 서비스 컨테이너와 함께 실행된 Promtail도 emptydir 볼륨에 접근이 가능했기 때문에 간단했다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구현 순서에 대해서 간단히 설명하자면,&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Configmap을 이용하여 Promtail Config.yml 생성&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Promtail이 실행될 때 사용할 config 파일을 configmap으로 선언한다고 보면 된다. 아래와 같이 실행될 서비스의 네임스페이스, loki의 gateway 주소, job-name과 쿼리 될 레이블, 그리고 log파일의 경로를 선언해 준다.&lt;/p&gt;
&lt;pre id=&quot;code_1703687018905&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: v1
kind: ConfigMap
metadata:
  name: promtail-sidecar-config-map
  namespace: {{ namespace }}
data:
  config.yml: |
      server:
        http_listen_port: 9080
        grpc_listen_port: 0
        log_level: &quot;debug&quot;
      positions:
        filename: /tmp/positions.yaml
      clients: 
        - url: {{ loki-url }}
      scrape_configs:
        - job_name:  {{ job-name }}
          static_configs:
            - targets:
                - localhost
              labels:
                app: {{ app }}
                __path__: {{ log-path }}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Helm chart에서 emptydir 볼륨 마운트 + Promtail Sidecar 추가 + configmap 볼륨 마운트&lt;/h4&gt;
&lt;pre id=&quot;code_1703687142289&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  volumes:
  - name: log-volume
    emptyDir: {}
		# emptyDir 선언, log 파일을 적재할 공간 
		# promtail sidecar와 서비스 컨테이너가 같이 공유함
  - name: config
    configMap:
      name: promtail-sidecar-config-map
		# configmap을 통해 config파일을 지정
  ...
      - name: promtail-sidecar
      volumeMounts:
        - name: log-volume
          mountPath: /log
  	   	  # log 파일이 저장되는 volume 마운트
        - name: config
          mountPath: /etc/promtail
		  # configmap을 통해 지정된 config를 mountPath에 저장
  ...
      - name: fn
      volumeMounts:
        - name: log-volume
          mountPath: /log
		  # 서비스 컨테이너가 저장할 log volume 마운트, /log 경로에 저장&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 grafana/promtail의 config는 /etc/promtail/config.yml를 호출하기 때문에 경로와 파일명을 맞춰야 한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Promtail 로그&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2101&quot; data-origin-height=&quot;525&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qYhwb/btsCEJHP9X1/NppbbbhBdB4HV3iZZemY50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qYhwb/btsCEJHP9X1/NppbbbhBdB4HV3iZZemY50/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qYhwb/btsCEJHP9X1/NppbbbhBdB4HV3iZZemY50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqYhwb%2FbtsCEJHP9X1%2FNppbbbhBdB4HV3iZZemY50%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2101&quot; height=&quot;525&quot; data-origin-width=&quot;2101&quot; data-origin-height=&quot;525&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 설정을 통해서 /log/service.log라는 로그파일을 수집하는 Promtail 컨테이너 로그를 확인할 수 있다.&lt;/p&gt;</description>
      <category>DevOps/Monitoring</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/393</guid>
      <comments>https://tigercoin.tistory.com/393#entry393comment</comments>
      <pubDate>Wed, 27 Dec 2023 23:31:08 +0900</pubDate>
    </item>
    <item>
      <title>ERC1155, Multi-token standard</title>
      <link>https://tigercoin.tistory.com/392</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;ERC1155&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ERC1155는 가스 효율적인 Token Contract를 만들기 위해서 이전 표준을 최대한 활용하기 위해 만들어진 토큰 표준이다. &lt;b&gt;좀 더 이해하기 쉽게 얘길하자면, 하나의 컨트랙트에서 여러 토큰을 발행해서 관리한다고 볼 수 있다.&lt;/b&gt; &lt;b&gt;심지어 ERC20, ERC721 모두 지원한다. 그래서 Multi-token standard라고 불린다.&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ERC1155의 특징은 단일 스마트 컨트랙트를 이용해서 여러 토큰을 한번에 표현&lt;/li&gt;
&lt;li&gt;각 토큰 마다 고유한 id 를 기준으로 구분된 balanceOf 메소드를 호출 가능&lt;/li&gt;
&lt;li&gt;모든 state를 하나의 컨트랙트에 존재하기 때문에 단일 트랜잭션에서 다양한 토큰 관리 가능&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;1082&quot; data-origin-height=&quot;645&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Il4sN/btsz932iyPZ/A4ILQ5rZ5Y3Zeep72iKIZ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Il4sN/btsz932iyPZ/A4ILQ5rZ5Y3Zeep72iKIZ0/img.png&quot; data-alt=&quot;배포 스크립트를 보면 어떤 느낌인지 바로 알 수 있음 by 오픈제플린&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Il4sN/btsz932iyPZ/A4ILQ5rZ5Y3Zeep72iKIZ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIl4sN%2Fbtsz932iyPZ%2FA4ILQ5rZ5Y3Zeep72iKIZ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1082&quot; height=&quot;645&quot; data-origin-width=&quot;1082&quot; data-origin-height=&quot;645&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;배포 스크립트를 보면 어떤 느낌인지 바로 알 수 있음 by 오픈제플린&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Features&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Batch Transfer: 여러 에셋을 하나의 Tx로 전송가능&lt;/li&gt;
&lt;li&gt;Batch Balance: 여러 에셋을 하나의 콜로 balance 확인 가능&lt;/li&gt;
&lt;li&gt;Batch Approval: 모든 토큰을 하나의 주소에 approve 가능&lt;/li&gt;
&lt;li&gt;Hooks: token hook 받기&lt;/li&gt;
&lt;li&gt;NFT Support: 발행량이 1이라면, NFT로 사용가능&lt;/li&gt;
&lt;li&gt;Safe Transfer Rules: 안전한 Transfer rule&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 기능들 중 Batch Transfer와 Hooks만 한 번 보자.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Batch Transfer&lt;/h4&gt;
&lt;pre id=&quot;code_1699768829643&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// ERC-20
function transferFrom(address from, address to, uint256 value) external returns (bool);

// ERC-1155
function safeBatchTransferFrom(
    address _from,
    address _to,
    uint256[] calldata _ids,
    uint256[] calldata _values,
    bytes calldata _data
) external;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ERC20는 transferFrom 메소드로 하나의 Tx 콜로 하나의 토큰 전송만 가능하지만 ERC1155는 에셋의 고유번호인 ids가 array로 입력할 수 있어 여러 토큰을 한번에 trasfer 하는 것이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ids = [1, 3], values = [100, 5] 로 transfer 하게되면 id가 1인 에셋 100개가 _to로 전송되고, 3인 에셋은 4개만 전송된다고 보면 된다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Receive Hook&lt;/h4&gt;
&lt;pre id=&quot;code_1699769106164&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function onERC1155BatchReceived(
    address _operator,
    address _from,
    uint256[] calldata _ids,
    uint256[] calldata _values,
    bytes calldata _data
) external returns(bytes4);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;receive hook은 토큰이 특정 주소로 전송될 때 호출되는 함수다. &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;ERC1155는 EIP165를 지원하기 때문에&lt;span&gt; 이를 이용해서 &lt;/span&gt;&lt;/span&gt;전송된 토큰을 안전하게 처리하기 위해 수신하는 컨트랙트가 인터페이스를 구현하는지 체크한다.&lt;/p&gt;
&lt;pre id=&quot;code_1699769449531&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;bytes4(keccak256(&quot;onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)&quot;))&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #498bb5; text-align: start;&quot;&gt;onERC1155BatchReceived&lt;/span&gt; 를 호출하여 bytes4로 변환되어 받는 magic value가 있으면 존재하는 것으로 판단하고 다음 액션을 취한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/Solidity</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/392</guid>
      <comments>https://tigercoin.tistory.com/392#entry392comment</comments>
      <pubDate>Sun, 12 Nov 2023 15:23:22 +0900</pubDate>
    </item>
    <item>
      <title>ERC-721, Non-Fungible Token</title>
      <link>https://tigercoin.tistory.com/391</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;ERC721, NFT는 크립토에 관심이 없는 사람들도 아는 대표적인 토큰 유형으로 toknID 기준, 다른 토큰들과는 구별되는 고유한 특성이 있다. 워낙 유명해서.. 굳이 소개할 필요는 없을 것같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 활동하는 CURG 라는 블록체인 학회에서 관련 코드를 재정리했기 때문에 코드 구성을 한번 확인하고 정리해보려 한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;SolRoot/token/ERC-721&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CURG 학회에서 진행하는 오픈소스 프로젝트인 SolRoot에서 ERC-721 코드 디렉토리는 다음과 같이 구성되어 있다. (Extension은 제외)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ERC721Base.sol&lt;/li&gt;
&lt;li&gt;ERC721Extension.sol&lt;/li&gt;
&lt;li&gt;ERC721Metadata.sol&lt;/li&gt;
&lt;li&gt;ERC721SlotBase.sol&lt;/li&gt;
&lt;li&gt;ERC721Utils.sol&lt;/li&gt;
&lt;li&gt;IERC721.sol&lt;/li&gt;
&lt;li&gt;IERC721Enumerable.sol&lt;/li&gt;
&lt;li&gt;IERC721Metadata.sol&lt;/li&gt;
&lt;li&gt;IERC721Receiver.sol&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 인터페이스를 살펴보자.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;IERC721&lt;/h4&gt;
&lt;pre id=&quot;code_1699165102346&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.0;

import { IERC165 } from &quot;../../interfaces/IERC165.sol&quot;;

interface IERC721 is IERC165 {

    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
	// tokenId 토큰이 from 주소에서 to 주소로 이전

    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
	// tokenId 토큰에 대해 owner가 approved 주소에게 권한 부여

    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
	// owner가 operator에게 자신의 모든 토큰을 관리할 권한 부여
    // true일때 권한 부여, false일때 권한 취소

    function owners(uint256 tokenId) external view returns (address);
	// tokenId에 해당하는 토큰 소유자의 address 반환
    
    function balances(address account) external view returns (uint256);
	// account가 소유한 토큰의 수를 반환

    function tokenApprovals(uint256 tokenId) external view returns (address);
	// tokenId 토큰에 대한 승인된 주소를 반환

    function operatorApprovals(address owner, address operator) external view returns (bool);
	// owner에 의해 operator에게 부여된 모든 토큰을 관리할 수 있는 권한의 유무를 반환

    function balanceOf(address owner) external view returns (uint256 balance);
    // owner의 주소에 해당하는 토큰의 수를 반환

    function ownerOf(uint256 tokenId) external view returns (address owner);
	// 특정 tokenId의 소유자 address 반환

    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes calldata data
    ) external;
 	// from -&amp;gt; to tokenId 토큰을 전송, calldata와 함께 전달됨
    // 해당 계약이 토큰을 받을 수 있는지 확인하는 safe 장치가 존재
   
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;
	// from -&amp;gt; to tokenId 토큰을 전송하지만 추가 데이터 없이 전송
    // 해당 계약이 토큰을 받을 수 있는지 확인하는 safe 장치가 존재

    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;
    // safe 장치 없이 tokenId를 from -&amp;gt; to 이전 

    function approve(address to, uint256 tokenId) external;
	// tokenId에 대한 transfer 권한을 to에게 부여

    function setApprovalForAll(address operator, bool approved) external;
	// 호출자가 operator에게 자신의 모든 토큰을 관리할 수 있는 권한을 부여하거나 취소

    function getApproved(uint256 tokenId) external view returns (address operator);
	// 특정 tokenId에 대해서 현재 승인된 주소를 반환

    function isApprovedForAll(address owner, address operator) external view returns (bool);
	// owner가 operator에게 자신의 모든 토큰을 관리할 수 있느 권한을 부여했는지 여부 반환
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터페이스를 보면 특이하게 transfer가 3가지다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;transferFrom&lt;/li&gt;
&lt;li&gt;data를 포함하는 safeTransferFrom&lt;/li&gt;
&lt;li&gt;data가 없는 safeTransferFrom&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;safe가 붙지않는 transferFrom은 말그대로 안전장치없이 NFT가 전송되는 함수다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1699183869442&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    function transferFrom(address from, address to, uint256 tokenId) public virtual override {
        require(
            _isApprovedOrOwner(_msgSender(), tokenId),
            &quot;ERC721: caller is not token owner or approved&quot;);

        _transfer(from, to, tokenId);
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 safeTransferFrom은 아래와 같이 data를 포함여부를 기준으로 2가지로 나뉘어 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1699183641257&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    function _safeTransfer(
        address from,
        address to,
        uint256 tokenId,
        bytes memory data
    ) internal virtual {
        _transfer(from, to, tokenId);
        require(
            _checkOnERC721Received(from, to, tokenId, data),
            &quot;ERC721: transfer to non ERC721Receiver implementer&quot;);
    }

    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public virtual override {
        safeTransferFrom(from, to, tokenId, &quot;&quot;);
    }

	function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes memory data
        ) public virtual override {
            require(_isApprovedOrOwner(_msgSender(), tokenId),
            &quot;ERC721: caller is not token owner or approved&quot;);
            _safeTransfer(from, to, tokenId, data);
        }&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;data 매개변수가 없는 버전은 결론적으로 data 파라미터가 &quot;&quot;로 비어있는 상태에서 다시 data 매개변수가 있는 safeTransferFrom을 호출한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 두 메소드는 결국엔 _isApprovedOrOwner를 통해서 Owner이거나 approve된 account인지를 확인한 다음,&amp;nbsp; internal로 선언된 _safeTransfer를 호출해서&amp;nbsp; _checkOnERC721Received 조건을 만족하는지 확인하고 _transfer가 호출된다.&lt;/p&gt;
&lt;pre id=&quot;code_1699186589463&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    function _checkOnERC721Received(
        address from,
        address to,
        uint256 tokenId,
        bytes memory data
    ) private returns (bool) {
        if (to.isContract()) {
            try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) {
                return retval == IERC721Receiver.onERC721Received.selector;
            } catch (bytes memory reason) {
                if (reason.length == 0) {
                    revert(&quot;ERC721: transfer to non ERC721Receiver implementer&quot;);
                } else {
                    /// @solidity memory-safe-assembly
                    assembly {
                        revert(add(32, reason), mload(reason))
                    }
                }
            }
        } else {
            return true;
        }
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;_checkOnERC721Received()가 사실상 safe 장치의 핵심인데, 이 녀석은 안전한 토큰 trasfer를 보장하기 위해서 토큰을 받는 컨트랙트가 IERC721Receiver 인터페이스를 잘 구현했는지 확인한다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;to.isContract: 주소 to가 컨트랙트 주소인지 확인 (to가 EOA라면 함수는 바로 true를 반환함)&lt;/li&gt;
&lt;li&gt;to가 컨트랙트 주소일 경우, onERC721Received 함수를 호출 (보내는 주소 from, tokenId 이전되는 토큰 Id와 추가 데이터를 파라미터로 받음) bytes4 타입 반환&lt;/li&gt;
&lt;li&gt;return retval == IERC721Receiver.onERC721Received.selector; 호출 성공하면 반환 값인 retval이 onERC721Received의 selector와 일치하는 지 확인, 일치 시 true 반환&lt;/li&gt;
&lt;li&gt;onERC721Received 호출 실패시에는 에러메시지인 reason이 catch되어 2가지로 분기처리됨 (에러 메시지가 없으면 단순 revert, 있으면 에러메시지 출력)&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;간단히 정리하면, to로 받는 주소가 컨트랙트일 경우에 NFT 토큰을 관리할 인터페이스가 없으면 관리에 문제가 생기므로, onERCReceived 확인하는 절차라고 보면 된다.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1699186244106&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    function _transfer(address from, address to, uint256 tokenId) internal virtual {
        require(ownerOf(tokenId) == from, &quot;ERC721: transfer from incorrect owner&quot;);
        require(to != address(0), &quot;ERC721: transfer to the zero address&quot;);

        _beforeTokenTransfer(from, to, tokenId, 1);

        // Check that tokenId was not transferred by `_beforeTokenTransfer` hook
        require(ownerOf(tokenId) == from, &quot;ERC721: transfer from incorrect owner&quot;);

        // Clear approvals from the previous owner
        setTokenApproval(tokenId, address(0));

        unchecked {
            // `_balances[from]` cannot overflow for the same reason as described in `_burn`:
            // `from`'s balance is the number of token held, which is at least one before the current
            // transfer.
            // `_balances[to]` could overflow in the conditions described in `_mint`. That would require
            // all 2**256 token ids to be minted, which in practice is impossible.
            setBalances(from, balances(from) - 1);
            setBalances(to, balances(to) + 1);
        }
        setOwners(tokenId, to);

        emit Transfer(from, to, tokenId);

        _afterTokenTransfer(from, to, tokenId, 1);
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;internal로 선언된 _transfer 코드를 보면, transfer 전에 hook으로 _beforeTokenTransfer() 메소드 그리고 transfer 이후의 hoo인 _afterTokenTransfer()도 선언되어 있다. 특히 _beforeTokenTransfer() 실행 후에 혹시나 모를 상황을 대비한 owner를 확인하는 require 문을 추가로 선언했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이외에는 storageSlot을 활용해서 지정된 슬롯에 데이터를 할당하도록 하는 ERC721Metadata와 ERC721SlotBase 그리고 URI를 설정하는 ERC721Utils, 여러 기능을 추가한 ERC721Extensions로 구성된다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 크립토 씬에서 NFT는 대체로 PFP로 많이 사용된다. 그러나 NFT의 궁극적인 활용가치는 소유권을 쉽게 증명하는데 있다고 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ERC6551을 활용하면 NFT하나로 여러 컨트랙트의 Ownership을 쉽게 관리할 수 있는데, 여기서 더욱 효용있는 유스케이스가 생겨날 것이라고 우리 CURG 팀은 생각하고 있다.&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/Solidity</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/391</guid>
      <comments>https://tigercoin.tistory.com/391#entry391comment</comments>
      <pubDate>Sun, 5 Nov 2023 15:19:15 +0900</pubDate>
    </item>
    <item>
      <title>ERC-6551, NFT Bound Account</title>
      <link>https://tigercoin.tistory.com/390</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;짧게 TBA라고도 하는 ERC-6551은 NFT의 오너가 여러 컨트랙트를 컨트롤할 수 있는 권한을 가지고 있는 것이라고 보면된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;즉, NFT + CA의 결합이라고도 보는데, 이 TBA의 NFT는 '지갑의 역할을 하기 때문에 누군가에게 양도되는 순간, 이 NFT에 있는 모든 자산도 그대로 양도된다.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;디사이퍼 미디움에 따르면, 여러 유스케이스를 예상할 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Gas Fee 절약&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;NFT를 살때 개별 NFT마다 Tx가 일어나야했지만, TBA에 NFT Collection이 있다면 한번의 Tx로 모든 NFT를 구매할 수 있음&lt;/li&gt;
&lt;li&gt;게임의 경우에도 하나의 NFT TBA안에 캐릭터와 물약, 아이템이 있다면 한번에 거래가 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;보안의 향상&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;NFT 판매 시점에 ERC-20 토큰을 내재한 채로 판매하여 에어드랍 가능&lt;/li&gt;
&lt;li&gt;별도의 스냅샷 없이도 NFT TBA의 NFT, ERC-20을 에어드랍할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Interactive NFT&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;온체인으로 상호작용 가능한 NFT 생성 가능,&lt;/li&gt;
&lt;li&gt;NFT TBA에 ERC-20과 ERC-721이 있을 경우 새로운 형태로 표현하거나 강화 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/decipher-media/erc-6551%EC%9D%98-%ED%8A%B9%EC%A7%95%EA%B3%BC-%EC%82%AC%EB%A1%80-91057d8410dd&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;출처&lt;/a&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1861&quot; data-origin-height=&quot;971&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqTJOc/btszLmA5KuU/KSnKzqMpRJGK2m26HgZNkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqTJOc/btszLmA5KuU/KSnKzqMpRJGK2m26HgZNkk/img.png&quot; data-alt=&quot;https://eips.ethereum.org/EIPS/eip-6551&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqTJOc/btszLmA5KuU/KSnKzqMpRJGK2m26HgZNkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqTJOc%2FbtszLmA5KuU%2FKSnKzqMpRJGK2m26HgZNkk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1861&quot; height=&quot;971&quot; data-origin-width=&quot;1861&quot; data-origin-height=&quot;971&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://eips.ethereum.org/EIPS/eip-6551&lt;/figcaption&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;ERC6551에는 두 가지 주요 구성 요소가 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;토큰 바인딩 Account를 위한 싱글 Registry&lt;/li&gt;
&lt;li&gt;토큰 바인딩 Account 구현을 위한 공통 Interface&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Registry&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;레지스트리는 모든 토큰 바인딩 Account의 진입점 역할을 하는 싱글톤 Contract다. 쉽게 말해서 Account를 생성하고 관리하는데 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 NFT에 대해 바인딩된 계정이 존재하는 지 확인하거나 새 account를 생성하는 역할을 담당한다..&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;createAccount implementation&lt;/b&gt;: 주어진 address로 NFT에 대한 토큰 바인딩 account 생성&lt;/li&gt;
&lt;li&gt;&lt;b&gt;account implementation:&lt;/b&gt; 주어진 address에 따라 NFT에 대한 토큰 바인딩 account address를 계산&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1699162622181&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface IERC6551Registry {
    /**
     * @dev The registry SHALL emit the AccountCreated event upon successful account creation
     */
    event AccountCreated(
        address account, // Account 주소
        address indexed implementation, // 사용된 구현체 주소
        uint256 chainId, // Chain ID
        address indexed tokenContract, // 토큰 컨트랙트 주소
        uint256 indexed tokenId, // 토큰 ID
        uint256 salt // 토큰에 사용된 salt 값
    ); // Account가 성공적으로 생성되었을 때 발생하는 이벤트

    function createAccount(
        address implementation, // 계정 생성에 사용될 구현체 주소
        uint256 chainId, // Chain ID
        address tokenContract, // 토큰 컨트랙트 주소
        uint256 tokenId, // 토큰 ID
        uint256 salt, // Account 주소 생성에 사용될 salt
        bytes calldata initData // 계정 초기화에 사용될 데이터
    ) external returns (address); // 생성된 Account 주소값 리
		// NFT 에대한 토큰 바인딩 Account 생성

    function account(
        address implementation,
        uint256 chainId,
        address tokenContract,
        uint256 tokenId,
        uint256 salt
    ) external view returns (address);
		// 특정 NFT의 토큰 바인딩 주소를 계산하여 반환
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Account&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 NFT와 연결된 Account를 나타낸다. Account는 ETH를 받을 수 있으며, 어떤 NFT에 연결되어있는 지에 대한 정보도 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 Account는 NFT 소유자에 의해서 컨트롤된다.&lt;/p&gt;
&lt;pre id=&quot;code_1699162784000&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/// @dev the ERC-165 identifier for this interface is `0x6faff5f1`
interface IERC6551Account {

    receive() external payable;

    function token()
        external
        view
        returns (
            uint256 chainId, // 토큰이 존재하는 체인의 EIP155 ID
            address tokenContract, // 토큰 컨트랙트의 주소
            uint256 tokenId // 토큰 ID
        );

    function state() external view returns (uint256);
		// 계정의 상태가 변경될 때마다 변경되어야 하는 값을 반환
		// 반환 값은 계정의 현재 상태값

    function isValidSigner(address signer, bytes calldata context)
        external
        view
        returns (bytes4 magicValue);
		// 주어진 서명자가 계정을 대신해서 행동할 권한이 있는지 여부
		// 기본적으로 계정이 연결된 NFT 소유자는 유효한 서명자로 간주되어야함
		// signer 서명 권한을 확인할 주소
		// context 서명자가 유효성을 결정하는데 사용되는 추가 데이터
		// 리턴 값은 서명자의 유효성을 나타내는 magicValue

		// Account 인터페이스는 NFT 소유권과 관련해 특정 계정의 기능과 상태를 관리하고 검증
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/Solidity</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/390</guid>
      <comments>https://tigercoin.tistory.com/390#entry390comment</comments>
      <pubDate>Sun, 5 Nov 2023 14:46:14 +0900</pubDate>
    </item>
    <item>
      <title>OpenZeppelin ERC-20 Solidity 코드 리뷰</title>
      <link>https://tigercoin.tistory.com/389</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;OpenZepplin&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오픈제플린은 EVM 스마트 컨트랙트 개발에 많이 사용되는 오픈 소스 라이브러리다. 사실상 Solidity 기반 컨트랙트 개발에 있어선 표준으로 자리 잡을 정도로 사용된다.&amp;nbsp;&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;Security-Centric&lt;/b&gt; : 보안 전문가들에 의해서 검토되어 있으며, 실사용되고 있는 검증된 컨트랙트들로 구성되어 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Standard Contracts&lt;/b&gt; : ERC-20, ERC-721과 같은 표준 토큰 컨트랙트를 제공함.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Reusable Components&lt;/b&gt; : 공통기능을 제공하는 다양한 스마트 계약 구성 요소를 포함하고 있어서, 개발자들은 이를 조합해 복잡한 기능을 빠르고 안전하게 구현가능.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Community-Driven :&lt;/b&gt; 활발한 커뮤니티에 의해 지원되고 있으며, 보안과 최적화 및 기타 주제에 대해서 지식을 공유하고 있음.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Plugins and Extensibility :&lt;/b&gt; Hardhat, Truffle 등의 인기있는 이더리움 개발 도구를 지원&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오픈제플린에는 여러 코드들이 있는데, 그 중 컨트랙트 개발에 있어서 가장 기본이 되는 ERC20 코드를 리뷰하려 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Defi, Dex 등 크립토 씬의 모든 섹터를 통틀어 자산거래에 있어 ERC20은 다 사용되기 때문에 살펴보면 좋다. 특히 오픈제플린의 소스코드가 얼마나 보안적으로 안전하고 검증되었는지를 확인해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1503&quot; data-origin-height=&quot;998&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4pZJp/btsxiez44yn/N60QY1LFhxl2ooEOVcPgHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4pZJp/btsxiez44yn/N60QY1LFhxl2ooEOVcPgHK/img.png&quot; data-alt=&quot;https://docs.openzeppelin.com/contracts/5.x/api/token/erc20&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4pZJp/btsxiez44yn/N60QY1LFhxl2ooEOVcPgHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4pZJp%2Fbtsxiez44yn%2FN60QY1LFhxl2ooEOVcPgHK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1503&quot; height=&quot;998&quot; data-origin-width=&quot;1503&quot; data-origin-height=&quot;998&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://docs.openzeppelin.com/contracts/5.x/api/token/erc20&lt;/figcaption&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;b&gt;IERC20&lt;/b&gt; : ERC20의 모든 실행의 인터페이스.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;IERC20Metadata&lt;/b&gt; : ERC20 인터페이스의 익스텐션으로 name, symbol, decimals 함수를 포함함.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ERC20&lt;/b&gt; : ERC20 인터페이스 Implementation으로 standard extension&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[ERC20Base.sol]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1696850827317&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol)

pragma solidity ^0.8.0;

import { IERC20 } from &quot;./IERC20.sol&quot;;
import { ERC20Metadata } from &quot;./ERC20Metadata.sol&quot;;

import { ERC20SlotBase } from &quot;./ERC20SlotBase.sol&quot;;
import { StorageSlot, Uint256Slot } from &quot;../../utils/StorageSlot.sol&quot;;
// 아래에 StorageSlot에 대한 추가 설명 있음

import { Context } from &quot;../../utils/Context.sol&quot;;

abstract contract ERC20Base is IERC20, ERC20Metadata, Context {
    function getSlotTotalSupply() private pure returns (Uint256Slot storage) {
        // TODO: slot offset conventions
        return StorageSlot.getUint256Slot(ERC20SlotBase-4);
    }

    function getSlotBalance(address account) private pure returns (Uint256Slot storage) {
        // TODO: slot offset conventions
        return StorageSlot.getUint256Slot(keccak256(abi.encode(ERC20SlotBase, account)));
    }
    function getSlotAllowance(address owner, address spender) private pure returns (Uint256Slot storage) {
        // TODO: slot offset conventions
        return StorageSlot.getUint256Slot(keccak256(abi.encode(ERC20SlotBase, owner, spender)));
    }
		// StorageSlot의 totalSupply, balance, allowance의 슬롯 위치를 반환하는 getter 메소드.

    function setTotalSupply(uint256 _totalSupply) internal {
        getSlotTotalSupply().value = _totalSupply;
    }
    function setBalance(address account, uint256 balance) internal {
        getSlotBalance(account).value = balance;
    }
    function setAllowance(address owner, address spender, uint256 _allowance) internal {
        getSlotAllowance(owner, spender).value = _allowance;
    }
		// StorageSlot 위치를 반환해서 해당 슬롯의 변수값 totalSupply, balance, allowance를 변경하는 setter 메소드

    function totalSupply() public view override returns (uint256) {
        return getSlotTotalSupply().value;
    }
    function balanceOf(address account) public view override returns (uint256) {
        return getSlotBalance(account).value;
    }
    function allowance(address owner, address spender) public view override returns (uint256) {
        return getSlotAllowance(owner, spender).value;
    }
		// IERC20 인터페이스에 정의된 메소드를 재정의

    function transfer(address to, uint256 amount) public virtual override returns (bool) {
        address owner = _msgSender();
        _transfer(owner, to, amount);
        return true;
    }

    function approve(address spender, uint256 amount) public virtual override returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, amount);
        return true;
    }

    function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, amount);
        _transfer(from, to, amount);
        return true;
    }

    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, allowance(owner, spender) + addedValue);
        return true;
    }

    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
        address owner = _msgSender();
        uint256 currentAllowance = allowance(owner, spender);
        require(currentAllowance &amp;gt;= subtractedValue, &quot;ERC20: decreased allowance below zero&quot;);
        unchecked {
            _approve(owner, spender, currentAllowance - subtractedValue);
        }

        return true;
    }
		// 외부에서 호출가능한 메소드들로 virtual로 선언되어 override가 가능함.
		// 실제 동작하는 메소드는 _(언더스코어)로 선언된 internal 메소드들임

    function _transfer(address from, address to, uint256 amount) internal virtual {
        require(from != address(0), &quot;ERC20: transfer from the zero address&quot;);
        require(to != address(0), &quot;ERC20: transfer to the zero address&quot;);
		// require을 통해 조건부 검증 진행, from, to가 0이면 트랜잭션 실패

        _beforeTokenTransfer(from, to, amount);
		// hook 함수 실행

        // TODO: balanceOf optimization?
        uint256 fromBalance = balanceOf(from);
        require(fromBalance &amp;gt;= amount, &quot;ERC20: transfer amount exceeds balance&quot;);
        unchecked {
            setBalance(from, fromBalance - amount);
            // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
            // decrementing then incrementing.
            setBalance(to, balanceOf(to)+amount);
        }
		// overlfow, underflow 발생 시 revert

        emit Transfer(from, to, amount);
		// transfer 이벤트 발생

        _afterTokenTransfer(from, to, amount);
		// hook 함수 실행
    }

    function _mint(address account, uint256 amount) internal virtual {
        require(account != address(0), &quot;ERC20: mint to the zero address&quot;);
		// account가 0인 경우 트랜잭션 실패

        _beforeTokenTransfer(address(0), account, amount);
		// hook 메소드 실행

        // TODO: totalSupply optimization?
        setTotalSupply(totalSupply() + amount);
		// totalSupply 추가 발행
 
        unchecked {
            // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
            setBalance(account, balanceOf(account) + amount);
        }
		// account의 토큰 수량 증가, 오버플로우, 언더플로우 시 revert

        emit Transfer(address(0), account, amount);
		// Transfer 이벤트 실행

        _afterTokenTransfer(address(0), account, amount);
		// hook 메소드 실행
    }

    function _burn(address account, uint256 amount) internal virtual {
        require(account != address(0), &quot;ERC20: burn from the zero address&quot;);
		// account가 0인 경우 트랜잭션 실패

        _beforeTokenTransfer(account, address(0), amount);
		// hook 메소드 실행

        // TODO: balanceOf optimization?
        uint256 accountBalance = balanceOf(account);
        require(accountBalance &amp;gt;= amount, &quot;ERC20: burn amount exceeds balance&quot;);
		// account 보유 수량이 burn 수량보다 적으면 트랜잭션 실패

        unchecked {
            setBalance(account, accountBalance - amount);
            // Overflow not possible: amount &amp;lt;= accountBalance &amp;lt;= totalSupply.
            setTotalSupply(totalSupply()-amount);
        }
		// 오버플로우와 언더플로우 시 revert

        emit Transfer(account, address(0), amount);
		// Transfer 이벤트 실행

        _afterTokenTransfer(account, address(0), amount);
		// hook 메소드 실행
    }

    function _approve(address owner, address spender, uint256 amount) internal virtual {
        require(owner != address(0), &quot;ERC20: approve from the zero address&quot;);
        require(spender != address(0), &quot;ERC20: approve to the zero address&quot;);
		// owner, spender의 address가 0이면 트랜잭션 실패

        setAllowance(owner, spender, amount);
		// owner의 토큰을 spender가 사용할 수 있는 수량 설정
        emit Approval(owner, spender, amount);
		// approval 이벤트 실행
    }

    function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance != type(uint256).max) {
            require(currentAllowance &amp;gt;= amount, &quot;ERC20: insufficient allowance&quot;);
		// 현재 allowance가 사용하려는 amount보다 적을 때 트랜잭션 실패
            unchecked {
                _approve(owner, spender, currentAllowance - amount);
            }
		// approve 메소드 실행, 오버플로우 언더플로우 발생시 revert
        }
    }

    function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}
		// 토큰 전송 전에 실행되는 훅 메소드 정의

    function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}
		// 토큰 전송 후에 실되는 훅 메소드 정의
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;+ 추가 개념&lt;/b&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;StorageSlot&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Storage Slot에 대한 접근과 관리를 도와주는 유틸리티 라이브러리. Storage Slot은 이더리움 스토리지의 각 위치를 나타냄&lt;/li&gt;
&lt;li&gt;Ethereum 스토리지는 key-value 저장소로 구성되어 있음. 각 key는 256 bit Slot&lt;/li&gt;
&lt;li&gt;Smart Contract의 변수는 이 Slot에 저장되며, Slot의 개념은 Ehtereum Gas비용과 스토리지 최적화와 관련이 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;StorageSlot이 필요한 이유&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Gas 최적화&lt;/b&gt; : Ethereum에서는 스토리지 변경 때마다 gas가 소비됨. 변수의 배치와 사용 방식으로 스토리지를 효율적으로 활용하면 Gas 비용을 절약할 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터 무결성 :&lt;/b&gt; 스마트 컨트랙트 코드가 업그레이드 되거나 변경될 때 스토리지의 레이아웃이 변경되지 않도록 해야함. 잘못된 스토리지 구조 변경은 데이터 손실 유발가능&lt;/li&gt;
&lt;li&gt;&lt;b&gt;저수준 접근 :&lt;/b&gt; Storage Slot을 조작해야하는 경우가 있음. 프록시 패턴으로 컨트랙트를 업그레이드할 때 컨트랙트 스토리지 레이아웃을 그대로 유지해야함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;최적화된 데이터 구조 :&lt;/b&gt; 배열, 매핑 등의 복잡한 데이터 구조를 사용할 때, 내부적으로 여러 슬롯에 대해 이해하면 데이터 구조를 효율적으로 구성하고 관리가능&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[IERC20.sol]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1696851334178&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

interface IERC20 {
    event Transfer(address indexed from, address indexed to, uint256 value);

    event Approval(address indexed owner, address indexed spender, uint256 value);

    function totalSupply() external view returns (uint256);

    function balanceOf(address account) external view returns (uint256);

    function transfer(address to, uint256 amount) external returns (bool);

    function allowance(address owner, address spender) external view returns (uint256);

    function approve(address spender, uint256 amount) external returns (bool);

    function transferFrom(address from, address to, uint256 amount) external returns (bool);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 인터페이스를 이용해서 ERC20 컨트랙트를 배포&lt;/p&gt;</description>
      <category>개발/Solidity</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/389</guid>
      <comments>https://tigercoin.tistory.com/389#entry389comment</comments>
      <pubDate>Mon, 9 Oct 2023 20:36:50 +0900</pubDate>
    </item>
    <item>
      <title>Service Monitor 서비스 모니터 Target 등록 에러</title>
      <link>https://tigercoin.tistory.com/388</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;대부분 쿠버네티스 기반 모니터링에 특화된 Prometheus Operator를 활용하여 job을 추가한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Prometheus Operator를 사용하면 일일이 kubectl patch를 통해 configmap에서 job을 추가하지 않고도 Service monitor 혹은 Pod monitor라는 CR로 쉽게 등록이 가능하다는 장점이 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1366&quot; data-origin-height=&quot;994&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DKLan/btsv7AX14Mn/WiziNCWuEk3bX8YLWkJ06K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DKLan/btsv7AX14Mn/WiziNCWuEk3bX8YLWkJ06K/img.png&quot; data-alt=&quot;ServiceMonitor를 이용하여 등록된 Target 리스트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DKLan/btsv7AX14Mn/WiziNCWuEk3bX8YLWkJ06K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDKLan%2Fbtsv7AX14Mn%2FWiziNCWuEk3bX8YLWkJ06K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1366&quot; height=&quot;994&quot; data-origin-width=&quot;1366&quot; data-origin-height=&quot;994&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;ServiceMonitor를 이용하여 등록된 Target 리스트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;그러나 문제는 Service Monitor를 apply했는데도, Target에 등록조차 안되는 상황이 올때가 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1330&quot; data-origin-height=&quot;579&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ABID5/btswgXRHAy7/mco9jUzUkNKFC9Q5Tj5x20/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ABID5/btswgXRHAy7/mco9jUzUkNKFC9Q5Tj5x20/img.png&quot; data-alt=&quot;ServiceMonitor 리스트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ABID5/btswgXRHAy7/mco9jUzUkNKFC9Q5Tj5x20/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FABID5%2FbtswgXRHAy7%2Fmco9jUzUkNKFC9Q5Tj5x20%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1330&quot; height=&quot;579&quot; data-origin-width=&quot;1330&quot; data-origin-height=&quot;579&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;ServiceMonitor 리스트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kubectl get servicemonitor 를 확인하면 오브젝트가 정상적으로 apply된 상태임을 알 수 있다. 에러 메시지도 확인할 수 없는 상황.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;사실 프로메테우스 오퍼레이터는 초기 배포 시 namespace와 label 키 값을 설렉터로 지정하여 특정 Service monitor만 읽어들인다. 그렇기 때문에 오퍼레이터의 셀렉터 label을 확인하고 Service monitor를 배포할 필요가 있다.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1695999977477&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# redis-service-monitor.yaml

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  labels:
    app: redis 
    release: prometheus-stack
  name: redis
  namespace: monitoring
spec:
  namespaceSelector:
    any: true
  selector:
    matchLabels:
      app.kubernetes.io/instance: wemixdev-dex
      app.kubernetes.io/name: prometheus-redis-exporter
  endpoints:
  - port: redis-exporter&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위는 배포했던 Service monitor 중 하나다. label을 보면 app과 release라는 키가 설정되어있다. 나는 프로메테우스 오퍼레이터를 helm-chart로 배포했는데, 초기 배포할 때 serviceMonitorSelector로 선언된 release값은&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;942&quot; data-origin-height=&quot;333&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPdtUH/btsv8ibLp9d/O6k6wug6MdvYlLFwu9QWo0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPdtUH/btsv8ibLp9d/O6k6wug6MdvYlLFwu9QWo0/img.png&quot; data-alt=&quot;Prometheus Operator's helm chart value.yaml&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPdtUH/btsv8ibLp9d/O6k6wug6MdvYlLFwu9QWo0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbPdtUH%2Fbtsv8ibLp9d%2FO6k6wug6MdvYlLFwu9QWo0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;942&quot; height=&quot;333&quot; data-origin-width=&quot;942&quot; data-origin-height=&quot;333&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Prometheus Operator's helm chart value.yaml&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;release: prometheus라고 선언되어있다. 해당 라벨 값의 Service monitor만 불러오기 때문에 위에서 release: prometheus-stack이라는 Service monitor는 읽어오지 못한 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1211&quot; data-origin-height=&quot;203&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qzGXj/btsv8flLAUy/k50AuDJp9XalZQAHVbHdY0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qzGXj/btsv8flLAUy/k50AuDJp9XalZQAHVbHdY0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qzGXj/btsv8flLAUy/k50AuDJp9XalZQAHVbHdY0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqzGXj%2Fbtsv8flLAUy%2Fk50AuDJp9XalZQAHVbHdY0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1211&quot; height=&quot;203&quot; data-origin-width=&quot;1211&quot; data-origin-height=&quot;203&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Service monitor의 release label키를 일치시키게 했더니 이 문제는 해결되었다.&lt;/p&gt;</description>
      <category>DevOps/Monitoring</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/388</guid>
      <comments>https://tigercoin.tistory.com/388#entry388comment</comments>
      <pubDate>Sat, 30 Sep 2023 00:13:08 +0900</pubDate>
    </item>
    <item>
      <title>Grafana - Loki - Promtail 모니터링</title>
      <link>https://tigercoin.tistory.com/387</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Prometheus는 Memory와 CPU같은 하드웨어 리소스를 모니터링하는데 사용되므로 프로세스의 이벤트를 로깅하는데 한계가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ELK 스택으로 개별 모니터링 파이프라인을 구축하기도 하지만, Grafana로 로깅에 최저화된 Loki를 사용하면 이미 Prometheus + Grafana로 메트릭을 수집하던 파이프라인에서 효율적인 로깅까지도 가능해진다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Loki&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1172&quot; data-origin-height=&quot;470&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLipIw/btsv7Ws3eCG/rcgcmkTd5figMkCok5OYgk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLipIw/btsv7Ws3eCG/rcgcmkTd5figMkCok5OYgk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLipIw/btsv7Ws3eCG/rcgcmkTd5figMkCok5OYgk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLipIw%2Fbtsv7Ws3eCG%2FrcgcmkTd5figMkCok5OYgk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1172&quot; height=&quot;470&quot; data-origin-width=&quot;1172&quot; data-origin-height=&quot;470&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Loki는 2018년 Grafana Lab에서 시작한 프로젝트로 수평 확장과 높은 가용성 그리고 멀티테넌시라는 특징을 가지고 있으며 낮은 비용에 운영이 간단하다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Store the logs in Loki&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Loki는 로그 텍스트를 인덱싱하지않고, 스트림으로 그룹화, 라벨링으로 인덱싱한다. 이를 통해서 비용 절감과 함께 로그 라인 쿼리를 짧은 시간에 처리할 수 있다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;LogQL&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로키의 강력한 쿼리언어로, 로그를 explore하는데 사용한다. LogQL 쿼리는 Grafana에서 Log를 시각화한다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Distributed Storage&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그를 압축하고 동일한 로그 라인을 중복 저장하지 않도록 설계되어 있어, 스토리지 비용이 절약된다. (Loki는 로그 데이터 저장에 chunk와 index 두가지 주요 컴포넌트로 데이터를 나누어 저장함)&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Chunk : 실제 로그 데이터의 압축된 연속적 블록을 의미함. 수집한 로그 데이터를 chunk 형태로 압축하여 저장하며, 압축된 chunk는 다양한 백엔드 스토리지에 저장됨. 대표적으로 AWS S3, Google Cloud Storage 등이 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Architecture&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1098&quot; data-origin-height=&quot;940&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BSwHj/btswpW5XbTr/NQRwkCwzQuKkPK0TG3yux1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BSwHj/btswpW5XbTr/NQRwkCwzQuKkPK0TG3yux1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BSwHj/btswpW5XbTr/NQRwkCwzQuKkPK0TG3yux1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBSwHj%2FbtswpW5XbTr%2FNQRwkCwzQuKkPK0TG3yux1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1098&quot; height=&quot;940&quot; data-origin-width=&quot;1098&quot; data-origin-height=&quot;940&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로키는 Distributor, Ingester, &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Qurie,&amp;nbsp; &lt;/span&gt;Query Frontend 라는 4가지 모듈로 구성된다.&amp;nbsp;&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;Distributor&lt;/b&gt; : 클라이언트의 데이터 스트림은 Distributor에 의해서 처리되고 검증된다. 유효 데이터는 Chunk로 분할되어 병렬 처리를 위해 여러 Ingester로 전송된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Ingester&lt;/b&gt; : Ingester에 의해서 데이터가 Storage에 기록된다. 메모리 내에서의 검색의 경우에서 ingester가 데이터를 리턴한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Querier&lt;/b&gt; : Ingester와 오브젝트 스토리지에서 사용자 쿼리를 처리하는데 사용된다. 쿼리는 먼저 로컬 스토리지에서 수행된 다음, Long-term 스토리지에서 수행된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Query&lt;/b&gt; &lt;b&gt;Frontend&lt;/b&gt; : 선택적으로 쿼리에 대한 API 엔드포인트를 제공하여 대규모 쿼리를 병렬화할 수 있다. 대규모 검색을 작은 단위로 나누어 로그 읽기를 병렬로 수행한다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Promtail&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Promtail은 Loki를 위한 Log collector로 Prometheus의 서비스 디스커버리와 같은 역할을 한다. labeling, transforming 그리고 Log filtering을 Loki로 전달하기 전에 수행한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Grafana Loki의 작동&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1135&quot; data-origin-height=&quot;445&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/drR4Jx/btsv5ltlyU8/oeOwCH6qwEB87FA0OgRZZk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/drR4Jx/btsv5ltlyU8/oeOwCH6qwEB87FA0OgRZZk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/drR4Jx/btsv5ltlyU8/oeOwCH6qwEB87FA0OgRZZk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdrR4Jx%2Fbtsv5ltlyU8%2FoeOwCH6qwEB87FA0OgRZZk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1135&quot; height=&quot;445&quot; data-origin-width=&quot;1135&quot; data-origin-height=&quot;445&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;1) Promtail로 로그 가져오기 : Loki로 수집 전에 로그의 태그 지정과 변환 필터링과 같은 기능을 거친다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) Loki에 로그 저장&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) LogQL을 이용하여 탐색&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4) alert 로그&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Loki 적용 테스트&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1) &lt;a href=&quot;https://github.com/grafana/helm-charts&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/grafana/helm-charts&lt;/a&gt; / &lt;span style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;loki-stack helm chart 배포&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1696000782178&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;test_pod:
  enabled: true
  image: bats/bats:1.8.2
  pullPolicy: IfNotPresent

loki:
  enabled: true
  isDefault: true
  url: http://{{(include &quot;loki.serviceName&quot; .)}}:{{ .Values.loki.service.port }}
  readinessProbe:
    httpGet:
      path: /ready
      port: http-metrics
    initialDelaySeconds: 45
  livenessProbe:
    httpGet:
      path: /ready
      port: http-metrics
    initialDelaySeconds: 45
  datasource:
    jsonData: &quot;{}&quot;
    uid: &quot;&quot;


promtail:
  enabled: true
  config:
    logLevel: info
    serverPort: 3101
    clients:
      - url: http://{{ .Release.Name }}:3100/loki/api/v1/push&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나머지 컴포넌트는 false 설정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2) Grafana datasource 추가&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1457&quot; data-origin-height=&quot;775&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjmtEx/btsv7ADIdc6/oPunKtZkDYnBHNEKNecFl0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjmtEx/btsv7ADIdc6/oPunKtZkDYnBHNEKNecFl0/img.png&quot; data-alt=&quot;loki datasource&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjmtEx/btsv7ADIdc6/oPunKtZkDYnBHNEKNecFl0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjmtEx%2Fbtsv7ADIdc6%2FoPunKtZkDYnBHNEKNecFl0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1457&quot; height=&quot;775&quot; data-origin-width=&quot;1457&quot; data-origin-height=&quot;775&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;loki datasource&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동일 클러스터 내에서 배포되었기 때문에 릴리즈 네임과 포트 지정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3) Label filtering&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2199&quot; data-origin-height=&quot;1151&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c18Eyz/btswpVFZpfF/DYZGNGU7qAUv7LaAFtHCEK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c18Eyz/btswpVFZpfF/DYZGNGU7qAUv7LaAFtHCEK/img.png&quot; data-alt=&quot;loki explore&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c18Eyz/btswpVFZpfF/DYZGNGU7qAUv7LaAFtHCEK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc18Eyz%2FbtswpVFZpfF%2FDYZGNGU7qAUv7LaAFtHCEK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2199&quot; height=&quot;1151&quot; data-origin-width=&quot;2199&quot; data-origin-height=&quot;1151&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;loki explore&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/lonto-digital-services-integrator/grafana-loki-configuration-nuances-2e9b94da4ac1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://medium.com/lonto-digital-services-integrator/grafana-loki-configuration-nuances-2e9b94da4ac1&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.atatus.com/blog/a-beginners-guide-for-grafana-loki/&quot;&gt;https://www.atatus.com/blog/a-beginners-guide-for-grafana-loki/&lt;/a&gt;&lt;/p&gt;</description>
      <category>DevOps/Monitoring</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/387</guid>
      <comments>https://tigercoin.tistory.com/387#entry387comment</comments>
      <pubDate>Fri, 29 Sep 2023 23:52:01 +0900</pubDate>
    </item>
    <item>
      <title>쿠버네티스 컨테이너, 파드의 Volume</title>
      <link>https://tigercoin.tistory.com/382</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;쿠버네티스 컨테이너에서 정의되는 Volume은 컨테이너의 데이터를 영구적으로 저장하거나 컨테이너 간 데이터를 공유하기 위해 사용된다. 각 볼륨은 여러 목적과 특성을 가지고 있어 상황에 맞게 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복습 겸, 정리해보자.&lt;/p&gt;
&lt;pre id=&quot;code_1689510419996&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: productpage-v1
  labels:
    app: productpage
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: productpage
      version: v1
  template:
    metadata:
      annotations:
        prometheus.io/scrape: &quot;true&quot;
        prometheus.io/port: &quot;9080&quot;
        prometheus.io/path: &quot;/metrics&quot;
      labels:
        app: productpage
        version: v1
    spec:
      serviceAccountName: bookinfo-productpage
      containers:
      - name: productpage
        image: docker.io/istio/examples-bookinfo-productpage-v1:1.17.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9080
        volumeMounts:
        - name: tmp
          mountPath: /tmp
        securityContext:
          runAsUser: 1000
      volumes:
      - name: tmp
        emptyDir: {}
---&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위는 어느 어플리케이션의 Deployment 정의 내용이다. 여기서 볼륨 섹션은 spec.template.spec.containers.volumeMounts와 spec.template.spec.containers.volumes 두가지가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;굳이 순서로 따지면 volumes를 먼저 설명해야한다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;spec.template.spec.containers.volumes&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;volumes는 파드 또는 컨테이너에 사용되는 볼륨의 실제 정의를 말한다.&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;408&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnYtKj/btsnTCOSpgx/LRuCjZhIkReSk3Ekc1mrck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnYtKj/btsnTCOSpgx/LRuCjZhIkReSk3Ekc1mrck/img.png&quot; data-alt=&quot;https://livebook.manning.com/book/kubernetes-in-action-second-edition/chapter-7/v-6/14&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnYtKj/btsnTCOSpgx/LRuCjZhIkReSk3Ekc1mrck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnYtKj%2FbtsnTCOSpgx%2FLRuCjZhIkReSk3Ekc1mrck%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/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;408&quot; data-origin-width=&quot;1292&quot; data-origin-height=&quot;408&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://livebook.manning.com/book/kubernetes-in-action-second-edition/chapter-7/v-6/14&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그림에서 volumes 섹션은 Pod의 왼쪽 Volume 요소를 의미하는 것으로, 먼저 정의가 되어야 컨테이너에서 마운트할 수 있다. 이 볼륨은 여러 유형이 있는데 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;EmptyDir : EmptyDir은 파드의 라이프 사이클동안 데이터를 저장하는 임시 볼륨이다. 파드 내부의 여러 컨테이너 간에 데이터를 공유하는데 사용될 수 있다. 파드가 재시작되면 삭제된다.&lt;/li&gt;
&lt;li&gt;HostPath : 워커 노드의 파일 시스템 경로를 파드 내부로 마운트하는 방식으로 동작한다. 워커 노드 상의 파일 시스템에 접근해야하는 경우에 사용하는데, 문제는 다른 노드로 파드가 스케쥴링되면 해당 경로에 파일이 없을 수 있다.&lt;/li&gt;
&lt;li&gt;PersistentVolumeClaim (PVC) : 영구적인 데이터 저장을 위한 볼륨 유형으로, 스토리지 클래스에 의해서 백엔드 스토리지로 동적 프로비저닝될 수 있다. 파드가 삭제되더라도 PVC는 유지되기 때문에 데이터를 보존할 수 있다.&lt;/li&gt;
&lt;li&gt;ConfigMap과 Secret : 어플리케이션 정보나 암호화된 데이터를 컨테이너에 주입하는데 사용된다.&lt;/li&gt;
&lt;li&gt;Cloude Provider의 Volume : AWS같은 클라우드 프로바이더가 제공하는 스토리지 솔루션을 사용하여 영구 데이터를 저장할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 containers.volumeMounts은 정의된 볼륨을 컨테이너 파일 시스템에 마운트하는 것이라고 보면 된다. 이는 컨테이너가 볼륨과 상호작용을 위한 설정이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 yaml 파일을 통해 설명하자면,&lt;/p&gt;
&lt;pre id=&quot;code_1689511491130&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    spec:
      serviceAccountName: bookinfo-productpage
      containers:
      - name: productpage
        image: docker.io/istio/examples-bookinfo-productpage-v1:1.17.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9080
        volumeMounts:
        - name: tmp
          mountPath: /tmp
        securityContext:
          runAsUser: 1000
      volumes:
      - name: tmp
        emptyDir: {}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 파드에서 emptyDir 유형의 tmp 볼륨이 정의되었고, productpage라는 컨테이너가 이 tmp 볼륨을 컨테이너 내부 /tmp 경로로 마운트된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DevOps/Kubernetes</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/382</guid>
      <comments>https://tigercoin.tistory.com/382#entry382comment</comments>
      <pubDate>Sun, 16 Jul 2023 21:47:54 +0900</pubDate>
    </item>
    <item>
      <title>helm chart 만드는 팁</title>
      <link>https://tigercoin.tistory.com/377</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://helm.sh/ko/docs/howto/charts_tips_and_tricks/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://helm.sh/ko/docs/howto/charts_tips_and_tricks/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1688913294476&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;차트 개발 팁과 비법&quot; data-og-description=&quot;Covers some of the tips and tricks Helm chart developers have learned while building production-quality charts.&quot; data-og-host=&quot;helm.sh&quot; data-og-source-url=&quot;https://helm.sh/ko/docs/howto/charts_tips_and_tricks/&quot; data-og-url=&quot;https://helm.sh/ko/docs/howto/charts_tips_and_tricks/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cbYDay/hyTgSml5uB/YE71P461B0FfuDkMLswuKK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://helm.sh/ko/docs/howto/charts_tips_and_tricks/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://helm.sh/ko/docs/howto/charts_tips_and_tricks/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cbYDay/hyTgSml5uB/YE71P461B0FfuDkMLswuKK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;차트 개발 팁과 비법&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Covers some of the tips and tricks Helm chart developers have learned while building production-quality charts.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;helm.sh&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 helm 공식 문서에 차트 개발 팁과 비법이라는 내용이 있다.&amp;nbsp; 이 내용과 더불어 몇 가지 추가적으로 정리해보자.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. install과 upgrade 자동 실행&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1688913712017&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ helm upgrade mychart . -n mychart-ns --create-namespace --install&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;upgrade를 시도하는데, 기존 릴리즈가 없으면 install하는 명령어로 install과 upgrade를 일일이 구분할 필요없어 아주 유용하게 사용할 수 있다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. helm install pod 상태 확인 후 결과 리턴&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1688913794333&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ helm upgrade mychart . -n mychart --wait&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pod가 pending을 거쳐 Running이 될 때까지 리턴값을 받고 싶으면 --wait 옵션을 추가해주면 된다. default로 5분까지 기다리게 되는데 --timeout 15m 를 추가하면 15분까지 대기할 수 있다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3. Configmap 변경 시 Pod에 적용&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;configmap의 value값을 변경하면 configmap은 변경되지만 pod는 변경사항이 없어 재배포 되지 않는다. 이때 configmap을 사용하는 deployment.yaml에서 configmap의 변경을 감지하는 annotation을 추가해야한다.&lt;/p&gt;
&lt;pre id=&quot;code_1688913958266&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;annotations:
  checksum/config: {{ include (print $.Template.BasePath &quot;/configmap.yaml&quot;) | sha256sum }}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위처럼 추가하게 되면 configmap.yaml의 내용이 변경되면 sha256sum의 값이 변경되기 때문에 deployment.yaml에 의해 pod가 재배포되어 configmap의 변경된 내용이 반영된다.&lt;/p&gt;
&lt;pre id=&quot;code_1688914127022&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;annotations:
  rollme: {{ randAlphaNum 5 | quote }}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;configmap 변경 상관없이 pod를 재배포하는 방법으로 위 코드를 annotation에 추가한다. 배포할 때마다 값이 바뀌게 되어 pod도 재생성된다. (image tag를 latest로 사용시 유용하게 사용)&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;4. PV 변경 시 적용&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PV는 hostPath를 바꾸게 되면 오류가 발생한다.&lt;b&gt; Pod는 PVC와 바인딩 상태일 때 수정이 불가하기 때문이다.&lt;/b&gt; 이때는 Uninstall하고 다시 Install 해야 이 문제를 해결 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;여기서 Uninstall을 하려 namespace를 지우면 해당 namespace의 모든 리소스가 삭제될 수 있기 때문에 주의해야한다.&lt;/b&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;5. helm uninstall에서 namespace 삭제&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;helm은 쿠버네티스의 secret을 통해서 history 데이터를 쌓아간다. 그래서 helm histroy 명령어를 쓰면 이 secret 데이터들이 조회되어 배포 히스토리 확인이 가능해진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DevOps/Opensource</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/377</guid>
      <comments>https://tigercoin.tistory.com/377#entry377comment</comments>
      <pubDate>Sun, 9 Jul 2023 23:54:13 +0900</pubDate>
    </item>
    <item>
      <title>Grafana 헬름 차트 분석하기</title>
      <link>https://tigercoin.tistory.com/376</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Prometheus 헬름 차트에 이어 이번에는 helm test 옵션이 있는 grafana 헬름 차트를 분석해보려고 한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Grafana Helm chart&lt;/h3&gt;
&lt;pre id=&quot;code_1688910324655&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# grafana helm repo

Chart.yaml
values.yaml
README.md
templates
  - NOTES.txt
  - _helpers.tpl
  - deployment.yaml
  - statefulset.yaml
  - clusterrole.yaml
  - tests (directory)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Grafana의 template에는 tests라는 디렉토리가 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1324&quot; data-origin-height=&quot;437&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfzjAU/btsmWk3j3kR/gLdKVFYFRIygKw8l40YeMK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfzjAU/btsmWk3j3kR/gLdKVFYFRIygKw8l40YeMK/img.png&quot; data-alt=&quot;grafana helm chart의 template에 있는 tests 디렉토리&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfzjAU/btsmWk3j3kR/gLdKVFYFRIygKw8l40YeMK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfzjAU%2FbtsmWk3j3kR%2FgLdKVFYFRIygKw8l40YeMK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1324&quot; height=&quot;437&quot; data-origin-width=&quot;1324&quot; data-origin-height=&quot;437&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;grafana helm chart의 template에 있는 tests 디렉토리&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 tests는 마치 헬스체크처럼 kubernetes cluster에 grafana가 정 작동하는지를 헬스체를 한다. 아래와 같이 여러 yaml 파일이 생성되어 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1330&quot; data-origin-height=&quot;530&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DebZN/btsmQP4CAp3/2tXzRpBSwMq5SFipAIDcn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DebZN/btsmQP4CAp3/2tXzRpBSwMq5SFipAIDcn0/img.png&quot; data-alt=&quot;tests 디렉토리의 yaml 파일들&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DebZN/btsmQP4CAp3/2tXzRpBSwMq5SFipAIDcn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDebZN%2FbtsmQP4CAp3%2F2tXzRpBSwMq5SFipAIDcn0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1330&quot; height=&quot;530&quot; data-origin-width=&quot;1330&quot; data-origin-height=&quot;530&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;tests 디렉토리의 yaml 파일들&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 테스트를 위해서는 배포 테스트를 위해 아래와 같은 명령어를 진행한다.&lt;/p&gt;
&lt;pre id=&quot;code_1688910571528&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ helm test { release name }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 위 tests의 디렉토리의 yaml이 배포되어 test를 위한 pod가 생성된다. 이 pod는 grafana pod에 헬스체크하고는 바로 삭제된다. 뒤이어 helm test의 결과가 위 명령어에 이어서 터미널에 표시된다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;tests/test.yaml&lt;/h4&gt;
&lt;pre id=&quot;code_1688910746309&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{{- if .Values.testFramework.enabled }}
{{- $root := . }}
apiVersion: v1
kind: Pod
metadata:
  name: {{ include &quot;grafana.fullname&quot; . }}-test
  labels:
    {{- include &quot;grafana.labels&quot; . | nindent 4 }}
  annotations:
    &quot;helm.sh/hook&quot;: test-success
    &quot;helm.sh/hook-delete-policy&quot;: &quot;before-hook-creation,hook-succeeded&quot;
  namespace: {{ include &quot;grafana.namespace&quot; . }}
spec:
  serviceAccountName: {{ include &quot;grafana.serviceAccountNameTest&quot; . }}
  {{- with .Values.testFramework.securityContext }}
  securityContext:
    {{- toYaml . | nindent 4 }}
  {{- end }}
 ...
 
  containers:
    - name: {{ .Release.Name }}-test
      image: &quot;{{ .Values.testFramework.image}}:{{ .Values.testFramework.tag }}&quot;
      imagePullPolicy: &quot;{{ .Values.testFramework.imagePullPolicy}}&quot;
      command: [&quot;/opt/bats/bin/bats&quot;, &quot;-t&quot;, &quot;/tests/run.sh&quot;]
 ...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;{{-&amp;nbsp;if&amp;nbsp;.Values.testFramework.enabled&amp;nbsp;}}&lt;/b&gt;&lt;br /&gt;- values.yaml에 testFrameworkf의 enabled가 true가 되면 helm install되면 tests의 yaml 파일들 모두 배포되는 것을 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&amp;nbsp;annotations: &lt;/b&gt;&lt;br /&gt;&lt;b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;helm.sh/hook&quot;: test-success&lt;/b&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;- helm.sh/hook이 test-success로 annotation이 설정되면 helm install할 때 함께 배포되지 않고 helm test { release name } 을 통해서만 배포가 된다. test-success로 입력되어있나, 이는 이전 버전이며 현재 test만 설정해도 된다.&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DevOps/Opensource</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/376</guid>
      <comments>https://tigercoin.tistory.com/376#entry376comment</comments>
      <pubDate>Sun, 9 Jul 2023 23:06:09 +0900</pubDate>
    </item>
    <item>
      <title>Prometheus 헬름 차트 분석하기</title>
      <link>https://tigercoin.tistory.com/375</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Helm 차트를 무작정 만드는 것은 쉬우나, 더 적은 코드로 효율적으로 짜는 것은 쉽지않다. 그러기 위해선 이미 잘 만들어진 Helm 차트를 한번 뜯어보고 어떤 흐름제어와 함수들이 사용되었는 지를 확인해보면 좋다고 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Prometheus는 웬만한 서비스들이 사용하는 모니터링 툴이자, 차트도 잘 짜여져있어 참고해보면 좋다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Prometheus Helm chart&lt;/h3&gt;
&lt;pre id=&quot;code_1688903389097&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Prometheus helm root path

Chart.yaml
Chart.lock
README.md
values.yaml
templates
  - NOTES.txt
  - _helpers.tpl
  - alertmanager
  - node-exporter
  - server
  - pushgateway
  ...&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Chart dependency&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Helm 차트에는 여러 차트가 종속되어 있어 단순히 helm install을 통해서 리소스를 생성할 수 없다. Chart.yaml을 살펴보면 아래와 같이 dependencies 섹터에 alertmanager, kube-state-metrics... 등의 차트들이 나열된 것을 볼 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1688903850983&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: v2
name: prometheus
appVersion: v2.45.0
version: 23.0.0
kubeVersion: &quot;&amp;gt;=1.16.0-0&quot;
description: Prometheus is a monitoring system and time series database.
...
dependencies:
  - name: alertmanager
    version: &quot;0.33.*&quot;
    repository: https://prometheus-community.github.io/helm-charts
    condition: alertmanager.enabled
  - name: kube-state-metrics
    version: &quot;5.8.*&quot;
    repository: https://prometheus-community.github.io/helm-charts
    condition: kube-state-metrics.enabled
  - name: prometheus-node-exporter
    version: &quot;4.18.*&quot;
    repository: https://prometheus-community.github.io/helm-charts
    condition: prometheus-node-exporter.enabled
  - name: prometheus-pushgateway
    version: &quot;2.3.*&quot;
    repository: https://prometheus-community.github.io/helm-charts
    condition: prometheus-pushgateway.enabled
...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 차트의 version과 repository 위치가 입력되는데, 여기서 version의 경우, patch가 *로 입력되어있다. 이는 해당 major와 minor를 만족하는 버전에서 가장 최신의 patch를 설치하도록 한다. 사용 여부는 condition의 true, false로 결정된다. 당연히 values.yaml에서 지정한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1055&quot; data-origin-height=&quot;693&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7MABI/btsmRM0z3uU/CLiqY0j9XknQXtbkkCtJ81/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7MABI/btsmRM0z3uU/CLiqY0j9XknQXtbkkCtJ81/img.png&quot; data-alt=&quot;prometheus/values.yaml&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7MABI/btsmRM0z3uU/CLiqY0j9XknQXtbkkCtJ81/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7MABI%2FbtsmRM0z3uU%2FCLiqY0j9XknQXtbkkCtJ81%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1055&quot; height=&quot;693&quot; data-origin-width=&quot;1055&quot; data-origin-height=&quot;693&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;prometheus/values.yaml&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 prometheus helm chart를 설치하기 위해서는 다음과 같은 순서로 명령어를 진행한다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;helm repo add (prometheus 레포지토리 추가)&lt;/li&gt;
&lt;li&gt;helm pull (prometheus 차트 다운로드)&lt;/li&gt;
&lt;li&gt;helm dependency update (종속된 패키지 다운로드)&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;charts 라는 디렉토리와 함께 종속 패키지의 tgz 파일이 생성된다.&lt;/li&gt;
&lt;li&gt;Chart.lock 파일이 생성되어 다운된 종속 패키지의 내용이 담긴다.&lt;/li&gt;
&lt;li&gt;helm dependency list를 통해서 다운된 종속 패키지의 리스트 확인이 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;helm install (prometheus와 종속된 패키지 설치)&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;주요 함수&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1) SplitList&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1688904392712&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;splitList&amp;gt;
 {{- $url := splitList &quot;/&quot; &quot;helm.sh/docs/helm&quot; }}
 host {{ first $url }}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;url 배열에 [&quot;helm.sh&quot; &quot;docs&quot; &quot;helm&quot;] 이 추가되고 host 변수에 $url의 첫번째 값인 helm.sh가 저장된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2) RegexMatch&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1688904530343&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;regexMatch&amp;gt;
 regexmatch: {{ regexMatch &quot;.*\\.ya?ml$&quot; &quot;config.yaml&quot; }}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;regex는 regular expression의 줄임말로, 첫번째 인자값과 두번째 인자값과 매치가 되면 True, 아니면 False를 출력한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3) Index&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1688904653443&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;index&amp;gt;
 colors: &quot;{{ index.Values.colors 0 }}&quot;
 
 # values.yaml
 # colors:
 #   - &quot;blue&quot;
 #   - &quot;red&quot;
 #   - &quot;green&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Values.yaml을 통해 colors가 위와 같이 선언되어 있다면 index함수에서는 가장 첫번째 값인 blue가 출력된다.&lt;/p&gt;
&lt;pre id=&quot;code_1688904805793&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;path: /{{ index.Values &quot;server&quot; &quot;path&quot; &quot;prefix&quot; }}/ready

# values.yaml
# server:
#   path:
#     prefix: &quot;prom&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;index 함수는 위와 같이 직접 경로를 지정해서 해당 값을 출력할 수 도 있다. 위 함수의 결과는 'prom/ready'가 출력된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4) semver&lt;/p&gt;
&lt;pre id=&quot;code_1688904910624&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{{- $version := semver &quot;1.2.3-alpha.1+123&quot; -}}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시멘틱 버전을 관리하기 위한 함수로, 위와 같은 입력은 아래와 같이 변수로 지정되어 사용할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1688904981753&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$version.Major = 1
$version.Minor = 2
$version.Patch = 3
$version.Prerelease = alpha.1
$version.Metadata = 123
$version.Original = 1.2.3-alpha.1+123&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;yaml 파일 살펴보기&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;[cm.yaml]&lt;/h4&gt;
&lt;pre id=&quot;code_1688905274261&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{{- if (empty .Values.server.configMapOverrideName) -}}
apiVersion: v1
kind: ConfigMap
metadata:
  labels:
    {{- include &quot;prometheus.server.labels&quot; . | nindent 4 }}
    {{- with .Values.server.extraConfigmapLabels }}
    {{- toYaml . | nindent 4 }}
    {{- end }}
  name: {{ template &quot;prometheus.server.fullname&quot; . }}
  namespace: {{ include &quot;prometheus.namespace&quot; . }}
data:
  allow-snippet-annotations: &quot;false&quot;
{{- $root := . -}}
{{- range $key, $value := .Values.ruleFiles }}
  {{ $key }}: {{- toYaml $value | indent 2 }}
{{- end }}
{{- range $key, $value := .Values.serverFiles }}
  {{ $key }}: |
{{- if eq $key &quot;prometheus.yml&quot; }}
    global:
{{ $root.Values.server.global | toYaml | trimSuffix &quot;\n&quot; | indent 6 }}
{{- if $root.Values.server.remoteWrite }}
    remote_write:
{{ $root.Values.server.remoteWrite | toYaml | indent 4 }}
{{- end }}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;{{-&amp;nbsp;if&amp;nbsp;(empty&amp;nbsp;.Values.server.configMapOverrideName)&amp;nbsp;-}}&lt;/b&gt;&lt;br /&gt;- cm.yaml을 보면 처음 Values.yaml 에 server.configMapOverrideName이 입력되지 않았다면 true가 출력되어 cm.yaml의 내용이 적용된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;{{- include &quot;prometheus.server.labels&quot; . | nindent 4 }}&lt;/b&gt;&lt;br /&gt;- metadata.labels에 include를 통해서 _helpers.tpl의 prometheus.server.labels의 내용들을 가져온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;{{-&amp;nbsp;range&amp;nbsp;$key,&amp;nbsp;$value&amp;nbsp;:=&amp;nbsp;.Values.ruleFiles&amp;nbsp;}} &lt;/b&gt;&lt;br /&gt;&lt;b&gt;&amp;nbsp;&amp;nbsp;{{&amp;nbsp;$key&amp;nbsp;}}:&amp;nbsp;{{-&amp;nbsp;toYaml&amp;nbsp;$value&amp;nbsp;|&amp;nbsp;indent&amp;nbsp;2&amp;nbsp;}} &lt;/b&gt;&lt;br /&gt;&lt;b&gt;{{-&amp;nbsp;end&amp;nbsp;}}&lt;br /&gt;&lt;/b&gt;- Values.ruleFiles의 key와 value를 불러오는 것으로 아래와 같이 ruleFiles에 선언된 내용이 입력되는데 아쉽게도 선언되어 있진 않다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1061&quot; data-origin-height=&quot;398&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PFGpu/btsmQpkMLfm/J54w4rNes52Ym2ZP0RW3M1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PFGpu/btsmQpkMLfm/J54w4rNes52Ym2ZP0RW3M1/img.png&quot; data-alt=&quot;prometheus/values.yaml&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PFGpu/btsmQpkMLfm/J54w4rNes52Ym2ZP0RW3M1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPFGpu%2FbtsmQpkMLfm%2FJ54w4rNes52Ym2ZP0RW3M1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1061&quot; height=&quot;398&quot; data-origin-width=&quot;1061&quot; data-origin-height=&quot;398&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;prometheus/values.yaml&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;[ingress.yaml]&lt;/h4&gt;
&lt;pre id=&quot;code_1688909000330&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{{- if .Values.server.ingress.enabled -}}
{{- $ingressApiIsStable := eq (include &quot;ingress.isStable&quot; .) &quot;true&quot; -}}
{{- $ingressSupportsIngressClassName := eq (include &quot;ingress.supportsIngressClassName&quot; .) &quot;true&quot; -}}
{{- $ingressSupportsPathType := eq (include &quot;ingress.supportsPathType&quot; .) &quot;true&quot; -}}
{{- $releaseName := .Release.Name -}}
{{- $serviceName := include &quot;prometheus.server.fullname&quot; . }}
{{- $servicePort := .Values.server.service.servicePort -}}
{{- $ingressPath := .Values.server.ingress.path -}}
{{- $ingressPathType := .Values.server.ingress.pathType -}}
{{- $extraPaths := .Values.server.ingress.extraPaths -}}
apiVersion: {{ template &quot;ingress.apiVersion&quot; . }}
kind: Ingress
metadata:
{{- if .Values.server.ingress.annotations }}
  annotations:
{{ toYaml .Values.server.ingress.annotations | indent 4 }}
...

spec:
  {{- if and $ingressSupportsIngressClassName .Values.server.ingress.ingressClassName }}
  ingressClassName: {{ .Values.server.ingress.ingressClassName }}
  {{- end }}
  rules:
  {{- range .Values.server.ingress.hosts }}
    {{- $url := splitList &quot;/&quot; . }}
    - host: {{ first $url }}
      http:
        paths:
        
 ...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;{{-&amp;nbsp;$releaseName&amp;nbsp;:=&amp;nbsp;.Release.Name&amp;nbsp;-}} &lt;/b&gt;&lt;br /&gt;&lt;b&gt;{{-&amp;nbsp;$serviceName&amp;nbsp;:=&amp;nbsp;include&amp;nbsp;&quot;prometheus.server.fullname&quot;&amp;nbsp;.&amp;nbsp;}} &lt;/b&gt;&lt;br /&gt;&lt;b&gt;{{-&amp;nbsp;$servicePort&amp;nbsp;:=&amp;nbsp;.Values.server.service.servicePort&amp;nbsp;-}} &lt;/b&gt;&lt;br /&gt;&lt;b&gt;{{-&amp;nbsp;$ingressPath&amp;nbsp;:=&amp;nbsp;.Values.server.ingress.path&amp;nbsp;-}}&lt;br /&gt;&lt;/b&gt;- Release.Name, _helpers.tpl에 선언된 server.fullname 그리고 values.yaml에 선언된 server.service.servicePort와 server.ingress.path가 각각 입된다.&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp; {{- range .Values.server.ingress.hosts }} &lt;/b&gt;&lt;br /&gt;&lt;b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{{-&amp;nbsp;$url&amp;nbsp;:=&amp;nbsp;splitList&amp;nbsp;&quot;/&quot;&amp;nbsp;.&amp;nbsp;}} &lt;/b&gt;&lt;br /&gt;&lt;b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;host:&amp;nbsp;{{&amp;nbsp;first&amp;nbsp;$url&amp;nbsp;}} &lt;/b&gt;&lt;br /&gt;&lt;b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;http: &lt;/b&gt;&lt;br /&gt;&lt;b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;paths:&lt;/b&gt; &lt;br /&gt;&amp;nbsp; -&amp;nbsp; values.yaml에서 server.ingress.hosts 값의 전체 주소가 '/'를 기준으로 나누어져 url 변수에 배열로 할당된다. 만약 hosts의 값이 'prometheus.com/login' 이라고 한다면 first에 할당된 변수는 prometheus.com이 되기 때문에 host에 선언된다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;[sts.yaml]&lt;/h4&gt;
&lt;pre id=&quot;code_1688909499178&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;...
{{- if semverCompare &quot;&amp;gt;=1.13-0&quot; .Capabilities.KubeVersion.GitVersion }}
      {{- if or (.Values.server.enableServiceLinks) (eq (.Values.server.enableServiceLinks | toString) &quot;&amp;lt;nil&amp;gt;&quot;) }}
      enableServiceLinks: true
      {{- else }}
      enableServiceLinks: false
      {{- end }}
{{- end }}
...
          {{- range .Values.configmapReload.prometheus.extraVolumeDirs }}
            - --watched-dir={{ . }}
          {{- end }}
...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;{{-&amp;nbsp;if&amp;nbsp;semverCompare&amp;nbsp;&quot;&amp;gt;=1.13-0&quot;&amp;nbsp;.Capabilities.KubeVersion.GitVersion&amp;nbsp;}}&lt;/b&gt;&lt;br /&gt;- 1.13 버전보다 뒤의 값이 큰지를 판단하는 것으로 kubeversion에서 gitversion이 크다면 true가 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;{{- if or (.Values.server.enableServiceLinks) (eq (.Values.server.enableServiceLinks | toString) &quot;&amp;lt;nil&amp;gt;&quot;) }}&lt;/b&gt; &lt;br /&gt;&amp;nbsp;- values.yaml에서 enbaleServiceLinks가 true면 or 조건이기 때문에 뒤이은 조건에 상관없이 if문은 true가 된다. 이 조건은enableServiceLinks의 값이 null인지 확인하는 것으로 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;{{- range .Values.configmapReload.prometheus.extraVolumeDirs }} &lt;/b&gt;&lt;br /&gt;&lt;b&gt;&amp;nbsp; - --watched-dir={{ . }} &lt;/b&gt;&lt;br /&gt;&lt;b&gt;{{- end }}&lt;/b&gt;&lt;br /&gt;- watched-dir={{ . }}는 configmapReload.prometheus.extraVolumeDirs의 watched-dir key에 입력되는 모든 값을 말한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DevOps/Opensource</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/375</guid>
      <comments>https://tigercoin.tistory.com/375#entry375comment</comments>
      <pubDate>Sun, 9 Jul 2023 21:16:51 +0900</pubDate>
    </item>
    <item>
      <title>Istio 서비스메시에 대해서 알아보자!</title>
      <link>https://tigercoin.tistory.com/374</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;Istio?&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;Istio는 오픈소스 서비스 메쉬로, 분리된 어플리케이션을 투명하게 계층화할 수 있다. 현재 쿠버네티스의 네트워크 구성에 가장 많이 사용되고 있는 오픈소스기도 하다. Istio는 쿠버네티스 네트워크의 복잡성을 줄이고, 분산 네트워크 환경에서 여러 어플리케이션들의 연결을 쉽게 설정할 수 있게 지원한다. Istio를 대표하는 3가지의 컨셉은 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Traffic management&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-indent-level=&quot;2&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Sidecar 패턴(Pod 내에 Envoy proxy가 sidecar로 존재)을 이용하여 application 코드의 변경없이 작업자가 VirtualService, DestinationRule이라는 Custom Resource로 손쉽게 원하는 서비스로 트래픽 전송이 가능&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;k8s로 Canary 배포를 하기 위해선 직접 replica 개수를 조정해야 했으나, Istio VirtualService의 Weight와 subset을 통해 이 과정이 단순해짐&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Envoy로 Header와 Path의 L7 라우팅이 매우 간단해짐&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;letter-spacing: 0px; color: #000000;&quot;&gt;Observability&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-indent-level=&quot;2&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;log, metric, trace를 Istio를 통해 모두 수집 가능 &amp;rarr; Observability&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Envoy를 통해 Observability 구현&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Security capabilities&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-indent-level=&quot;2&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;MSA 구조로 인한 Man in middle 공격과 manifest 노출의 리스크를 mTLS로 통신 레이어 보안 향상시킴&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Policy를 활용하여 서비스간의 통신의 권한을 코드화시켜 관리가 가능&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;어플리케이션 코드의 변경없이도 클러스터의 보안을 강화시킴&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;Istio를 사용하면 서비스의 코드를 변경하지않고 로드밸런싱과 service to service 인증 및 모니터링을 할 수 있다. 여기서 Istio의 컨트롤타워인 control plane은 아래와 같은 기능들을 가진다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-indent-level=&quot;1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;TLS 암호화와 함께 서비스간 통신의 보안과 인증&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;HTTP, gRPC, Websocket, TCP의 로드밸런싱&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;다양한 라우팅 룰과 재시도, 결함 제거 및 장애 극복과 같은 트래픽 동작을 세부적으로 제어&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;플러그형 정책 계층과 액세스 제어와 속도 제한 등 을 지원하는 API&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;ingress, egress를 포함한 클러스터 내의 자동 메트릭, 로그, 추적 기능&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;control plane은 kubernetes 상에서 작동되고, 다른 클러스터로의 확장을 위해 여러 어플리케이션을 추가할 수 있다. control plane은 kubernetes namespace 'istio-system'에 속한 파드들을 의미하기도 한다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;1229&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Data plane, Control plane, Envoy&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1266&quot; data-origin-height=&quot;831&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8lqP9/btsmOAsCCBh/dsIgd0ExQkXfIZFS1m8Sx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8lqP9/btsmOAsCCBh/dsIgd0ExQkXfIZFS1m8Sx1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8lqP9/btsmOAsCCBh/dsIgd0ExQkXfIZFS1m8Sx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8lqP9%2FbtsmOAsCCBh%2FdsIgd0ExQkXfIZFS1m8Sx1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1266&quot; height=&quot;831&quot; data-origin-width=&quot;1266&quot; data-origin-height=&quot;831&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Data Plane&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Data Plane은 서비스간의 통신으로 실제 트래픽을 받아 처리한다. 서비스의 사이드카 형태로 구성된 프록시들을 말하며 Envoy가 사이드카 프록시로 활용된다. Data plane은 Control plane에 의해서 컨트롤된다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Control Plane&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Data Plane을 관리하는 컨트롤타워다. kubernetes cluster에서 istio-system 네임스페이스로 구성된다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Envoy&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Istio 외에도 Consule, App mesh, Kong Mesh 등의 서비스메쉬가 Envoy로 구현되어 있다. Envoy는 경량화된 L7 Proxy로 HTTP, TCP, gRPC 등의 프로토콜을 지원한다. Retry, Circuit Breaker, Timeout 등 다양한 기능을 수행할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;2453&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;How Components Interact With Each Other&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;a102681a-5e29-4503-a413-fb2ff4d271b7.png&quot; data-origin-width=&quot;2960&quot; data-origin-height=&quot;1428&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dnSM8W/btsmQQt289w/QZIswBaE48p5N3LvzGY8D0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dnSM8W/btsmQQt289w/QZIswBaE48p5N3LvzGY8D0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dnSM8W/btsmQQt289w/QZIswBaE48p5N3LvzGY8D0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdnSM8W%2FbtsmQQt289w%2FQZIswBaE48p5N3LvzGY8D0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2960&quot; height=&quot;1428&quot; data-filename=&quot;a102681a-5e29-4503-a413-fb2ff4d271b7.png&quot; data-origin-width=&quot;2960&quot; data-origin-height=&quot;1428&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;위 이미지에서 왼편에 APIs Content를 시작으로 Ingress를 거쳐 두 개의 마이크로 서비스가 있고 오른편에 Egress로 이어진다. Service A와 Service B는 컨테이너에서 동작하는 마이크로서비스고 그들은 Envoy Proxy로 통신하는 것을 볼 수 있다.(Service A는 서비스의 프론트엔드고 Service B는 백엔드)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;2725&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Istio는 Envoy가 배포되면 Envoy proxy를 Pod에 주입한다. 트래픽 패킷은 서비스 메시를 통해서 다음과 같은 단계를 거치게된다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;Ingress&quot; style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;2807&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Ingress&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;2816&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;트래픽은 Ingress 리소스를 통해서 서비스 매시에 도착한다. Ingress는 Pilot에 의해서 구성된 하나 이상의 Envoy 프록시의 은행이다. Pilot은 쿠버네티스 서비스 엔드포인트를 사용해서 Ingress proxy를 구성하면 이 Ingress 프록시는 백엔드를 인식하게된다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;2978&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그러므로 Ingress는 패킷을 수신하면 패킷을 보낼 위치를 인식한다. health check와 로드밸런싱을 수행하고 패킷과 할당량 및 트래픽 밸런싱과 같은 메트릭을 기반하여 메시지를 보내는 지능적인 결정을 내린다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;Service-A&quot; style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;3100&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Service A&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;3111&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Ingress가 첫 파드에 라우트하면 컨테이너 대신해서 Service A의 프록시에 도달한다. 사이드카가 같은 파드에 존재하기 떄문에 그들은 같은 네트워크 네임스페이스를 공유하고 같은 노드에 위치한다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;3226&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;두 컨테이너는 같은 IP 주소와 같은 IP table rule을 공유하게되어, 프록시는 완전한 파드 컨트롤이 가능해진다. 여기서 파드에 전송되는 모든 트래픽을 처리하게된다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;3324&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Envoy 프록시는 Citadel과 상호작용하여 만약 어떤 정책이 강화되는지를 이해한다. 그리고 트래픽을 암호화해야하는지, 백엔드 파드와 TLS를 맺어야하는지 확인한다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;Service-B&quot; style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;3420&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Service B&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;3431&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Service A가 암호화된 패킷을 Service B에 보내면, 패킷의 발신자의 신원증명과 함께 TLS 핸드쉐이크를 수행한다. 신뢰관계가 맺어지면 패킷을 수신하고 Service B 컨테이너로 향한다. 이후 Egress로 이어진다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;Egress&quot; style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;3561&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Egress&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;3569&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;모든 트래픽은 메시를 통해서 나오며, Egress 리소스를 사용한다. Egress 레이어는 어떤 트래픽이 메시를 통해 나오는지를 정의하고 Pliot을 사용하며, Ingress 레이어의 구성과 비슷하다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;3683&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Egress 리소스를 사용함으로써 제한된 아웃바운드 트래픽의 정책을 쓸 수 있고, 요구된 서비스만이 패킷을 매쉬 밖으로 보내는 것이 가능해진다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>DevOps/Kubernetes</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/374</guid>
      <comments>https://tigercoin.tistory.com/374#entry374comment</comments>
      <pubDate>Fri, 7 Jul 2023 18:37:16 +0900</pubDate>
    </item>
    <item>
      <title>Karpenter의 Provisioner</title>
      <link>https://tigercoin.tistory.com/372</link>
      <description>&lt;h3 id=&quot;Provisioner&quot; style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;1&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Provisioner&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;프로비저너는 카펜터를 시작할 때 기본적으로 사용되는 노드와 파드의 구성값, 제약 조건을 설정한다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-indent-level=&quot;1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;pod의 리밋인 taint를 정의&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;node의 zone, instance type, computer architecture 정의&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;node expiration 정의&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;spec.requirements&quot; style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;1262&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;spec.requirements&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1688281253063&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  # Requirements that constrain the parameters of provisioned nodes.
  # These requirements are combined with pod.spec.affinity.nodeAffinity rules.
  # Operators { In, NotIn } are supported to enable including or excluding values
  requirements:
    - key: &quot;karpenter.k8s.aws/instance-category&quot;
      operator: In
      values: [&quot;c&quot;, &quot;m&quot;, &quot;r&quot;]
    - key: &quot;karpenter.k8s.aws/instance-cpu&quot;
      operator: In
      values: [&quot;4&quot;, &quot;8&quot;, &quot;16&quot;, &quot;32&quot;]
    - key: &quot;karpenter.k8s.aws/instance-hypervisor&quot;
      operator: In
      values: [&quot;nitro&quot;]
    - key: karpenter.k8s.aws/instance-generation
      operator: Gt
      values: [&quot;2&quot;]
    - key: &quot;topology.kubernetes.io/zone&quot;
      operator: In
      values: [&quot;us-west-2a&quot;, &quot;us-west-2b&quot;]
    - key: &quot;kubernetes.io/arch&quot;
      operator: In
      values: [&quot;arm64&quot;, &quot;amd64&quot;]
    - key: &quot;karpenter.sh/capacity-type&quot; # If not included, the webhook for the AWS cloud provider will default to on-demand
      operator: In
      values: [&quot;spot&quot;, &quot;on-demand&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; text-align: start;&quot;&gt;requirements는 Provisioner API 섹션이다. 인스턴스의 타입과 CPU, region, architecture 등 을 정의한다. 사실 architecture를 제외하면 크게 설정할 필요가 없다. karpenter가 비용효율적으로 Node의 consolidate와 Node 생성과 삭제를 진행하기 때문.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;만약 Capacity type이 spot이라면 남는 resource의 instance type이 있어야 가능하기 때문에 instance category를 최대한 많이 설정할 필요가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;spec.kubeletConfiguration&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1688282045088&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;spec:
  ...
  kubeletConfiguration:
    clusterDNS: [&quot;10.0.1.100&quot;]
    containerRuntime: containerd
    systemReserved:
      cpu: 100m
      memory: 100Mi
      ephemeral-storage: 1Gi
    kubeReserved:
      cpu: 200m
      memory: 100Mi
      ephemeral-storage: 3Gi
    evictionHard:
      memory.available: 5%
      nodefs.available: 10%
      nodefs.inodesFree: 10%
    evictionSoft:
      memory.available: 500Mi
      nodefs.available: 15%
      nodefs.inodesFree: 15%
    evictionSoftGracePeriod:
      memory.available: 1m
      nodefs.available: 1m30s
      nodefs.inodesFree: 2m
    evictionMaxPodGracePeriod: 60
    imageGCHighThresholdPercent: 85
    imageGCLowThresholdPercent: 80
    cpuCFSQuota: true
    podsPerCore: 2
    maxPods: 20&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;spec.requirements&quot; style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;1262&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;kubelet은 각 노드에서 실행되는 Node agent로 Node에 Pod를 직접 생성, 삭제, 관리하는 역할을 한다. karpenter는 Provisioner를 통해서 이 kubelet에 관련된 argumentes를 설정할 수 있다.&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;b&gt;Reserved Resources :&lt;/b&gt; 카펜터는 kube reserve resource 요청을 사용자를 대신하여 자동으로 구성한다. 이 요청은 노드를 구성하고 포드에 대한 스케쥴링에 사용된다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Eviction Thresholds :&lt;/b&gt; kubelet은 evction thresholds를 지원하는데, 노드에 충분한 리소스가 유지될 때 시스템 데몬과 다른 시스템이 안정적으로 작동하기 위해서 pod를 제거한다. 여기서 kubelet은 hard, soft evction 두 가지 방식으로 eviction을 실행한다.hard 방식.spec.kubeletConfiguration.evictionHard은 조건에 부합하면 즉시 evict하는 것이고, soft 방식.spec.kubeletConfiguration.evictionSoft은 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;840&quot; data-origin-height=&quot;381&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vPVMO/btsmd0RkL3T/bGll6vyvKnMK9bwigIhkb0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vPVMO/btsmd0RkL3T/bGll6vyvKnMK9bwigIhkb0/img.png&quot; data-alt=&quot;eviction 설정에 대한 내&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vPVMO/btsmd0RkL3T/bGll6vyvKnMK9bwigIhkb0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvPVMO%2Fbtsmd0RkL3T%2FbGll6vyvKnMK9bwigIhkb0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;840&quot; height=&quot;381&quot; data-origin-width=&quot;840&quot; data-origin-height=&quot;381&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;eviction 설정에 대한 내&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;spec.limits.resources&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;imits.resources는 리소스의 최대량을 설정한다. 이 리밋을 초과하면 노드는 제거되도록 하여 불필요한 리소스 낭비를 제한한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1688282342635&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: karpenter.sh/v1alpha5
kind: Provisioner
metadata:
  name: default
spec:
  requirements:
    - key: karpenter.sh/capacity-type
      operator: In
      values: [&quot;spot&quot;]
  limits:
    resources:
      cpu: 1000
      memory: 1000Gi
      nvidia.com/gpu: 2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;그러나 카펜터으 프로비저닝은 병렬적으로 진행되기 때문에 급진적인 스케일아웃의 경우, 리밋을 초과하는 overrun이 발생할 수 있다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;spec.providerRef&quot; style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;4637&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;spec.providerRef&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;4655&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;미리 선언된 Nodetemplate을 참조&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;spec.consolidation&quot; style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;4680&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;spec.consolidation&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;4700&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;카펜터는 효율적인 노드 관리를 위해 불필요한 노드는 deprovisioning하여 인스턴스를 통합한다. 여기서 사용되는 값은 spec.TTLSecondsAfterEmpty, spec.ttlSecondsUntilExpired, spec.consolidation.enabled 이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Use-case 1 / taints-tolerations&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1688282414524&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: karpenter.sh/v1alpha5
kind: Provisioner
metadata:
  name: gpu
spec:
  consolidation:
    enabled: true
  requirements:
  - key: node.kubernetes.io/instance-type
    operator: In
    values: [&quot;p3.8xlarge&quot;, &quot;p3.16xlarge&quot;]
  taints:
  - key: nvidia.com/gpu
    value: &quot;true&quot;
    effect: NoSchedule&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;위는 &lt;a style=&quot;color: #000000;&quot; href=&quot;http://nvidia.com/gpu&quot; data-testid=&quot;link-with-safety&quot; data-renderer-mark=&quot;true&quot;&gt;nvidia.com/gpu&lt;/a&gt; 키의 taint가 설정된 provisioner이다. taint가 설정되었기 때문에 toleration이 설정된 pod만 해당 노드에서 생성될 수 있다. consolidation이 enable되었기 때문에 인스턴스의 통합이 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;5351&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;아래는 &lt;a style=&quot;color: #000000;&quot; href=&quot;http://nvidia.com/gpu%EA%B0%80&quot; data-testid=&quot;link-with-safety&quot; data-renderer-mark=&quot;true&quot;&gt;nvidia.com/gpu&lt;/a&gt; toleration이 설정된 pod yaml이다. 이 pod는 위 node에서 생성이 가능하다. 왜? 오염에 대한 내성(tolerance)가 있어서.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1688282431539&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: v1
kind: Pod
metadata:
  name: mygpupod
spec:
  containers:
  - name: gpuapp
    resources:
      requests:
        nvidia.com/gpu: 1
      limits:
        nvidia.com/gpu: 1
    image: mygpucontainer
  tolerations:
  - key: &quot;nvidia.com/gpu&quot;
    operator: &quot;Exists&quot;
    effect: &quot;NoSchedule&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;operator 옵션&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-indent-level=&quot;1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Equal : 키, 값, 효과가 모두 같은지 확인.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Exists : 값을 확인하지 않으며, 필요하지 않음. key값이 설정되어 있지않으면, 어떤 taint가 걸려있어도 무시하고 스케쥴링되어 포드 실행함. key값이 하나라도 존재하면 해당 키의 taint가 적용된 노드에만 실행됨&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;5934&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;effect 옵션&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-indent-level=&quot;1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;NoSchedule : toleration이 없으면 포드가 스케쥴되어 실행되지 않음. 기존에 실행되던 포드에는 적용되지 않음.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;PreferNoSchedule: toleration이 없으면 포드를 스케쥴링 하지 않으려고 하긴 하지만 필수는 아님. 클러스터내의 자원이 &amp;nbsp;부족하거나 하면 taint가 걸려 있는 노드에서 포드가 스케쥴링 될 수 있음.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;NoExecute : 새로운 포드도 toleration이 없으면 실행되지 않게 하고, 기존에 있던 포드역시 taint에 맞는 toleration설정이 없으면 종료.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>DevOps/Kubernetes</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/372</guid>
      <comments>https://tigercoin.tistory.com/372#entry372comment</comments>
      <pubDate>Sun, 2 Jul 2023 16:21:48 +0900</pubDate>
    </item>
    <item>
      <title>EKS 스케일링의 강자 Karpenter</title>
      <link>https://tigercoin.tistory.com/371</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;EKS에는 기본적으로 Cluster Autoscaler가 있다. Karpenter가 나오기 전에 유일하게 노드를 확장해주는 방식으로, 여러 프로바이더를 지원한다.그러나 CA는 하나의 자원을 두 주체(ASG, EKS)가 각자의 방식으로 관리하기 때문에 관리 정보에 싱크가 맞지않아 여러 문제가 발생한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대표적으로 EKS에서 노드를 삭제해도 인스턴스(노드)가 삭제되지 않는 현상이 있다. 또한, CA의 노드 스케일인 옵션이 적고 느리다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;CA의 문제점들&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;AWS Auto scaling에만 의존하여, 직접적인 노드 삭제와 생성이 안됨&lt;/li&gt;
&lt;li&gt;EKS에서 노드 삭제해도 인스턴스가 삭제되지 않음&lt;/li&gt;
&lt;li&gt;노드 축소 시, 특정 노드 축소가 어려움&lt;/li&gt;
&lt;li&gt;Pulling 방식이기 때문에 API 제한이 걸릴 수 있음&lt;/li&gt;
&lt;li&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;1541&quot; data-origin-height=&quot;422&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/utB27/btslAmbjnJG/nxBA1Z2KwWhJJPxjog7kPK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/utB27/btslAmbjnJG/nxBA1Z2KwWhJJPxjog7kPK/img.png&quot; data-alt=&quot;Karpenter vs Cluster Autoscaler&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/utB27/btslAmbjnJG/nxBA1Z2KwWhJJPxjog7kPK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FutB27%2FbtslAmbjnJG%2FnxBA1Z2KwWhJJPxjog7kPK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1541&quot; height=&quot;422&quot; data-origin-width=&quot;1541&quot; data-origin-height=&quot;422&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Karpenter vs Cluster Autoscaler&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Karpenter&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;karpenter는 이런 CA의 문제들을 해결할 수 있다. 비교적 출시된지 얼마 안되었기 때문에 자료가 없지만, 퍼포먼스는 매우 뛰어나다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1384&quot; data-origin-height=&quot;835&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/by4O9y/btslCwKZcYy/qOEsCKxTSLBHBmYp0KjZp1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/by4O9y/btslCwKZcYy/qOEsCKxTSLBHBmYp0KjZp1/img.png&quot; data-alt=&quot;https://www.youtube.com/watch?v=FPlCVVrCD64&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/by4O9y/btslCwKZcYy/qOEsCKxTSLBHBmYp0KjZp1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fby4O9y%2FbtslCwKZcYy%2FqOEsCKxTSLBHBmYp0KjZp1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1384&quot; height=&quot;835&quot; data-origin-width=&quot;1384&quot; data-origin-height=&quot;835&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.youtube.com/watch?v=FPlCVVrCD64&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Karpenter는 pod 스케쥴링 이벤트가 pub-sub 방식이기 때문에 API 영향이 없으며, 바로 대응하기 때문에 레이턴시가 있는 Pulling보다 속도가 빠르다. 스케쥴링 안된 Pod를 발견하면 바로 노드를 생성할 수 있고,&amp;nbsp; 비어있는 노드는 발견하면 즉각 제거한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Kubernetes 커스텀 리소스기 때문에 ArgoCD로 배포가 가능하며, Yaml에 선언된 다양한 Provisioner를 활용 가능하다.&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Provisioner&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로비저널은 노드와 노드를 통해 실행되는 파드의 제약조건을 의미한다. 하나의 Karpenter에는 하나 이상의 프로비저너가 구성되어야하며, 구성된 프로비저너는 karpenter에 의해서 반복된다. 가능한 설정은 아래와 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;karpenter가 만드는 노드에서 실행되는 파드를 taint 정의로 제한&lt;/li&gt;
&lt;li&gt;노드 생성을 특정 영역, 인스턴스 유형으로 제한&lt;/li&gt;
&lt;li&gt;초기 taint 정의&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(아래는 provisioner yaml 템플릿 파일)&lt;/p&gt;
&lt;pre id=&quot;code_1687871821903&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: karpenter.sh/v1alpha5
kind: Provisioner
metadata:
  name: default
spec:
  # References cloud provider-specific custom resource, see your cloud provider specific documentation
  providerRef:
    name: default

  # Provisioned nodes will have these taints
  # Taints may prevent pods from scheduling if they are not tolerated by the pod.
  taints:
    - key: example.com/special-taint
      effect: NoSchedule

  # Provisioned nodes will have these taints, but pods do not need to tolerate these taints to be provisioned by this
  # provisioner. These taints are expected to be temporary and some other entity (e.g. a DaemonSet) is responsible for
  # removing the taint after it has finished initializing the node.
  startupTaints:
    - key: example.com/another-taint
      effect: NoSchedule

  # Labels are arbitrary key-values that are applied to all nodes
  labels:
    billing-team: my-team

  # Annotations are arbitrary key-values that are applied to all nodes
  annotations:
    example.com/owner: &quot;my-team&quot;

  # Requirements that constrain the parameters of provisioned nodes.
  # These requirements are combined with pod.spec.affinity.nodeAffinity rules.
  # Operators { In, NotIn } are supported to enable including or excluding values
  requirements:
    - key: &quot;karpenter.k8s.aws/instance-category&quot;
      operator: In
      values: [&quot;c&quot;, &quot;m&quot;, &quot;r&quot;]
    - key: &quot;karpenter.k8s.aws/instance-cpu&quot;
      operator: In
      values: [&quot;4&quot;, &quot;8&quot;, &quot;16&quot;, &quot;32&quot;]
    - key: &quot;karpenter.k8s.aws/instance-hypervisor&quot;
      operator: In
      values: [&quot;nitro&quot;]
    - key: karpenter.k8s.aws/instance-generation
      operator: Gt
      values: [&quot;2&quot;]
    - key: &quot;topology.kubernetes.io/zone&quot;
      operator: In
      values: [&quot;us-west-2a&quot;, &quot;us-west-2b&quot;]
    - key: &quot;kubernetes.io/arch&quot;
      operator: In
      values: [&quot;arm64&quot;, &quot;amd64&quot;]
    - key: &quot;karpenter.sh/capacity-type&quot; # If not included, the webhook for the AWS cloud provider will default to on-demand
      operator: In
      values: [&quot;spot&quot;, &quot;on-demand&quot;]

  # Karpenter provides the ability to specify a few additional Kubelet args.
  # These are all optional and provide support for additional customization and use cases.
  kubeletConfiguration:
    clusterDNS: [&quot;10.0.1.100&quot;]
    containerRuntime: containerd
    systemReserved:
      cpu: 100m
      memory: 100Mi
      ephemeral-storage: 1Gi
    kubeReserved:
      cpu: 200m
      memory: 100Mi
      ephemeral-storage: 3Gi
    evictionHard:
      memory.available: 5%
      nodefs.available: 10%
      nodefs.inodesFree: 10%
    evictionSoft:
      memory.available: 500Mi
      nodefs.available: 15%
      nodefs.inodesFree: 15%
    evictionSoftGracePeriod:
      memory.available: 1m
      nodefs.available: 1m30s
      nodefs.inodesFree: 2m
    evictionMaxPodGracePeriod: 60
    imageGCHighThresholdPercent: 85
    imageGCLowThresholdPercent: 80
    cpuCFSQuota: true
    podsPerCore: 2
    maxPods: 20


  # Resource limits constrain the total size of the cluster.
  # Limits prevent Karpenter from creating new instances once the limit is exceeded.
  limits:
    resources:
      cpu: &quot;1000&quot;
      memory: 1000Gi

  # Enables consolidation which attempts to reduce cluster cost by both removing un-needed nodes and down-sizing those
  # that can't be removed.  Mutually exclusive with the ttlSecondsAfterEmpty parameter.
  consolidation:
    enabled: true

  # If omitted, the feature is disabled and nodes will never expire.  If set to less time than it requires for a node
  # to become ready, the node may expire before any pods successfully start.
  ttlSecondsUntilExpired: 2592000 # 30 Days = 60 * 60 * 24 * 30 Seconds;

  # If omitted, the feature is disabled, nodes will never scale down due to low utilization
  ttlSecondsAfterEmpty: 30

  # Priority given to the provisioner when the scheduler considers which provisioner
  # to select. Higher weights indicate higher priority when comparing provisioners.
  # Specifying no weight is equivalent to specifying a weight of 0.
  weight: 10&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고할 만한 설정은 Subnet, Security group, instance type, tag, Storage, AMI가 있다. 여기서 AMI를 설정하지 않는다면 최적화된 AMI를 자동으로 설정해준다고 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1687872755912&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  # Requirements that constrain the parameters of provisioned nodes.
  # These requirements are combined with pod.spec.affinity.nodeAffinity rules.
  # Operators { In, NotIn } are supported to enable including or excluding values
  requirements:
    - key: &quot;karpenter.k8s.aws/instance-category&quot;
      operator: In
      values: [&quot;c&quot;, &quot;m&quot;, &quot;r&quot;]
    - key: &quot;karpenter.k8s.aws/instance-cpu&quot;
      operator: In
      values: [&quot;4&quot;, &quot;8&quot;, &quot;16&quot;, &quot;32&quot;]
    - key: &quot;karpenter.k8s.aws/instance-hypervisor&quot;
      operator: In
      values: [&quot;nitro&quot;]
    - key: karpenter.k8s.aws/instance-generation
      operator: Gt
      values: [&quot;2&quot;]
    - key: &quot;topology.kubernetes.io/zone&quot;
      operator: In
      values: [&quot;us-west-2a&quot;, &quot;us-west-2b&quot;]
    - key: &quot;kubernetes.io/arch&quot;
      operator: In
      values: [&quot;arm64&quot;, &quot;amd64&quot;]
    - key: &quot;karpenter.sh/capacity-type&quot; # If not included, the webhook for the AWS cloud provider will default to on-demand
      operator: In
      values: [&quot;spot&quot;, &quot;on-demand&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Instance type은 가드레일 방식으로 여러개 선언이 가능하다. 여기서 values에 spot과 on-demand 두 방식을 동시에 선언하게 되면 spot으로 생성되지만 없으면 on-demand로 설정된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 스팟 선택 시엔 최대한 오래 유지될 수 있거나, 저렴한 인스턴스로 띄우게 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1687872941745&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  # Resource limits constrain the total size of the cluster.
  # Limits prevent Karpenter from creating new instances once the limit is exceeded.
  limits:
    resources:
      cpu: &quot;1000&quot;
      memory: 1000Gi&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;auto-scaling은 단일 인스턴스기 때문에 갯수 기준으로 노드의 limit을 정한다. 반면에 karpenter는 인스턴스 개수 기준이 아닌, CPU와 Memory 기준으로 limit을 정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 CA를 사용할 때는 PV 때문에 단일 서브넷에 노드 그룹을 만든다. 그러나 Karpenter를 사용하면 자동적으로 PV가 존재하는 서브넷에 노드를 생성하기 때문에 안정적으로 운영이 가능하다.&lt;/p&gt;
&lt;pre id=&quot;code_1687873295508&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  # If omitted, the feature is disabled and nodes will never expire.  If set to less time than it requires for a node
  # to become ready, the node may expire before any pods successfully start.
  ttlSecondsUntilExpired: 2592000 # 30 Days = 60 * 60 * 24 * 30 Seconds;

  # If omitted, the feature is disabled, nodes will never scale down due to low utilization
  ttlSecondsAfterEmpty: 30&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가적으로 ttlSecondsUntilExpired와 ttlSecondsAfterEmpty도 노드 디프로비저닝에 아주 유용한 설정값이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ttlSecondsUntilExpired : 노드에 데몬셋을 제외한 모든 Pod이 존재하지 않을 때, 지정된 값 이 후 자동으로 정리됨 (안쓰면 삭제)&lt;/li&gt;
&lt;li&gt;ttlSecondsAfterEmpty : 설정한 기간이 지난 노드는 자동적으로 cordon, drain 처리되어 삭제됨. (주기적인 삭제로 노드 업데이트)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론적으로 Karpenter를 사용하면 노드 최적화를 통한 비용절감에 굉장히 효과적이다. 유휴 노드는 알아서 정리해주고, 비용적으로 계산하여 노드를 합치거나 분리시키기도 한다. 리소스 할당량이 늘어나기 때문에 불필요한 리소스를 낭비하지 않게된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 리소스 할당량이 클 경우, 아무리 스케일링 속도가 빠르다 한들 갑자기 늘어나는 트래픽을 감당하지 못할 수 있다. (Karpenter의 노드와 데몬셋 생성의 스케일링 속도는 대략 1~2분 사이라고함)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럴 땐 오버 프로비저닝을 설정해서 증설용 깡통 Pod를 만들어 여유 공간을 확보해야한다.&amp;nbsp;&lt;/p&gt;</description>
      <category>DevOps/Kubernetes</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/371</guid>
      <comments>https://tigercoin.tistory.com/371#entry371comment</comments>
      <pubDate>Tue, 27 Jun 2023 22:50:32 +0900</pubDate>
    </item>
    <item>
      <title>Github action + Vault + ECR + ArgoCD CICD 파이프라인 구축하기</title>
      <link>https://tigercoin.tistory.com/370</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;우리 팀에서는 실제 여러 클라우드 환경에서 서비스를 운영, 테스트하고 있기 때문에 서비스 별로 각기 다른 config 파일을 관리해야 한다. 처음엔 환경마다 Parameter store를 이용해 파일과 key들을 관리했지만 환경에 접속해서 매번 수정하는 게 아주 번거로웠다. 특히나 github action에서 action을 위한 secret 환경변수도 레포마다 관리하는 것이 쉽지 않았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 흩어져있는 설정 파일 혹은 key값들을 중앙화시킬 필요가 있었고, 쿠버네티스를 사용하기 때문에 모든 환경에서 작동하는 컴포넌트의 배포 상태와 흐름을 파악할 수 있어야 했다. 이 요구사항들을 바탕으로 Vault, ECR, ArgoCD가 사용되는 Github action CICD 파이프라인을 구축하게 되었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;757&quot; data-origin-height=&quot;475&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buiBoa/btsg2kOzbxv/FpOYnEg7DinynyovCGuJMK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buiBoa/btsg2kOzbxv/FpOYnEg7DinynyovCGuJMK/img.png&quot; data-alt=&quot;정말 간단히 구성한 흐름도&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buiBoa/btsg2kOzbxv/FpOYnEg7DinynyovCGuJMK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbuiBoa%2Fbtsg2kOzbxv%2FFpOYnEg7DinynyovCGuJMK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;757&quot; height=&quot;475&quot; data-origin-width=&quot;757&quot; data-origin-height=&quot;475&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;정말 간단히 구성한 흐름도&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EKS에 배포되는 CICD 파이프라인은 위와 같다.&amp;nbsp;github Repo에 특정 branch의 소스코드의 변경이 있으면 트리거가 되어 github action이 시작된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) github action의 workflow에 따라서 도커 이미지가 빌드되고 빌드된 이미지는 ECR에 push 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) github action에서 생성된 이미지의 태그로 argoCD manifest 파일을 수정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) argoCD는 수정된 manifest에 맞춰 EKS 재배포를 진행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4) EKS에서 배포되는 이미지는 ECR를 통해서 pull 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Repo에는 VAULT의 접근 인증을 위한 VAULT_URL, VAULT_TOKEN, VAULT_CA_CERT 를 제외하고는 나머지 config 파일과 token, key 값 모두 vault의 kv 시크릿으로 저장된다.&lt;/p&gt;
&lt;pre id=&quot;code_1684755122401&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# github action workflow

	  - name: Import Secrets
        id: import-secrets
        uses: hashicorp/vault-action@v2
        with:
          url: ${{ secrets.VAULT_URL }}
          token: ${{ secrets.VAULT_TOKEN }}
          caCertificate: ${{ secrets.VAULT_CA_CERT }}
          secrets: |
              eden/kv frontnode | FRONTNODE_CONFIG ;
              eden/kv argoCD | cloneArgoCD ;
              eden/kv aws_access_key | AWS_ACCESS_KEY_ID ;      
              eden/kv aws_secret_access_key | AWS_SECRET_ACCESS_KEY ;
              eden/kv github_token | GITHUB_TOKEN&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 경로를 기준으로 여러 서비스의 민감 데이터를 vault로 중앙화하여 관리하면 매번 repo, 클라우드 환경 별로 번거롭게 관리할 필요가 없어진다.&lt;/p&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;466&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcebSH/btsg1V2qhXS/U9a3QFhcwGU8kUEfb7LPm1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcebSH/btsg1V2qhXS/U9a3QFhcwGU8kUEfb7LPm1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcebSH/btsg1V2qhXS/U9a3QFhcwGU8kUEfb7LPm1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcebSH%2Fbtsg1V2qhXS%2FU9a3QFhcwGU8kUEfb7LPm1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/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;466&quot; data-origin-width=&quot;1424&quot; data-origin-height=&quot;466&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 전체적인 파이프라인 구축을 위해서 배포에 필요한 모든 시크릿을 구성했지만, 앞으로 공통으로 사용할 시크릿, 서비스 별 시크릿을 구분, 특정 시크릿을 관리할 수 있는 User를 추가할 계획이다.&lt;/p&gt;
&lt;pre id=&quot;code_1684755719147&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ env.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ env.AWS_SECRET_ACCESS_KEY }}
          aws-region: ap-northeast-2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS Credential은 환경별로 github action용 User를 생성했다. User의 Role은 단순히 ECR 권한만 부여하기 때문에 OIDC 토큰을 굳이 사용할 필요가 없었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 외에 ECR에 이미지를 push 하거나, argoCD의 manifest를 수정하는 것은 간단하지만 Docker 이미지 빌드를 위해서 Private repository의 패키지를 Import 할 수 있도록 구성하는데 시간이 많이 소요되었다. (사실 코드만 보면 간단...)&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1684756010337&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# install git &amp;amp; credential
RUN apt-get update &amp;amp;&amp;amp; apt-get install git curl
RUN git config --global credential.helper '!f() { echo &quot;username=${GITHUB_TOKEN}&quot;; echo &quot;password=x-oauth-basic&quot;; }; f'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;vault에서 받아온 시크릿 중 GITHUB_TOKEN은 Dockerfile의 gith credential을 위한 것이고, 위 코드를 통해서 이 문제는 해결할 수 있었다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2012&quot; data-origin-height=&quot;1035&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/depTkO/btsg0vi1gFK/lVNdZgbuQfbIAUFHBt2rnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/depTkO/btsg0vi1gFK/lVNdZgbuQfbIAUFHBt2rnk/img.png&quot; data-alt=&quot;성공.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/depTkO/btsg0vi1gFK/lVNdZgbuQfbIAUFHBt2rnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdepTkO%2Fbtsg0vi1gFK%2FlVNdZgbuQfbIAUFHBt2rnk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2012&quot; height=&quot;1035&quot; data-origin-width=&quot;2012&quot; data-origin-height=&quot;1035&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;성공.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>DevOps/Vault</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/370</guid>
      <comments>https://tigercoin.tistory.com/370#entry370comment</comments>
      <pubDate>Mon, 22 May 2023 20:52:57 +0900</pubDate>
    </item>
    <item>
      <title>Vault Secrets Engine 정의와 KV Secrets Engine v2 테스트</title>
      <link>https://tigercoin.tistory.com/369</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Vault의 시크릿 엔진은 data를 암호화하고 저장하고 생성하는, 어떤&amp;nbsp;기능을 하는 유연한 특징을 가진 컴포넌트로 보면된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 시크릿 엔진은 단순히 데이터 저장과 읽기만 제공하지만, 어떤 것은 서비스와 연결되어 동적인 Credential을 생성하기도 하고 인증 역할을 하기도 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;987&quot; data-origin-height=&quot;352&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bx56SV/btsgEMrOOWh/A2xkd4GXHO5r0xv3JgALYk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bx56SV/btsgEMrOOWh/A2xkd4GXHO5r0xv3JgALYk/img.png&quot; data-alt=&quot;Key-Vaule Secret Engine&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bx56SV/btsgEMrOOWh/A2xkd4GXHO5r0xv3JgALYk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbx56SV%2FbtsgEMrOOWh%2FA2xkd4GXHO5r0xv3JgALYk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;987&quot; height=&quot;352&quot; data-origin-width=&quot;987&quot; data-origin-height=&quot;352&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Key-Vaule Secret Engine&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 시크릿 엔진은 볼트의 path를 통해서 활성화된다. 그래서 볼트에 요청이 올때 자동으로 해당 경로로 라우팅되어 처리된다. &lt;b&gt;시크릿 엔진은 개별 경로(path)와 속성이 정해져있기 때문에 사용하는 유저입장에서는 Virtual Filesystem이라고도 볼 수 있음&lt;/b&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Lifecycle&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Enable : 시크릿 엔진의 경로와 함께 Enable된다. (몇몇 시크릿 엔진은 여러 경로로 Enable이 될 수 있음) 각 시크릿 엔진은 각기 다른 경로에 isolated 된다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Disable : 생성된 시크릿 엔진을 Disable한다. 해당 하는 시크릿들은 모두 revoke되어 물리적 Storage에 저장된 모든 데이터들은 삭제된다.&lt;/li&gt;
&lt;li&gt;Move : 존재하는 시크릿엔진의 경로를 옮긴다. 이건 모든 시크릿을 revoke하고 새로 생성된 경로로 만들어진다.&lt;/li&gt;
&lt;li&gt;Tune :&amp;nbsp; TTL과 같은 전역(Global) 구성을 조정하는 것으로 수정이라고 해석해도 될 듯하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;시크릿 엔진이 Enable 되면 임의의 UUID가 생성되어 해당 시크릿 엔진의 data root가 된다. 그래서 Vault Storage Layer는 상대적인 접근 (../ 과 같은)을 지원하지 않기 때문에 하나의 시크릿 엔진이 다른 데이터로 접근이 불가능하다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Secret Engine 종류&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Key Value&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 많이 사용하는 대표적인 시크릿 엔진이다. Key-Value 방식으로 물리적인 Storage에 저장되며 백앤드에서는 두가지 모드로 실행된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;KV version 1 :&amp;nbsp;&lt;/b&gt; 버전이 지정되지 않은 kv 시크릿 엔진이 실행될 때 version 1으로 구성된다. 오직 최근에 쓰기된 key-value가 보존된다. 이 버전의 장점은 각 키의 추가적인 메타데이터와 히스토리가 없기 때문에 Storage size를 줄일 수 있다. 또한, Storage call와 locking이 없기 때문에 퍼포먼스도 비교적 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;KV version 2 :&lt;/b&gt; 이전 버전의 메타데이터와 데이터를 검색할 수 있으며, Check-and-Set 작업으로 데이터를 실수로 덮어쓰는 것을 방지할 수 있다. 버전이 삭제되면 기본 데이터는 삭제되지 않는다(삭제된 것으로 표시는 됨) 물론 버전 별 메타데이터를 삭제할 수 있으나 ACL을 통해서 삭제 권한을 유저에 따라 지정할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 아래에 KV version 2를 테스트해보려고함&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Transit&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전송 중인 데이터에 대한 암호화 기능을 지원한다. Vault는 전송된 데이터를 저장하지 않는다. Transit는 데이터에 서명하고 확인이 가능하다. 어플리케이션의 데이터를 암호화할 수 있어, 어플리케이션 개발자의 보안(민감 데이터의 암호화/복호화) 부담을 덜어주는 역할을 한다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;AWS&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IAM 정책에 따라서 동적인 AWS 액세스 자격 증명을 생성한다. 웹 UI를 클릭할 필요없이 AWS IAM 작업을 손쉽게 진행할 수 있다. 이 프로세스는 코드화되어서 내부 인증 방법에 매핑되며, AWS IAM 자격증명은 시간 기반이기 때문에 Vault lease 가 만료되면 자동으로 revoke된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지원하는 자격증명은 3가지다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;iam_user&lt;/li&gt;
&lt;li&gt;assumed_role&lt;/li&gt;
&lt;li&gt;federation_token&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Database&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성된 역할을 기반으로 동적으로 데이터베이스 자격 증명을 생성할 수 있다. Plugin 인터페이스로 다양한 데이터베이스와 함께 작동한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 서비스가 유니크한 자격 증명을 통해서 데이터베이스에 접근하기 때문 관리가 쉬우며, 유저가 정해진 기간에만 접근하도록 통제할 수 있다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;KV Secrets Engine v2 테스트&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;v2는 롤백 기능을 제공해서, 덮어쓰기와 손실로 인한 데이터 복구가 가능하다. v2에서는 secret의 버전을 유지해서 이전 데이터를 검색할 수 있다. 아래 그림처럼 이미 삭제(Delete)된 시크릿을 복구(Undo Delete) 할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1577&quot; data-origin-height=&quot;517&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/L1oLY/btsgJZ49jmU/XWfdmO0KXImTpR3kEGaRp1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/L1oLY/btsgJZ49jmU/XWfdmO0KXImTpR3kEGaRp1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/L1oLY/btsgJZ49jmU/XWfdmO0KXImTpR3kEGaRp1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FL1oLY%2FbtsgJZ49jmU%2FXWfdmO0KXImTpR3kEGaRp1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1577&quot; height=&quot;517&quot; data-origin-width=&quot;1577&quot; data-origin-height=&quot;517&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: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;직접 v2를 올려보고 복구하는 과정을 테스트해보려고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;KV v2 enable, write&lt;/h4&gt;
&lt;pre id=&quot;code_1684652891079&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ vault secrets enable -path=secret kv-v2
$ vault kv put secret/customer/acme customer_name=&quot;ACME Inc.&quot; \
        contact_email=&quot;john.smith@acme.com&quot;&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;574&quot; data-origin-height=&quot;290&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GmAzP/btsgG5q5IdX/EFJStdZ3LP0Q3gCp0BhYkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GmAzP/btsgG5q5IdX/EFJStdZ3LP0Q3gCp0BhYkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GmAzP/btsgG5q5IdX/EFJStdZ3LP0Q3gCp0BhYkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGmAzP%2FbtsgG5q5IdX%2FEFJStdZ3LP0Q3gCp0BhYkK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;574&quot; height=&quot;290&quot; data-origin-width=&quot;574&quot; data-origin-height=&quot;290&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kv put을 통해서 위와 같은 Secret이 생성 것을 알 수 있다. 처음 생성된 Secret은 version이 1로 시작된다.&lt;/p&gt;
&lt;pre id=&quot;code_1684653059276&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ vault kv put secret/customer/acme customer_name=&quot;ACME Inc.&quot; \
    contact_email=&quot;john.smith@acme.com&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 같은 경로에 Secret을 생성하면 아래와 같이 Version이 2로 변경된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;527&quot; data-origin-height=&quot;290&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkNWi7/btsgDMy7YzP/BpHRa1EK9KJL9U4JR7o8l0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkNWi7/btsgDMy7YzP/BpHRa1EK9KJL9U4JR7o8l0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkNWi7/btsgDMy7YzP/BpHRa1EK9KJL9U4JR7o8l0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkNWi7%2FbtsgDMy7YzP%2FBpHRa1EK9KJL9U4JR7o8l0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;527&quot; height=&quot;290&quot; data-origin-width=&quot;527&quot; data-origin-height=&quot;290&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1684653115067&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ vault kv get secret/customer/acme&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 경로에서 Secret을 확인해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;561&quot; data-origin-height=&quot;412&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dQxMEh/btsgEdpEGkb/5Djhch0sPyOrj2R7V5v7jk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dQxMEh/btsgEdpEGkb/5Djhch0sPyOrj2R7V5v7jk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dQxMEh/btsgEdpEGkb/5Djhch0sPyOrj2R7V5v7jk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdQxMEh%2FbtsgEdpEGkb%2F5Djhch0sPyOrj2R7V5v7jk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;561&quot; height=&quot;412&quot; data-origin-width=&quot;561&quot; data-origin-height=&quot;412&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Version 2의 Data가 입력되어 있는 것을 알 수 있다. 같은 경로에 Secret을 put하면 이전 버전의 Secret을 대체한다. 그럼 이제 put이 아닌, patch를 통해서 secret의 버전을 업데이트해본다.&lt;/p&gt;
&lt;pre id=&quot;code_1684653320467&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ vault kv patch secret/customer/acme contact_email=&quot;admin@acme.com&quot;&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;528&quot; data-origin-height=&quot;268&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/piPrZ/btsgEgtDwPc/3MRjAkDZy1ucLInrRjRYyk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/piPrZ/btsgEgtDwPc/3MRjAkDZy1ucLInrRjRYyk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/piPrZ/btsgEgtDwPc/3MRjAkDZy1ucLInrRjRYyk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpiPrZ%2FbtsgEgtDwPc%2F3MRjAkDZy1ucLInrRjRYyk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;528&quot; height=&quot;268&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;268&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;patch를 통해 Secret의 Version은 3으로 변경되었다.&lt;/p&gt;
&lt;pre id=&quot;code_1684653451183&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ vault kv get -version=2 secret/customer/acme&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Version 2의 Secret을 확인하려면 -version=2 를 추가한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;407&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmK3vb/btsgNW70EdD/9akoW3Bhi3KAq0aw3Ge6m0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmK3vb/btsgNW70EdD/9akoW3Bhi3KAq0aw3Ge6m0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmK3vb/btsgNW70EdD/9akoW3Bhi3KAq0aw3Ge6m0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbmK3vb%2FbtsgNW70EdD%2F9akoW3Bhi3KAq0aw3Ge6m0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;528&quot; height=&quot;407&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;407&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 해당 경로의 Secret의 메타데이터를 확인하고 싶다면 아래와 같이 입력한다.&lt;/p&gt;
&lt;pre id=&quot;code_1684653542968&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ vault kv metadata get secret/customer/acme&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;KV v2에서는 시크릿 엔진이 10개 Version을 유지한다.(config에서는 max_versions가 0으로 되어있으나 실제 default는 10이라고 보면됨) 이 값을 수정해서 불필요하게 보관하는 시크릿을 줄일 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1684653641618&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ vault read secret/config // secret 설정 확인
$ vault write secret/config max_versions=4 // secret max_version 변경&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Web UI를 이용하면 아래와 같이 쉽게 확인할 수 있다.&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;605&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c8cc57/btsgG4MusEl/VqUnLRB8XA4v6oxkzP6NA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c8cc57/btsgG4MusEl/VqUnLRB8XA4v6oxkzP6NA1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c8cc57/btsgG4MusEl/VqUnLRB8XA4v6oxkzP6NA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc8cc57%2FbtsgG4MusEl%2FVqUnLRB8XA4v6oxkzP6NA1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/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;605&quot; data-origin-width=&quot;1281&quot; data-origin-height=&quot;605&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;</description>
      <category>DevOps/Vault</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/369</guid>
      <comments>https://tigercoin.tistory.com/369#entry369comment</comments>
      <pubDate>Sun, 21 May 2023 16:23:10 +0900</pubDate>
    </item>
    <item>
      <title>EKS Ingress 생성 시 failed to retrieve credentials, sts:AssumeRoleWithWebIdentity 오류 해결하기</title>
      <link>https://tigercoin.tistory.com/368</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2220&quot; data-origin-height=&quot;804&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/B6Y0W/btsgkik4tce/L4bRHNkayOxAHJIw16MdC1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/B6Y0W/btsgkik4tce/L4bRHNkayOxAHJIw16MdC1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/B6Y0W/btsgkik4tce/L4bRHNkayOxAHJIw16MdC1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FB6Y0W%2Fbtsgkik4tce%2FL4bRHNkayOxAHJIw16MdC1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2220&quot; height=&quot;804&quot; data-origin-width=&quot;2220&quot; data-origin-height=&quot;804&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: #172b4d; text-align: start;&quot;&gt;ServiceAccount에 적용된 Role의 신뢰관계 설정 문제일 가능성이 크다. ServiceAccount가 AWS 리소스에 접근할 권한이 없기 때문.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1684328891542&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ kubectl describe sa aws-load-balancer-controller -n kube-system&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;1562&quot; data-origin-height=&quot;328&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qedWT/btsgkIw2WYa/uLZWoznHbudErNducNNF91/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qedWT/btsgkIw2WYa/uLZWoznHbudErNducNNF91/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qedWT/btsgkIw2WYa/uLZWoznHbudErNducNNF91/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqedWT%2FbtsgkIw2WYa%2FuLZWoznHbudErNducNNF91%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/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;328&quot; data-origin-width=&quot;1562&quot; data-origin-height=&quot;328&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: #172b4d; text-align: start;&quot;&gt;먼저 ALB Controller의 SA를 상세 정보를 확인하면, &lt;span style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot;&gt;위와 같이 Annotation에 선언된 Role을 확인할 수 있음. 위에선 AmazonEKSLoadBalancerControllerRole이 SA의 Role로 선언되어 있음. &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot;&gt;AmazonEKSLoadBalancerControllerRole을 확인해보면 아래와 같은 신뢰관계가 구성되어있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1684328657194&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
    &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::{ account }:oidc-provider/oidc.eks.ap-northeast-2.amazonaws.com/id/{ oidc ID }&quot;
            },
            &quot;Action&quot;: &quot;sts:AssumeRoleWithWebIdentity&quot;,
            &quot;Condition&quot;: {
                &quot;StringEquals&quot;: {
                    &quot;oidc.eks.ap-northeast-2.amazonaws.com/id/{ oidc ID }:aud&quot;: &quot;sts.amazonaws.com&quot;,
                    &quot;oidc.eks.ap-northeast-2.amazonaws.com/id/{ oidc ID }:sub&quot;: &quot;system:serviceaccount:kube-system:aws-load-balancer-controller&quot;
                }
            }
        }
    ]
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 oidc ID가 잘못 설정되어 있거나 AssumeRoleWithWebIdentity Action 선언이 안되어 있을 수 있다. 아니면 해당 Role에 ALB Controller에게 필요한 Policy가 연결안되어 있을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ALB Controller에게 필요한 Policy는 아래 명령어를 통해서 다운받아 생성하면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1684328816525&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ curl -o iam_policy.json https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.3.1/docs/install/iam_policy.json&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DevOps/Kubernetes</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/368</guid>
      <comments>https://tigercoin.tistory.com/368#entry368comment</comments>
      <pubDate>Wed, 17 May 2023 22:09:45 +0900</pubDate>
    </item>
    <item>
      <title>EKS ALB Controller 생성 후, ALB Ingress 배포하기</title>
      <link>https://tigercoin.tistory.com/367</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1892&quot; data-origin-height=&quot;1307&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b0CjQ7/btsgn1ofPql/73QPalDgnddlrxckVKkD8k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b0CjQ7/btsgn1ofPql/73QPalDgnddlrxckVKkD8k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b0CjQ7/btsgn1ofPql/73QPalDgnddlrxckVKkD8k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0CjQ7%2Fbtsgn1ofPql%2F73QPalDgnddlrxckVKkD8k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1892&quot; height=&quot;1307&quot; data-origin-width=&quot;1892&quot; data-origin-height=&quot;1307&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 id=&quot;Ingress-동작-방식&quot; style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;4&quot; data-ke-size=&quot;size23&quot;&gt;Ingress 동작 방식&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-indent-level=&quot;1&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;ALB Controller는 API 서버의 Ingress 이벤트를 모니터링한다. 요구 사항을 충족하는 수신 리소스 발견 시, AWS 리소스 생성을 시작한다.&lt;/li&gt;
&lt;li&gt;수신 리소스에 맞춰 AWS에서 ALB(ELB v2)를 생성한다.(이 ALB는 인터넷 연결이 되거나 내부에 존재할 수 있으며 Annotation으로 서브넷 지정 가능)&lt;/li&gt;
&lt;li&gt;Target Group은 수신 리소스에서 지정된 고유 k8s 서비스에 대해 AWS에서 생성된다.&lt;/li&gt;
&lt;li&gt;수신 리소스의 Annotation에 설명된 모든 포트에 대해 리스너가 생성된다. 포트는 80과 443이 디폴트며, Annotation에 인증서 첨부도 가능하다.&lt;/li&gt;
&lt;li&gt;수신 리소스에 각 경로에 대한 규칙이 생성된다. 특정 경로에 대한 트래픽이 적절한 k9s 서비스로 라우팅된다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;1)-OIDC-프로바이더-생성&quot; style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;423&quot; data-ke-size=&quot;size26&quot;&gt;1) OIDC 프로바이더 생성&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;441&quot; data-ke-size=&quot;size16&quot;&gt;AWS IAM에서는 OIDC(OpenID Connect)로 연동 자격 증명을 지원하는 기능을 추가했다. 이 기능으로 자격 증명 공급자를 이용하여 AWS API 호출을 인증하고 유효한 OIDC JWT를 수신한다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;560&quot; data-ke-size=&quot;size16&quot;&gt;이 토큰을 AWS STS AssumeRoleWithWebIdentity API작업에 전달하고 IAM 임시 역할 자격 증명을 수신한다. 이 자격 으로 AWS 서비스 리소스를 k8s 리소스들이 사용할 수 있게된다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;679&quot; data-ke-size=&quot;size16&quot;&gt;아래와 같이 eksctl로 IAM OIDC Provider를 생성한다.&lt;/p&gt;
&lt;pre id=&quot;code_1684327688499&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;eksctl utils associate-iam-oidc-provider \
    --region ${AWS_REGION} \
    --cluster ${ekscluster_name} \
    --approve&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;1387&quot; data-origin-height=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkLAox/btsgiCD8qfL/4LE424rR4sWYipKApNYXak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkLAox/btsgiCD8qfL/4LE424rR4sWYipKApNYXak/img.png&quot; data-alt=&quot;생성된 oidc 자격 증명 공급자&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkLAox/btsgiCD8qfL/4LE424rR4sWYipKApNYXak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkLAox%2FbtsgiCD8qfL%2F4LE424rR4sWYipKApNYXak%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1387&quot; height=&quot;600&quot; data-origin-width=&quot;1387&quot; data-origin-height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;생성된 oidc 자격 증명 공급자&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div&gt;
&lt;div data-type=&quot;file&quot; data-node-type=&quot;media&quot; data-width=&quot;1135&quot; data-height=&quot;333&quot; data-id=&quot;399c5ba3-16d4-4575-97cb-285188e1b2b6&quot; data-collection=&quot;contentId-394887399&quot; data-file-name=&quot;image-20230516-074029.png&quot; data-file-size=&quot;458610&quot; data-file-mime-type=&quot;image/png&quot; data-alt=&quot;&quot; data-context-id=&quot;394887399&quot;&gt;
&lt;div id=&quot;newFileExperienceWrapper&quot; data-testid=&quot;media-card-view&quot;&gt;
&lt;div data-testid=&quot;media-file-card-view&quot; data-test-status=&quot;complete&quot; data-test-media-name=&quot;image-20230516-074029.png&quot; data-test-progress=&quot;1&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&quot;2)-ALB-Controller&quot; style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;845&quot; data-ke-size=&quot;size26&quot;&gt;2) ALB Controller&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;864&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2-1) ALB Controller의 IAM Policy File&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1684327768086&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;curl -o iam_policy.json https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.3.1/docs/install/iam_policy.json&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;1042&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2-2) Create IAM Policy&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1684327778684&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;aws iam create-policy \
    --policy-name AWSLoadBalancerControllerIAMPolicy \
    --policy-document file://./iam_policy.json&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;1200&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2-3) Create Service Account (앞서 생성된 Policy와 Role을 이용)&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1684327793436&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;eksctl create iamserviceaccount \
--cluster=${ekscluster_name} \
--namespace=kube-system \
--name=aws-load-balancer-controller \
--attach-policy-arn=arn:aws:iam::${ACCOUNT_ID}:policy/AWSLoadBalancerControllerIAMPolicy \
--override-existing-serviceaccounts \
--region ${AWS_REGION} \
--approve&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;1550&quot; data-ke-size=&quot;size16&quot;&gt;k8s에 Service Account 생성 확인&lt;/p&gt;
&lt;pre id=&quot;code_1684327805263&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;kubectl get serviceaccounts -n kube-system aws-load-balancer-controller -o yaml&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;1660&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2-4) Cert Manager 설치&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1684327814195&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export CERTMGR_VERSION=1.9.1
kubectl apply --validate=false -f https://github.com/jetstack/cert-manager/releases/download/v${CERTMGR_VERSION}/cert-manager.yaml
kubectl -n cert-manager get pods&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;1876&quot; data-ke-size=&quot;size16&quot;&gt;3개의 cert manger pod가 작동하는 지 확인&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;1908&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2-5) ALB Controller Pod 설치&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1684327823521&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;curl -Lo v2_4_7_full.yaml https://github.com/kubernetes-sigs/aws-load-balancer-controller/releases/download/v2.4.7/v2_4_7_full.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;2069&quot; data-ke-size=&quot;size16&quot;&gt;yaml파일에서 cluster-name에 적용할 cluster 이름을 지정, Service Account 섹션은 이미 'aws-load-balancer-controller' SA 를 생성했기 때문에 지워줌&lt;/p&gt;
&lt;pre id=&quot;code_1684327834403&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;kubectl apply -f v2_4_7_full.yaml
kubectl get po -n kube-system&lt;/code&gt;&lt;/pre&gt;
&lt;div style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div&gt;
&lt;div data-type=&quot;file&quot; data-node-type=&quot;media&quot; data-width=&quot;766&quot; data-height=&quot;158&quot; data-id=&quot;f8ce62d1-14eb-45bc-8a9c-3fabed1d62db&quot; data-collection=&quot;contentId-394887399&quot; data-file-name=&quot;image-20230516-075006.png&quot; data-file-size=&quot;104861&quot; data-file-mime-type=&quot;image/png&quot; data-alt=&quot;&quot; data-context-id=&quot;394887399&quot;&gt;
&lt;div id=&quot;newFileExperienceWrapper&quot; data-testid=&quot;media-card-view&quot;&gt;
&lt;div data-testid=&quot;media-file-card-view&quot; data-test-status=&quot;complete&quot; data-test-media-name=&quot;image-20230516-075006.png&quot; data-test-progress=&quot;1&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;760&quot; data-origin-height=&quot;157&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bW90QF/btsgn21LFso/VY6UCRphn2GGPK3VpDfSrK/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bW90QF/btsgn21LFso/VY6UCRphn2GGPK3VpDfSrK/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bW90QF/btsgn21LFso/VY6UCRphn2GGPK3VpDfSrK/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbW90QF%2Fbtsgn21LFso%2FVY6UCRphn2GGPK3VpDfSrK%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;760&quot; height=&quot;157&quot; data-origin-width=&quot;760&quot; data-origin-height=&quot;157&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;2255&quot; data-ke-size=&quot;size16&quot;&gt;정상 작동 중인 것을 확인.&lt;/p&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;2272&quot; data-ke-size=&quot;size26&quot;&gt;3) Ingress Configuration&lt;/h2&gt;
&lt;pre id=&quot;code_1684327846399&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: &quot;i8&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-xxxxxxx
spec:
  rules:
   - http:
      paths:
        - path: /
          pathType: Prefix
          backend:
            service:
              name: &quot;nginx&quot;
              port:
                number: 80&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;2825&quot; data-ke-size=&quot;size16&quot;&gt;위는 Ingress.yaml 예시로 nginx service를 참조하고 있다. 여기서 annotation 설정이 중요하다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-indent-level=&quot;1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;alb.ingress.kubernetes.io/target-type: ip (트래픽 모드를 의미)
&lt;ul style=&quot;list-style-type: disc;&quot; data-indent-level=&quot;2&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;instance type : 수신 트래픽은 ALB에서 시작하여 각 서비스의 NodePort를 통해 Kubernetes 노드에 도달합니다. 이는 수신 리소스에서 참조하는 서비스가 ALB에 도달하기 위해 에서 type:NodePort가 있어야 함을 의미합니다.&lt;/li&gt;
&lt;li&gt;ip type : 수신 트래픽은 ALB에서 시작하여 Kubernetes Pod에 직접 도달합니다. CNI는 ENI의 Secondary IP 주소를 통해 직접 액세스할 수 있는 POD IP를 지원해야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;alb.ingress.kubernetes.io/scheme: internet-facing (로드밸런서의 인터넷 연결 여부)&lt;/li&gt;
&lt;li&gt;alb.ingress.kubernetes.io/subnets: subnet-********* (ALB가 라우트할 수 있는 subnet 지정)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2172&quot; data-origin-height=&quot;831&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o7Jl9/btsgnhSqhvn/trBxDmueBz7V4ps6tQGoaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o7Jl9/btsgnhSqhvn/trBxDmueBz7V4ps6tQGoaK/img.png&quot; data-alt=&quot;Ingress 생성 완료&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o7Jl9/btsgnhSqhvn/trBxDmueBz7V4ps6tQGoaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo7Jl9%2FbtsgnhSqhvn%2FtrBxDmueBz7V4ps6tQGoaK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2172&quot; height=&quot;831&quot; data-origin-width=&quot;2172&quot; data-origin-height=&quot;831&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Ingress 생성 완료&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2247&quot; data-origin-height=&quot;1034&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CuVFS/btsglvKIGrM/vgKFG8mcmg26VerKFIpGAK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CuVFS/btsglvKIGrM/vgKFG8mcmg26VerKFIpGAK/img.png&quot; data-alt=&quot;target-type(트래픽 모드)이 IP기 때문에 target은 Pod의 IP로 설정되어있다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CuVFS/btsglvKIGrM/vgKFG8mcmg26VerKFIpGAK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCuVFS%2FbtsglvKIGrM%2FvgKFG8mcmg26VerKFIpGAK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2247&quot; height=&quot;1034&quot; data-origin-width=&quot;2247&quot; data-origin-height=&quot;1034&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;target-type(트래픽 모드)이 IP기 때문에 target은 Pod의 IP로 설정되어있다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>DevOps/Kubernetes</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/367</guid>
      <comments>https://tigercoin.tistory.com/367#entry367comment</comments>
      <pubDate>Wed, 17 May 2023 21:57:25 +0900</pubDate>
    </item>
    <item>
      <title>이더리움의 트랜잭션(Transaction) 이란?</title>
      <link>https://tigercoin.tistory.com/361</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이더리움의 트랜잭션은 암호로 서명된 Data message다. 한 이더리움 account에서 다른 account로 ETH를 전송하거나, 블록체인에 배포된 Smart Contract와 상호작용하는 역할을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션은 블록체인에 있어 아주 기본적이지만, 중요한 개념이기 때문에 관련 종사자라면 필수적으로 알아야하는 부분이기도 하다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;트랜잭션 Transaction&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션은 EVM 상태 변경을 위해 전체 네트워크에 Broadcast되어야 한다. 모든 노드는 EVM에 실행될 트랜잭션에 대한 요청을 Broadcast할 수 있어야하며, Broadcast된 후에는 Validator가 트랜잭션을 실행하고 상태가 변경된 결과를 네트워크에 전파한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이더리움 네트워크에서 트랜잭션은 Serialize되어 전송되는데, 각 클라이언트와 어플리케이션은 자체 내부 데이터 구조를 사용해 트랜잭션을 메모리에 저장한다. &lt;b&gt;트랜잭션은 아래 트랜잭션 구조에 있는 nonce ~ data 데이터를 포함하는 serialize된 binary 메시지다.&lt;/b&gt;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000;&quot; data-ke-size=&quot;size20&quot;&gt;트랜잭션 구조&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션 메시지의 구조는 바이트 시리얼라이제이션을 위해 특별히 개발된 RLP(Recursive Length Prefix) 인코딩 체계를 통해서 시리얼라이즈된다.&lt;/p&gt;
&lt;pre id=&quot;code_1682343956574&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  from: &quot;0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8&quot;,
  to: &quot;0xac03bb73b6a9e108530aff4df5077c2b3d481e5a&quot;,
  gasLimit: &quot;21000&quot;,
  maxFeePerGas: &quot;300&quot;,
  maxPriorityFeePerGas: &quot;10&quot;,
  nonce: &quot;0&quot;,
  value: &quot;10000000000&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc; color: #10151b; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;color: #000000;&quot;&gt;from - 보내는 address&lt;/li&gt;
&lt;li style=&quot;color: #000000;&quot;&gt;to &amp;ndash; 받는 address&lt;/li&gt;
&lt;li style=&quot;color: #000000;&quot;&gt;value &amp;ndash; ETH 양&lt;/li&gt;
&lt;li style=&quot;color: #000000;&quot;&gt;data &amp;ndash; can contain code or a message to the recipient.&lt;/li&gt;
&lt;li style=&quot;color: #000000;&quot;&gt;gasLimit &amp;ndash; 사용할 수 있는 gas unit의 최대량&lt;/li&gt;
&lt;li style=&quot;color: #000000;&quot;&gt;nonce - account에서 발생한 tx 순&lt;/li&gt;
&lt;li style=&quot;color: #000000;&quot;&gt;maxPriorityFeePerGas - 마이너에게 지급되는 최대 가스량&lt;/li&gt;
&lt;li style=&quot;color: #000000;&quot;&gt;maxFeePerGas -트랜잭션에 지불되는 최대 가스량&lt;/li&gt;
&lt;li style=&quot;color: #000000;&quot;&gt;signature &amp;ndash; 보내는 account의 개인 키에서 발생되어 트랜잭션에 서명할 때 생성.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;여기서 nonce는 동일한 수신 account에 동일한 양의 ETH를 전송하더라도 순서에 따라 변경되는 nonce값에 의해서 각각의 개별 트랜잭션이 고유하게 된다.&lt;/b&gt; 그만큼 nonce는 계정 기반(account-based) 프로토콜에선 필수적인 데이터로 트랜잭션 복제 방지와 사용성 상의 기능 역할을 충실히 해낸다고 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근에는 EIP-1559에 의해서 트랜잭션 표준이 변경되었다.(보다 더 예측 가능한 가스 요금과, 효율적인 거래를 위함)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;911&quot; data-origin-height=&quot;527&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/esHHTm/btscxmKi0cX/FJo8YXWsa5BJK4OhIKBQ80/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/esHHTm/btscxmKi0cX/FJo8YXWsa5BJK4OhIKBQ80/img.png&quot; data-alt=&quot;트랜잭션 가스비&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/esHHTm/btscxmKi0cX/FJo8YXWsa5BJK4OhIKBQ80/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FesHHTm%2FbtscxmKi0cX%2FFJo8YXWsa5BJK4OhIKBQ80%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;911&quot; height=&quot;527&quot; data-origin-width=&quot;911&quot; data-origin-height=&quot;527&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;트랜잭션 가스비&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;트랜잭션의 유형&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;트랜잭션의 주요 payload는 value와 data라는 2개의 필드에 포함되는데, value만 있다면 단순 ETH 전송이며, data만 있다면 Contract 함수를 호출한다고 볼 수 있다.&lt;/b&gt; 이 두 데이터가 없는 트랜잭션은 그저 가스 낭비인 무의미한 트랜잭션이라고 보면 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;697&quot; data-origin-height=&quot;529&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kIP5b/btscjk1r9oR/RBMW6p1X4m4qDfFgiCNakK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kIP5b/btscjk1r9oR/RBMW6p1X4m4qDfFgiCNakK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kIP5b/btscjk1r9oR/RBMW6p1X4m4qDfFgiCNakK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkIP5b%2Fbtscjk1r9oR%2FRBMW6p1X4m4qDfFgiCNakK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;697&quot; height=&quot;529&quot; data-origin-width=&quot;697&quot; data-origin-height=&quot;529&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&lt;span&gt;&amp;nbsp;&lt;/span&gt;Message call&lt;span style=&quot;color: #58626d; text-align: left;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;transaction: 다른 EOA 또는 CA와 상호 작용하려는 EOA에 의해서 파생된 트랜잭션이다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;-&lt;span&gt;&amp;nbsp;&lt;/span&gt;Contract creation&lt;span style=&quot;color: #58626d; text-align: left;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;transaction: 스마트 컨트랙트 계정을 생성하기 위해 만든 트랜잭션으로 이것 역시 EOA에 의해서 파생된다. 대표적으로 데이터 저장을 위한 Storage Smart Contract를 생성한다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #58626d; text-align: left;&quot;&gt;트랜잭션의 상태&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc; color: #10151b; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;color: #000000;&quot;&gt;Pending: 네트워크에 Broadcast된 트랜잭션으로, 트랜잭션 처리시간이 길어지면 Gas 요금이 부족하여 발생&lt;/li&gt;
&lt;li style=&quot;color: #000000;&quot;&gt;Queued: 먼저 Pending된 트랜잭션 또는 Sequence Nonce가 잘못입력되어 아직 마이닝이 안된 트랜잭션&lt;/li&gt;
&lt;li style=&quot;color: #000000;&quot;&gt;Cancelled: 더이상 마이닝할 수 없는 상태로&lt;/li&gt;
&lt;li style=&quot;color: #000000;&quot;&gt;Replaced: Value와 Data의 빠른 실행 혹은 수정을 위해서 현재 Pending 중인 트랜잭션을 대체&lt;/li&gt;
&lt;li style=&quot;color: #000000;&quot;&gt;Failed: 잘못되거나 비논리적인 코드 혹은 함수 호출로 인해 오류가 발생한 트랜잭션&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;간단히 말해서 트랜잭션의 이더리움 시스템의 모든 활동의 시작으로, 트랜잭션에 의해 EVM이 컨트랙트를 실행하고 잔액을 업데이트하며, 이더리움의 상태를 수정하게 된다.&lt;/b&gt;&lt;/p&gt;</description>
      <category>DevOps/Chain</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/361</guid>
      <comments>https://tigercoin.tistory.com/361#entry361comment</comments>
      <pubDate>Mon, 24 Apr 2023 22:58:49 +0900</pubDate>
    </item>
    <item>
      <title>Arbitrum Transaction GasPrice 0 테스트</title>
      <link>https://tigercoin.tistory.com/359</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1589&quot; data-origin-height=&quot;596&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cwQVeb/btr9C4rXIKX/0w9dlreAsrVJ3FTVV4nX1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cwQVeb/btr9C4rXIKX/0w9dlreAsrVJ3FTVV4nX1K/img.png&quot; data-alt=&quot;gasUsed 0으로 트랜잭션 발생에 가스비가 사용되지 않음&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cwQVeb/btr9C4rXIKX/0w9dlreAsrVJ3FTVV4nX1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcwQVeb%2Fbtr9C4rXIKX%2F0w9dlreAsrVJ3FTVV4nX1K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1589&quot; height=&quot;596&quot; data-origin-width=&quot;1589&quot; data-origin-height=&quot;596&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;gasUsed 0으로 트랜잭션 발생에 가스비가 사용되지 않음&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서비스 테스트를 위해서, 자체적으로 구축한 아비트럼 체인의 TxGas 수수료를 제로로 하는 테스트를 진행했다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1133&quot; data-origin-height=&quot;696&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/r3Kaw/btr9qB6pPEi/ldY2YoPh60US887KaRk5KK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/r3Kaw/btr9qB6pPEi/ldY2YoPh60US887KaRk5KK/img.png&quot; data-alt=&quot;Blockscout로 확인한 Transaction Details&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/r3Kaw/btr9qB6pPEi/ldY2YoPh60US887KaRk5KK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fr3Kaw%2Fbtr9qB6pPEi%2FldY2YoPh60US887KaRk5KK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1133&quot; height=&quot;696&quot; data-origin-width=&quot;1133&quot; data-origin-height=&quot;696&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Blockscout로 확인한 Transaction Details&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;짧은 시간에 Tx가 많이 요구되는 서비스라면 사용자 경험을 최적화하기 위해서, 가스비를 0로 해야할 수 있다. 서비스 테스팅을 위해서 아래 local-dev-node 방식으로 일부 코드를 수정하여 체인을 구축했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.arbitrum.io/node-running/local-dev-node&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://developer.arbitrum.io/node-running/local-dev-node&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1681217667395&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;Running a local dev node | Arbitrum Documentation Center&quot; data-og-description=&quot;1. Install&quot; data-og-host=&quot;developer.arbitrum.io&quot; data-og-source-url=&quot;https://developer.arbitrum.io/node-running/local-dev-node&quot; data-og-url=&quot;https://developer.arbitrum.io/node-running/local-dev-node&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/uw0mh/hySe5A9G2f/CWhJR4hVINPEnuDyBTiTkk/img.png?width=1080&amp;amp;height=1080&amp;amp;face=0_0_1080_1080&quot;&gt;&lt;a href=&quot;https://developer.arbitrum.io/node-running/local-dev-node&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.arbitrum.io/node-running/local-dev-node&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/uw0mh/hySe5A9G2f/CWhJR4hVINPEnuDyBTiTkk/img.png?width=1080&amp;amp;height=1080&amp;amp;face=0_0_1080_1080');&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;Running a local dev node | Arbitrum Documentation Center&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;1. Install&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.arbitrum.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아비트럼의 가스비는 ETH로 사용되며, Arbos의 L2Pricing 기능을 통해서 비용이 결정되는데, Arbos가 Nitro 노드의 Middle layer기 때문에 Base layer인 Geth Core의 코드의 수정도 필요하다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1681217403193&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# arbos/l2pricing/model.go

const InitialSpeedLimitPerSecondV0 = 1000000
const InitialPerBlockGasLimitV0 uint64 = 20 * 1000000
const InitialSpeedLimitPerSecondV6 = 7000000
const InitialPerBlockGasLimitV6 uint64 = 32 * 1000000
const InitialMinimumBaseFeeWei = params.GWei / 10
const InitialBaseFeeWei = InitialMinimumBaseFeeWei * 0 #
const InitialGasPoolSeconds = 10 * 60
const InitialRateEstimateInertia = 60
const InitialPricingInertia = 102
const InitialBacklogTolerance = 10&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1681216961636&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Arbos L2PricingState

type L2PricingState struct {
	storage             *storage.Storage
	gasPool             storage.StorageBackedInt64
	smallGasPool        storage.StorageBackedInt64
	gasPoolSeconds      storage.StorageBackedUint64
	smallGasPoolSeconds storage.StorageBackedUint64
	gasPriceWei         storage.StorageBackedBigInt
	minGasPriceWei      storage.StorageBackedBigInt
	maxGasPriceWei      storage.StorageBackedBigInt // the maximum price ArbOS can set without breaking geth
	speedLimitPerSecond storage.StorageBackedUint64
	maxPerBlockGasLimit storage.StorageBackedUint64
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 살펴본 바로는 Arbos에서 L2Pricing에 영향을 주는 파라미터 설정(l2pricing/model.go)되면 User Demand와 Geth state 및 Computation Speed Limit 등의 요소를 고려해서 L2PricingState(l2pricing/l2pricingstate.go)를 통해 L2 가격을 결정한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 InitialBaseFeeWei와 UpdatePricingModel()을 통한 SetBaseFeeWei() 메소드의 인자값을 변경해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, Arbos는 Nitro 노드의 하나의 레이어로 실제 evm contract 실행과 state 구성에 Geth core가 담당하기 때문에 초기 TxGas 파라미터의 수정(go-ethereum/params/protocol_params.go)도 요구된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가스비를 제거했기 때문에 무분별한 Tx 전송으로 인한 디도스 공격과 대량의 Tx에 의한 Batch post의 레이턴시를 감안해야한다.&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://research.arbitrum.io/t/challenging-periods-reimagined-the-key-role-of-sequencer-decentralization/9189&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://research.arbitrum.io/t/challenging-periods-reimagined-the-key-role-of-sequencer-decentralization/9189&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1681219110897&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;Challenging Periods Reimagined: The Key Role of Sequencer Decentralization&quot; data-og-description=&quot;Check out the complete second part of the Challenging Periods Reimagined Series by clicking here. This part focuses on sequencer decentralization and its integration into our proposed dynamic challenging period model. If you have not read the first part, w&quot; data-og-host=&quot;research.arbitrum.io&quot; data-og-source-url=&quot;https://research.arbitrum.io/t/challenging-periods-reimagined-the-key-role-of-sequencer-decentralization/9189&quot; data-og-url=&quot;https://research.arbitrum.io/t/challenging-periods-reimagined-the-key-role-of-sequencer-decentralization/9189&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/btG5k2/hySeYvgWtw/QrfD1XbTL0iOdAKPf8UIm0/img.jpg?width=1024&amp;amp;height=578&amp;amp;face=0_0_1024_578,https://scrap.kakaocdn.net/dn/Dzw6v/hySe7lt08R/sRIlqtHZnzUzOvKSgrqE81/img.jpg?width=1024&amp;amp;height=578&amp;amp;face=0_0_1024_578,https://scrap.kakaocdn.net/dn/nQtkz/hySeZOslSU/4L6Gpiq8IWr97ATNUO8kA1/img.jpg?width=690&amp;amp;height=389&amp;amp;face=0_0_690_389&quot;&gt;&lt;a href=&quot;https://research.arbitrum.io/t/challenging-periods-reimagined-the-key-role-of-sequencer-decentralization/9189&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://research.arbitrum.io/t/challenging-periods-reimagined-the-key-role-of-sequencer-decentralization/9189&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/btG5k2/hySeYvgWtw/QrfD1XbTL0iOdAKPf8UIm0/img.jpg?width=1024&amp;amp;height=578&amp;amp;face=0_0_1024_578,https://scrap.kakaocdn.net/dn/Dzw6v/hySe7lt08R/sRIlqtHZnzUzOvKSgrqE81/img.jpg?width=1024&amp;amp;height=578&amp;amp;face=0_0_1024_578,https://scrap.kakaocdn.net/dn/nQtkz/hySeZOslSU/4L6Gpiq8IWr97ATNUO8kA1/img.jpg?width=690&amp;amp;height=389&amp;amp;face=0_0_690_389');&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;Challenging Periods Reimagined: The Key Role of Sequencer Decentralization&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Check out the complete second part of the Challenging Periods Reimagined Series by clicking here. This part focuses on sequencer decentralization and its integration into our proposed dynamic challenging period model. If you have not read the first part, w&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;research.arbitrum.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아비트럼은 직접적으로 L2 가스비를 수취하는 시퀀서를 탈중앙화할 계획이다. 이를 위해서 Governance adjusted time과 Multi-chain multi-slot sequencer selection process, Penalizing a seqeuncer 등 의 방법이 논의되고 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1508&quot; data-origin-height=&quot;798&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qAgWz/btr9zOKxjTN/SeJLCj2acsIy7Y0CmQ46W0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qAgWz/btr9zOKxjTN/SeJLCj2acsIy7Y0CmQ46W0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qAgWz/btr9zOKxjTN/SeJLCj2acsIy7Y0CmQ46W0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqAgWz%2Fbtr9zOKxjTN%2FSeJLCj2acsIy7Y0CmQ46W0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1508&quot; height=&quot;798&quot; data-origin-width=&quot;1508&quot; data-origin-height=&quot;798&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 Sequencer가 아비트럼 체인에서 활동할 주요 동기요인은 역시나 유저들의 L2 트랜잭션 수수료를 통한 수익이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Sequencer 노드는 L2 수수료의 일부를 수취하고 나머지는 network fee pool로 이동하여 L2 tx, L1 calldata와 Computation 및 Storage를 위해 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론적으로, 점진적으로 노드의 '탈중앙화'를 고려한다면 가스비가 0이어선 안된다. 가스비를 없애는 건, 오로지 단일 Dapp을 위한 프라이빗 L2에서만 가능한 구조다.&lt;/p&gt;</description>
      <category>DevOps/Chain</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/359</guid>
      <comments>https://tigercoin.tistory.com/359#entry359comment</comments>
      <pubDate>Tue, 11 Apr 2023 22:00:09 +0900</pubDate>
    </item>
    <item>
      <title>아비트럼의 Arbos, Aggregator, Sequencer, Validator</title>
      <link>https://tigercoin.tistory.com/358</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot;&gt;[Arbos]&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot;&gt;nitro 노드는 아래와 같은 세가지 layer로 구성된다.&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;1185&quot; data-origin-height=&quot;660&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NofC2/btr9CH4BD4M/9klZCSfVB69CsdYwxeQki0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NofC2/btr9CH4BD4M/9klZCSfVB69CsdYwxeQki0/img.png&quot; data-alt=&quot;https://developer.arbitrum.io/inside-arbitrum-nitro/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NofC2/btr9CH4BD4M/9klZCSfVB69CsdYwxeQki0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNofC2%2Fbtr9CH4BD4M%2F9klZCSfVB69CsdYwxeQki0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1185&quot; height=&quot;660&quot; data-origin-width=&quot;1185&quot; data-origin-height=&quot;660&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://developer.arbitrum.io/inside-arbitrum-nitro/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-indent-level=&quot;1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;base layer : evm contract 실행과 state를 구성하는 데이터 구조를 유지 관리하는 core 역할을 담당한다. nitro에선 필요한 hook를 추가하기 위해 몇가지 수정을 거쳐 이 코드를 라이브러리로 컴파일한다.&lt;/li&gt;
&lt;li&gt;middle layer : arbos로써, sequencer의 batch와 압축 및 해석, layer 1 가스비용 계산과 요금 징수 등 레이어 2의 추가 기능을 제공하는 custom s/w. 크로스체인 브릿지 기능을 지원한다.&lt;/li&gt;
&lt;li&gt;top layer : geth 에서 가져온 노드 소프트웨어로 구성된다. client로부터 접속과 RPC request를 처리하고 Ethernet 호환을 위한 노드를 작동시키는 기능을 담당한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;[Full-node-(Aggregator)]&quot; style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;1&quot; data-ke-size=&quot;size26&quot;&gt;[Full node, Aggregator]&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;27&quot; data-ke-size=&quot;size16&quot;&gt;아비트럼의 풀노드는 이더리움의 풀노드와 비슷한 역할을 함. 체인의 state를 알고 있고, 유저가 체인과 상호작용을 하기 위한 API를 제공함.&lt;/p&gt;
&lt;h3 id=&quot;Batch-트랜잭션&quot; style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;109&quot; data-ke-size=&quot;size23&quot;&gt;Batch 트랜잭션&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;121&quot; data-ke-size=&quot;size16&quot;&gt;풀노드는 애그리게이터로서 기능을 함. 사용자로부터 서명된 트랜잭션 세트를 수신하여 일괄적으로 체인의 Inbox에 제출함. 이 제출은 L1 트랜잭션으로, 일괄적으로 묶어서 제출하여 비용을 절약한다. 일괄 제출은 허가 없이 이뤄진다.&lt;/p&gt;
&lt;h3 id=&quot;트랜잭션-압축&quot; style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;251&quot; data-ke-size=&quot;size23&quot;&gt;트랜잭션 압축&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;260&quot; data-ke-size=&quot;size16&quot;&gt;풀노드는 트랜잭션을 압축하여 L1의 calldata 공간을 절약한다. 사용자는 트랜잭션을 풀노드에 제출하면 풀노드는 트랜잭션을 압축하여 체인에 제출한다. 여기서 ArbOS는 트랜잭션을 수신하여 압축해제 후, 읽을 수 있는 원래 트랜잭션으로 복구한다. ArbOS는 트랜잭션의 서명을 확인한 후 처리한다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;431&quot; data-ke-size=&quot;size16&quot;&gt;풀노드는 트랜잭션 제출 시, Batch로 묶고 압축하는 과정을 모두 거친다.&lt;/p&gt;
&lt;h3 id=&quot;제출-비용&quot; style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;475&quot; data-ke-size=&quot;size23&quot;&gt;제출 비용&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;482&quot; data-ke-size=&quot;size16&quot;&gt;유저를 대신에 트랜잭션을 제출하는데, L1 트랜잭션이므로 비용이 발생한다. 아비트럼은 유저로부터 요금을 징수해서 애그리게이터의 비용을 상환하는 기능을 통해서 비용을 충당한다.&lt;/p&gt;
&lt;h2 id=&quot;[Sequencer-Mode]&quot; style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;590&quot; data-ke-size=&quot;size26&quot;&gt;[Sequencer]&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;608&quot; data-ke-size=&quot;size16&quot;&gt;시퀀서 모드는 옵션 기능이지만, 대부분 활성화될 것으로 예상한다. 시퀀서는 특별한 풀노드로 트랜잭션 순서를 제어할 수 있는 권한이 부여된다. 또한 유저의 트랜잭션 결과를 즉시 보장할 수 있다. 클라이언트는 풀노드와 통신하는 것과 같은 방식으로 시퀀서와 상호작용한다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;758&quot; data-ke-size=&quot;size16&quot;&gt;시퀀서 모든 요청자로부터 트랜잭션을 받아 공정하게 처리해야하며, 각 요청자에게 최대한 빠르게 약속된 트랜잭션 결과를 제공한다.&lt;/p&gt;
&lt;h2 id=&quot;[Validator]&quot; style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;831&quot; data-ke-size=&quot;size26&quot;&gt;[Validator]&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;844&quot; data-ke-size=&quot;size16&quot;&gt;검증자는 시퀀서 Inbox에 있는 트랜잭션을 읽고 처리하여 업데이트된 L2 state 데이터 해시를 롤업 스마트 계약에 제출한다. 검증자가 L2 state 데이터를 롤업 스마트 계약에 제출할 때, 현재 체인의 어떤 블록이 이 새 블록의 상위 블록인지도 지정한다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;992&quot; data-ke-size=&quot;size16&quot;&gt;유효하지 않은 state 데이터를 제출하는 검증자를 처벌하기 위해서 검증자는 스테이커여야한다.(일정량의 ETH 보관) 악의적인 행위로 체인에 부정적인 영향을 끼치는 것이 판명되는 경우 보유한 ETH는 슬래쉬된다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #172b4d; text-align: start;&quot; data-renderer-start-pos=&quot;992&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.arbitrum.io/inside-arbitrum-nitro/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://developer.arbitrum.io/inside-arbitrum-nitro/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1681216238499&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;Inside Arbitrum Nitro | Arbitrum Documentation Center&quot; data-og-description=&quot;This document is a deep-dive explanation of Arbitrum Nitro&amp;rsquo;s design and the rationale for it. This isn&amp;rsquo;t API documentation, nor is it a guided tour of the code--look elsewhere for those. &amp;ldquo;Inside Arbitrum Nitro&amp;rdquo; is for people who want to understand &quot; data-og-host=&quot;developer.arbitrum.io&quot; data-og-source-url=&quot;https://developer.arbitrum.io/inside-arbitrum-nitro/&quot; data-og-url=&quot;https://developer.arbitrum.io/inside-arbitrum-nitro/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/U1FsH/hySeWRHmmO/uQX4FxaElkHGZ3KNlfKhY1/img.png?width=1080&amp;amp;height=1080&amp;amp;face=0_0_1080_1080,https://scrap.kakaocdn.net/dn/cqrwKM/hySeX39F2z/DZsmf7zpPVa4dvezu4b1lk/img.png?width=1647&amp;amp;height=779&amp;amp;face=0_0_1647_779,https://scrap.kakaocdn.net/dn/dxA8go/hySe34mWGo/sfOfZPXsr39Pv5W5WsGuNK/img.png?width=1490&amp;amp;height=799&amp;amp;face=0_0_1490_799&quot;&gt;&lt;a href=&quot;https://developer.arbitrum.io/inside-arbitrum-nitro/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.arbitrum.io/inside-arbitrum-nitro/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/U1FsH/hySeWRHmmO/uQX4FxaElkHGZ3KNlfKhY1/img.png?width=1080&amp;amp;height=1080&amp;amp;face=0_0_1080_1080,https://scrap.kakaocdn.net/dn/cqrwKM/hySeX39F2z/DZsmf7zpPVa4dvezu4b1lk/img.png?width=1647&amp;amp;height=779&amp;amp;face=0_0_1647_779,https://scrap.kakaocdn.net/dn/dxA8go/hySe34mWGo/sfOfZPXsr39Pv5W5WsGuNK/img.png?width=1490&amp;amp;height=799&amp;amp;face=0_0_1490_799');&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;Inside Arbitrum Nitro | Arbitrum Documentation Center&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;This document is a deep-dive explanation of Arbitrum Nitro&amp;rsquo;s design and the rationale for it. This isn&amp;rsquo;t API documentation, nor is it a guided tour of the code--look elsewhere for those. &amp;ldquo;Inside Arbitrum Nitro&amp;rdquo; is for people who want to understand&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.arbitrum.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>DevOps/Chain</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/358</guid>
      <comments>https://tigercoin.tistory.com/358#entry358comment</comments>
      <pubDate>Tue, 11 Apr 2023 21:30:43 +0900</pubDate>
    </item>
    <item>
      <title>Wemix3.0 Testnet L1, Arbitrum L2 연결 테스트</title>
      <link>https://tigercoin.tistory.com/356</link>
      <description>&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;아비트럼이 현재 옵티미즘 롤업 기반 L2 사이에서 높은 TPS를 자랑한다. 많은 Layer 1 프로젝트들이 Layer 2 연구에 옵티미즘을 많이 사용하는 만큼, 가장 빠른 아비트럼으로 테스트를 진행해봤다.&lt;br /&gt;조만간 Orbit이 출시하면 더 친절한 자료들이 나오겠지만, 시급한 서비스 테스트를 위해 현재 Arbitrum Nitro를 L1인 위믹스3.0 테스트넷에 연결시켰다.&lt;br /&gt;&lt;a href=&quot;https://developer.arbitrum.io/node-running/local-dev-node&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span&gt;https://developer.arbitrum.io/node-running/local-dev-node&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;opengraph&quot; data-og-title=&quot;Running a local dev node | Arbitrum Documentation Center&quot; data-ke-align=&quot;alignCenter&quot; data-og-description=&quot;1. Install&quot; data-og-host=&quot;developer.arbitrum.io&quot; data-og-source-url=&quot;https://developer.arbitrum.io/node-running/local-dev-node&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cs0sz5/hyRY9YwzaL/V0xCsQHUjWDLSQxC5bKs91/img.png?width=1080&amp;amp;height=1080&amp;amp;face=0_0_1080_1080&quot; data-og-url=&quot;https://developer.arbitrum.io/node-running/local-dev-node&quot;&gt;&lt;a href=&quot;https://developer.arbitrum.io/node-running/local-dev-node&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.arbitrum.io/node-running/local-dev-node&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cs0sz5/hyRY9YwzaL/V0xCsQHUjWDLSQxC5bKs91/img.png?width=1080&amp;amp;height=1080&amp;amp;face=0_0_1080_1080');&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;Running a local dev node | Arbitrum Documentation Center&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;1. Install&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.arbitrum.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;위 링크에 들어가면 Local 환경에서 docker-compose로 손쉽게 sequencer와 validator, redis, blockscout까지 올려볼 수 있다. L1은 이더리움 노드가 실행되는데, 설정을 통해서 외부의 wemix3.0 테스트넷으로 지정해야한다.&lt;br /&gt;&lt;b&gt;실행에 있어 모든 설정은 test-node.bash 파일에서 가능하다.&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;# nitro/test-node.bash
#!/usr/bin/env bash

set -e

NITRO_NODE_VERSION=offchainlabs/nitro-node:v2.0.10-73224e3-dev
BLOCKSCOUT_VERSION=offchainlabs/blockscout:v1.0.0-c8db5b1

mydir=`dirname $0`
cd &quot;$mydir&quot;

num_volumes=`docker volume ls --filter label=com.docker.compose.project=nitro -q | wc -l`
docker stop $(docker ps -a -q)
docker rm $(docker ps -a -q)
docker volume rm $(docker volume ls -q)

l1chainid=1111
tokenbridge=false

...&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;docker 컨테이너 실행을 위해, 전에 실행했던 컨테이너를 stop, rm, 이어서 디펜던시를 줄이기 위해 컨테이너 실행에서 사용된 volume도 한번에 지워야한다. l1chainid는 wemix3.0 테스트넷의 디폴트 chainId가 1111이므로 수정해주며, Ethereum L1과 호환되는 tokenbridge는 false로 설정한다.&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;docker-compose run --entrypoint /usr/local/bin/deploy poster --l1conn &amp;lt;L1_RPC_NODE&amp;gt;&amp;nbsp;&amp;nbsp;--l1keystore /home/user/l1keystore --sequencerAddress $sequenceraddress --ownerAddress $sequenceraddress --l1DeployAccount $sequenceraddress --l1deployment /config/deployment.json --authorizevalidators 10 --wasmrootpath /home/user/target/machines --l1chainid=&amp;lt;L1_ChainId&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;시퀀서가 L1에 컨트랙트를 배포할 명령어를 위와같이 수정한다. L1의 RPC 노드 앤드포인트와 ChainId를 수정해준다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;추가로 bridgefund, l1, l2 command 실행을 위해 testnode-scripts/index.ts에서 아래 l1 엔드포인트를 설정해준다.&lt;/p&gt;
&lt;pre id=&quot;code_1679970445369&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;async function main() {
  await Yargs(hideBin(process.argv))
    .options({
      redisUrl: { string: true, default: &quot;redis://redis:6379&quot; },
      l1url: { string: true, default: &quot;ws://geth:8546&quot; }, // wemix endpoint로
      l2url: { string: true, default: &quot;ws://sequencer:8548&quot; },
    })&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;중요한 것은 배포과정에서 sequencer account에 WEMIX가 충분히 있어야한다. 미리 L1에서 WEMIX를 충분히 넣어줘야한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2010&quot; data-origin-height=&quot;630&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0fktg/btr40SqdqC6/NIlBpzSf08kvB4XPxSkre0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0fktg/btr40SqdqC6/NIlBpzSf08kvB4XPxSkre0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0fktg/btr40SqdqC6/NIlBpzSf08kvB4XPxSkre0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0fktg%2Fbtr40SqdqC6%2FNIlBpzSf08kvB4XPxSkre0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2010&quot; height=&quot;630&quot; data-origin-width=&quot;2010&quot; data-origin-height=&quot;630&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;Funding Validator, Sequencer 과정에서 transaction underpriced 에러가 뜨는데, 이는 nitro/testnode-scripts/ethcommnads.ts에서 gasLimit과 gasPrice를 수정해주면 해결할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const response = await
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;account.sendTransaction({
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;to: namedAddress(argv.to, threadId),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;value: ethers.utils.parseEther(argv.ethamount),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data: argv.data,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;nonce: startNonce + index,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;gasLimit: 300000,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;gasPrice: 300000000000
&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;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;나는 위와같이 gas 값을 설정했다.&lt;br /&gt;아비트럼은 트랜잭션이 없을 경우 블록을 생성하지 않는다. 그럴만 한 것이 시퀀서는 l2 트랜잭션을 받아서 l1에 batch를 보내기 때문에 받은 L1에 올라간 트랜잭션이 없으면 벨리데이터도 블록 생성할 필요가 없다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2022&quot; data-origin-height=&quot;1160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cdWOlW/btr42Tol1Bu/X2AVjaWkVP2j0qIizBUkp1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cdWOlW/btr42Tol1Bu/X2AVjaWkVP2j0qIizBUkp1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cdWOlW/btr42Tol1Bu/X2AVjaWkVP2j0qIizBUkp1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcdWOlW%2Fbtr42Tol1Bu%2FX2AVjaWkVP2j0qIizBUkp1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2022&quot; height=&quot;1160&quot; data-origin-width=&quot;2022&quot; data-origin-height=&quot;1160&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;준비가 되면 트랜잭션을 시퀀서에 반복적으로 보내면 위와같이 정상적으로 트랜잭션이 submit되고 블록도 생성된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1361&quot; data-origin-height=&quot;827&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bMEkyI/btr42AbdR3K/fjigMEFa8oMc473VCAD4Ek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMEkyI/btr42AbdR3K/fjigMEFa8oMc473VCAD4Ek/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMEkyI/btr42AbdR3K/fjigMEFa8oMc473VCAD4Ek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMEkyI%2Fbtr42AbdR3K%2FfjigMEFa8oMc473VCAD4Ek%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1361&quot; height=&quot;827&quot; data-origin-width=&quot;1361&quot; data-origin-height=&quot;827&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;함께 생성된 blockscout에서도 BatchPostingReport를 확인할 수 있다.&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;404&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJ7yac/btr40FYKyl8/tKIIhFbdczEm2MVwFJHtN0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJ7yac/btr40FYKyl8/tKIIhFbdczEm2MVwFJHtN0/img.png&quot; data-alt=&quot;L2 시퀀서의 Balance&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJ7yac/btr40FYKyl8/tKIIhFbdczEm2MVwFJHtN0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJ7yac%2Fbtr40FYKyl8%2FtKIIhFbdczEm2MVwFJHtN0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/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;404&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;404&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;L2 시퀀서의 Balance&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;시퀀서 account를 보면 L2에서는 트랜잭션 fee를 받기 때문에 잔고가 계속해서 증가하고, L1에서 계속해서 calldata를 전송하기 때문에 수수료가 사용되어 잔고가 줄어드는 것을 확인할 수 있다.&lt;/b&gt;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DevOps/Chain</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/356</guid>
      <comments>https://tigercoin.tistory.com/356#entry356comment</comments>
      <pubDate>Mon, 20 Mar 2023 21:31:02 +0900</pubDate>
    </item>
    <item>
      <title>EKS Kubeconfig 다중 클러스터 적용하기</title>
      <link>https://tigercoin.tistory.com/353</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #172b4d;&quot;&gt;kubeconfig 파일을 생성하여 EKS 클러스터 API 서버와 통신할 수 있도록 구성한다. cluster를 컨트롤할 bastion 서버에는 aws cli, kubectl가 미리 설치되어 있어야한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #172b4d;&quot;&gt;(혹시 기존에 config 파일이 존재했다면, 삭제하고 재설정하는 것을 권장)&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;kubectl 설치 (아래 aws 공식문서 참고)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/&lt;/a&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1678195813339&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 기존 버전 설치되어 있는 지 확인
$ kubectl version | grep Client | cut -d : -f 5

# kubernetes amd 64 1.23버전 다운 (linux)
$ curl -o kubectl https://s3.us-west-2.amazonaws.com/amazon-eks/1.23.7/2022-06-29/bin/linux/amd64/kubectl

# 실행 권한
$ chmod +x ./kubectl

# PATH 폴더에 복사
$ mkdir -p $HOME/bin &amp;amp;&amp;amp; cp ./kubectl $HOME/bin/kubectl &amp;amp;&amp;amp; export PATH=$PATH:$HOME/bin

# 버전 확인
$ kubectl version --short --client&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;aws cli 설치&lt;/h4&gt;
&lt;pre id=&quot;code_1678195858729&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ curl &quot;https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip&quot; -o &quot;awscliv2.zip&quot;
$ unzip awscliv2.zip
$ sudo ./aws/install
$ ./aws/install -i /usr/local/aws-cli -b /usr/local/bin&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이어서 aws access key와 secret access key를 설정한다.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;372&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;EKS 클러스터가 생성이 되면 아래 명령어를 통해서 kubeconfig파일을 생성한다.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1678195875253&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ aws eks --region &amp;lt;region-code&amp;gt; update-kubeconfig --name &amp;lt;cluster_name&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kubeconfig 파일은 ~/.kube/config에 위치하며 구성으론 크게 clusters / contexts / users 로 구분된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-indent-level=&quot;1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;clusters : 클러스터 인증 정보&lt;/li&gt;
&lt;li&gt;contexts : clusters와 users의 조합으로 namespace 지정이 가능&lt;/li&gt;
&lt;li&gt;users : 사용자 eks로 iam에 대한 인증 정보를 토큰 값으로 저장&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;eks cluster 확인&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1678195897817&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ kubectl config get-contexts
$ kubectl config get-clusters&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;1825&quot; data-origin-height=&quot;412&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWilPR/btr2voTp9xp/gpBLPDKxFHpo7YhKAKzhH1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWilPR/btr2voTp9xp/gpBLPDKxFHpo7YhKAKzhH1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWilPR/btr2voTp9xp/gpBLPDKxFHpo7YhKAKzhH1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWilPR%2Fbtr2voTp9xp%2FgpBLPDKxFHpo7YhKAKzhH1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1825&quot; height=&quot;412&quot; data-origin-width=&quot;1825&quot; data-origin-height=&quot;412&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;사용 중인 eks cluster 확인&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1678195951124&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ kubectl config current-context&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;eks cluster 변경&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1678195960989&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ kubectl config use-context &amp;lt;context-name&amp;gt;
$ kubectl config set-cluster &amp;lt;cluster-name&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;등록된 eks cluster 삭제&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1678195971472&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ kubectl config delete-context &amp;lt;context-name&amp;gt;
$ kubectl config delete-cluster &amp;lt;cluster-name&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DevOps/Kubernetes</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/353</guid>
      <comments>https://tigercoin.tistory.com/353#entry353comment</comments>
      <pubDate>Tue, 7 Mar 2023 22:33:00 +0900</pubDate>
    </item>
    <item>
      <title>Quorum 체인 enableGasPrice 가스비 설정하기</title>
      <link>https://tigercoin.tistory.com/352</link>
      <description>&lt;p data-renderer-start-pos=&quot;3489&quot; data-ke-size=&quot;size16&quot;&gt;쿼럼은 기본적으로 gas 비용이 없는 프라이빗 체인으로 운영된다. 만약 가스비가 트랜잭션 처리에 요구되도록 설정한다면 가스비를 보상으로 수령할 주체도 필요하다.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3489&quot; data-ke-size=&quot;size16&quot;&gt;여기서 보상은 두가지로 구분되는데, 1) 트랜잭션 비용 2) 블록 생성 이다. 이는 genesis.json에서 transition block을 추가하여 설정해야한다.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3678&quot; data-ke-size=&quot;size16&quot;&gt;(참고로, coinbase에 account를 추가하거나, eth.coinbase에서 출력되는 account 또한 사실상 의미없다)&lt;/p&gt;
&lt;h4 id=&quot;1)-트랜잭션-비용-보상-(Transaction-cost-rewards)&quot; data-renderer-start-pos=&quot;3712&quot; data-ke-size=&quot;size20&quot;&gt;1) 트랜잭션 비용 보상 (Transaction cost rewards)&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-renderer-start-pos=&quot;3754&quot; data-ke-size=&quot;size16&quot;&gt;트랜잭션 전송에 사용되는 가스비로, 트랜잭션을 전송하는 주체가 부담하는 비용이다. 이 비용은 beneficiaryMode 로 설정된다.&lt;/p&gt;
&lt;h4 id=&quot;2)-블록-생성-보상&quot; data-renderer-start-pos=&quot;3831&quot; data-ke-size=&quot;size20&quot;&gt;2) 블록 생성 보상&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-renderer-start-pos=&quot;3844&quot; data-ke-size=&quot;size16&quot;&gt;각 블록을 생성할 때 벨리데이터에게 수령되는 보상이다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 id=&quot;+-Reward-Config(Transaction-보상)&quot; data-renderer-start-pos=&quot;3877&quot; data-ke-size=&quot;size20&quot;&gt;Reward Config 예시 (Transaction 보상, QBFT)&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1678103764796&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&quot;transitions&quot;: [{
     &quot;block&quot;: 0,
     &quot;miningBeneficiary&quot;: &quot;{{ transaction reward address }}&quot;,
     &quot;beneficiaryMode&quot;:&quot;fixed&quot;
   }]&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-indent-level=&quot;1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;block : 앞으로 보상 정책이 적용될 미래 blocknumber&lt;/li&gt;
&lt;li&gt;miningBeneficiary : 블록 생성 보상을 수령받는 어카운트를 설정한다.&lt;/li&gt;
&lt;li&gt;beneficiaryMode : 트랜잭션 가스비를 수령받는 벨리데이터 혹은 어카운트를 설정한다.&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;1100&quot; data-origin-height=&quot;460&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cjAcAR/btr2tDPbMi0/r5WY4M3YyONW73V58fAcxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cjAcAR/btr2tDPbMi0/r5WY4M3YyONW73V58fAcxK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cjAcAR/btr2tDPbMi0/r5WY4M3YyONW73V58fAcxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcjAcAR%2Fbtr2tDPbMi0%2Fr5WY4M3YyONW73V58fAcxK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1100&quot; height=&quot;460&quot; data-origin-width=&quot;1100&quot; data-origin-height=&quot;460&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설정 결과, 트랜잭션 1회 발생에서 &lt;span style=&quot;background-color: #ffffff; color: #505f79;&quot;&gt;21000 * 500000000000 = 1.05e + 16(0.0105 ETH) 가스비가 사용되었음.&lt;/span&gt;&lt;/p&gt;</description>
      <category>DevOps/Chain</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/352</guid>
      <comments>https://tigercoin.tistory.com/352#entry352comment</comments>
      <pubDate>Mon, 6 Mar 2023 20:58:56 +0900</pubDate>
    </item>
    <item>
      <title>Hashicorp Vault 서버 배포하기</title>
      <link>https://tigercoin.tistory.com/351</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;체인의 키를 안전하게 관리하기 위해서 많이들 사용하는 Hashicorp의 Vault 배포 과정을 간단히 정리해보려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 볼트 서버를 올리는 것은 간단하지만, Policy나 Secret Engine을 효율적으로 사용하고, Plugin을 적용하는 과정이 쉽지 않다. (관련해서는 다음 포스팅에 하나씩 정리해보려고 함)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Vault는 튜토리얼에서 dev 버전으로 간단히 올릴 수 있지만, 데이터를 memory에 저장하고 Unseal 상태가 디폴트기 때문에 실제 프로덕션 단계에서는 적합하지 않다. 아래는 실제 환경의 Vault를 배포하는 것을 정리한다.&lt;/b&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. Configuration&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Vault 서버의 구성파일을 먼저 작성한다. 아래와 같이 스토리지와 API 요청받을 리스너를 입력해준다.&lt;/p&gt;
&lt;pre id=&quot;code_1677671049835&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;## config.json

storage &quot;raft&quot; {
  path    = &quot;./vault/data&quot;
  node_id = &quot;node1&quot;
}

listener &quot;tcp&quot; {
  address     = &quot;127.0.0.1:8200&quot;
  tls_disable = &quot;true&quot;
}

api_addr = &quot;http://127.0.0.1:8200&quot;
cluster_addr = &quot;https://127.0.0.1:8201&quot;
ui = true&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-indent-level=&quot;1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;storage : 볼트가 물리적인 백엔드로 사용할 스토리지 설정&lt;/li&gt;
&lt;li&gt;listener : API 요청을 받을 리스너 설정, TLS가 disable되어 있으나 실제 운용시에는 필수로 적용해야하며 환경변수 VAULT_ADDR에 해당 리스너 URL을 지정해야한다.&lt;/li&gt;
&lt;li&gt;api_addr : 클라이언트의 요청을 받을 주소&lt;/li&gt;
&lt;li&gt;cluster_addr : 볼트 노드들 간의 통신을 위해 지정하는 주소와 port&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. Start Server&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 Config 파일에서 Storage의 디렉토리를 생성한다.&lt;/p&gt;
&lt;pre id=&quot;code_1677671170324&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ mkdir -p ./vault/data&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #172b4d;&quot;&gt;config 파일을 적용하여 서버를 실행한다. 여기서 mlock 에러가 발생 시, sudo로 실행하거나 위 config 파일에 &lt;/span&gt;disable_mlock = true&lt;span style=&quot;background-color: #ffffff; color: #172b4d;&quot;&gt; 를 추가하여 mlock을 disable한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1677671185893&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ vault server -config=config.hcl&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3. Initializing the Vault&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #172b4d;&quot;&gt;초기화는 서버가 아닌 클러스터 당 한번씩 진행하는 과정으로, encrytion key와 unseal key, initial root token이 생성된다. 터미널 세션 시작을 위해 VAULT_ADDR 환경변수를 지정한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1677671221389&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ export VAULT_ADDR='http://127.0.0.1:8200'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #172b4d;&quot;&gt;이어서 vault을 초기화하는 명령어를 실행한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1677671231696&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ vault operator init&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #172b4d;&quot;&gt;다음과 같아 생성된 key와 token이 출력되는 결과화면이 나온다.&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;1084&quot; data-origin-height=&quot;592&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWXx54/btr01THuq48/XROjKxEQuw33ZGR8HIZkm1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWXx54/btr01THuq48/XROjKxEQuw33ZGR8HIZkm1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWXx54/btr01THuq48/XROjKxEQuw33ZGR8HIZkm1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWXx54%2Fbtr01THuq48%2FXROjKxEQuw33ZGR8HIZkm1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1084&quot; height=&quot;592&quot; data-origin-width=&quot;1084&quot; data-origin-height=&quot;592&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Vault는 봉인된 상태가 디폴트로 설정된다. (서버를 종료할때도 기본적으로 sealing됨) 봉인을 해제하기 위해서는 위의 Unseal Key의 5개 중에 3개를 입력해야만 봉인이 해제된다. 이는 특정인 한 명이 서버를 통제하는 것을 막기 위함이다.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1193&quot; data-ke-size=&quot;size16&quot;&gt;Vault를 사용하려면 매번 Unseal 과정이 요구된다. 이는 API, command line을 통해서 진행될 수 있다.&lt;/p&gt;
&lt;h4 data-renderer-start-pos=&quot;1193&quot; data-ke-size=&quot;size20&quot;&gt;4. Seal/Unseal&lt;/h4&gt;
&lt;p data-renderer-start-pos=&quot;1193&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #172b4d;&quot;&gt;봉인 해제를 위해서 아래와 같은 명령어를 사용하면 된다. &lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1677671282991&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ vault operator unseal&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #172b4d;&quot;&gt;만약 Unseal Key에 유효한 값이 입력되면 아래와 같은 화면이 뜨게된다.&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;1114&quot; data-origin-height=&quot;606&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqPiMC/btr1yASTlpQ/DEhpXWmFvOfjixMm7BsFjK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqPiMC/btr1yASTlpQ/DEhpXWmFvOfjixMm7BsFjK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqPiMC/btr1yASTlpQ/DEhpXWmFvOfjixMm7BsFjK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqPiMC%2Fbtr1yASTlpQ%2FDEhpXWmFvOfjixMm7BsFjK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1114&quot; height=&quot;606&quot; data-origin-width=&quot;1114&quot; data-origin-height=&quot;606&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 Total Shares는 Unseal Key 수, Threshold는 Unseal하기 위한 최소한의 Key 수, 그리고 Unseal Progress는 현재 Unseal에 사용된 키 수다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1111&quot; data-origin-height=&quot;491&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KNafa/btr1ucSkRmk/4ztBdfFvvtz79KTZlvkwJK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KNafa/btr1ucSkRmk/4ztBdfFvvtz79KTZlvkwJK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KNafa/btr1ucSkRmk/4ztBdfFvvtz79KTZlvkwJK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKNafa%2Fbtr1ucSkRmk%2F4ztBdfFvvtz79KTZlvkwJK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1111&quot; height=&quot;491&quot; data-origin-width=&quot;1111&quot; data-origin-height=&quot;491&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1497&quot; data-ke-size=&quot;size16&quot;&gt;Unseal이 완료되면 위와 같은 화면이 뜨게된다. &lt;span style=&quot;background-color: #ffffff; color: #172b4d;&quot;&gt;이제 Vault 서버가 Unseal되었기 때문에 접속할 수 있는 상태가 되었다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1677671333376&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ vault login&lt;/code&gt;&lt;/pre&gt;
&lt;div data-layout=&quot;center&quot; data-width=&quot;100&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div&gt;
&lt;div data-context-id=&quot;329187336&quot; data-type=&quot;file&quot; data-node-type=&quot;media&quot; data-width=&quot;502&quot; data-height=&quot;220&quot; data-id=&quot;6f002bc1-6a24-4f90-95b3-bae155b963cc&quot; data-collection=&quot;contentId-329187336&quot; data-file-name=&quot;image-20230223-064900.png&quot; data-file-size=&quot;113958&quot; data-file-mime-type=&quot;image/png&quot; data-alt=&quot;&quot;&gt;
&lt;div id=&quot;newFileExperienceWrapper&quot; data-testid=&quot;media-card-view&quot;&gt;
&lt;div data-testid=&quot;media-file-card-view&quot; data-test-status=&quot;complete&quot; data-test-media-name=&quot;image-20230223-064900.png&quot; data-test-progress=&quot;1&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #172b4d;&quot;&gt;위 명령어를 입력하면 token을 기입하라는 메시지가 나오는데, 처음 initialize에서 생성된 root token을 입력하면 된다. root token이 유효하면 아래와 같이 로그인되었다는 결과화면이 나오게 된다.&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;497&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/p30TD/btr1p2oRuGV/qxx7O8NfyKmrwO28FGMMGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/p30TD/btr1p2oRuGV/qxx7O8NfyKmrwO28FGMMGK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/p30TD/btr1p2oRuGV/qxx7O8NfyKmrwO28FGMMGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fp30TD%2Fbtr1p2oRuGV%2Fqxx7O8NfyKmrwO28FGMMGK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/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;497&quot; data-origin-width=&quot;1138&quot; data-origin-height=&quot;497&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;</description>
      <category>DevOps/Vault</category>
      <category>blockchain</category>
      <category>Chain</category>
      <category>hashicorp</category>
      <category>Vault</category>
      <category>볼트</category>
      <category>블록체인</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/351</guid>
      <comments>https://tigercoin.tistory.com/351#entry351comment</comments>
      <pubDate>Wed, 1 Mar 2023 20:50:38 +0900</pubDate>
    </item>
    <item>
      <title>Quorum Blockchain Transaction 지연시간 테스트 (Latency Test)</title>
      <link>https://tigercoin.tistory.com/350</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;Latency&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;블록체인의 확장성을 평가할 때 가장 많이 언급되는 TPS(Transaction per Seconds)는 말 그대로 1초에 몇 개의 트랜잭션을 처리하는 지를 확인하는 지표다. 하지만 단순히 TPS로만 평가하기엔 부족하다. 전송된 트랜잭션이 포함된 블록이 생성되어야, 실제 트랜잭션이 처리되었다고 판단할 수 있기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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 style=&quot;letter-spacing: 0px;&quot;&gt; 실행되기까지 걸리는 시간을 블록이 생성된 시간으로 평가하기 위해서 Latency를 &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;체크해야 한다.&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt; Latency는 처리량보다 지연시간을 기준으로 체인의 확장성을 평가하는 주요 지표라고 볼 수 &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;있다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Quorum Blockchain&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿼럼은 JP모건에서 개발하고 현재 Consensys에서 인수하여 지속적으로 디벨롭 중인 Private Blockchain이다. 크게 3가지의 합의알고리즘을 지원하고 있다. 엔터프라이즈 용으로 많이 사용하기 때문에 높은 확장성을 보이지만, 지정된 노드만이 Validator로 참여할 수 있기 때문에 아주 낮은 수준의 탈중앙화로 구현되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Consensys에서는 QBFT가 Consensys에서 엔터프라이즈 용으로 가장 완성도가 높은 합의 알고리즘이며 IBFT는 보안적인 부분에서 한 단계 아래의 알고리즘이라고 하며, RAFT는 개발/테스트 용도로 사용하는 것을 권장하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 세 합의 알고리즘의 Latency를 확인해보았다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Latency Test&lt;/h3&gt;
&lt;pre id=&quot;code_1677069163602&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; ...
    const start = new Date().getTime()
    data.startTime = start

    await web3.eth
    .sendSignedTransaction(EncodedTx) 
    .then(function(receipt){
      PrevNonce = latestNonce
      data.txhash = receipt.transactionHash
      const end = new Date().getTime()
      data.endTime = end
      data.latency = end-start
     })
      
  ...&lt;/code&gt;&lt;/pre&gt;
&lt;div data-layout=&quot;default&quot;&gt;
&lt;div&gt;
&lt;div&gt;주요 코드 부분을 시간 순서도 설명하면,&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;getTime을 통해서 현재 시간을 ms단위의 숫자로 받는다.&lt;/li&gt;
&lt;li&gt;sendSignedTransaction()을 통해서 16진수로 인코딩된 서명된 트랜잭션을 전송한다.&lt;/li&gt;
&lt;li&gt;전송된 트랜잭션이 포함된 블록이 생성되면 응답받는 receipt를 기준으로 getTime을 실행한다&lt;/li&gt;
&lt;li&gt;1) 와 3)의 차이만큼을 Latency로 선언한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-number-column=&quot;false&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: 18.3721%; text-align: center;&quot;&gt;&lt;b&gt;ms \ Consensus&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25.3488%; text-align: center;&quot;&gt;&lt;b&gt;QBFT&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 27.0931%; text-align: center;&quot;&gt;&lt;b&gt;IBFT&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 29.0698%; text-align: center;&quot;&gt;&lt;b&gt;RAFT&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 18.3721%; text-align: center;&quot; data-colwidth=&quot;157&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;Latency 1&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 25.3488%; text-align: center;&quot; data-colwidth=&quot;200&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;2040&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 27.0931%; text-align: center;&quot; data-colwidth=&quot;213&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;5042&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 29.0698%; text-align: center;&quot; data-colwidth=&quot;190&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;16&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 18.3721%; text-align: center;&quot; data-colwidth=&quot;157&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;Latency 2&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 25.3488%; text-align: center;&quot; data-colwidth=&quot;200&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;1046&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 27.0931%; text-align: center;&quot; data-colwidth=&quot;213&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;3032&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 29.0698%; text-align: center;&quot; data-colwidth=&quot;190&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;21&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 18.3721%; text-align: center;&quot; data-colwidth=&quot;157&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;Latency 3&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 25.3488%; text-align: center;&quot; data-colwidth=&quot;200&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;2046&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 27.0931%; text-align: center;&quot; data-colwidth=&quot;213&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;4038&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 29.0698%; text-align: center;&quot; data-colwidth=&quot;190&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;21&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 18.3721%; text-align: center;&quot; data-colwidth=&quot;157&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;Latency 4&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 25.3488%; text-align: center;&quot; data-colwidth=&quot;200&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;3037&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 27.0931%; text-align: center;&quot; data-colwidth=&quot;213&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;7041&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 29.0698%; text-align: center;&quot; data-colwidth=&quot;190&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;27&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 18.3721%; text-align: center;&quot; data-colwidth=&quot;157&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;Latency 5&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 25.3488%; text-align: center;&quot; data-colwidth=&quot;200&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;1040&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 27.0931%; text-align: center;&quot; data-colwidth=&quot;213&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;4036&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 29.0698%; text-align: center;&quot; data-colwidth=&quot;190&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;20&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 18.3721%; text-align: center;&quot; data-colwidth=&quot;157&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;&lt;b&gt;평균&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 25.3488%; text-align: center;&quot; data-colwidth=&quot;200&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;&lt;b&gt;1841&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 27.0931%; text-align: center;&quot; data-colwidth=&quot;213&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;&lt;b&gt;4637&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 29.0698%; text-align: center;&quot; data-colwidth=&quot;190&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;&lt;b&gt;21&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-renderer-start-pos=&quot;2263&quot; data-ke-size=&quot;size16&quot;&gt;테스트 결과, QBFT는 1.841초, IBFT는 4.637초, RAFT는 0.021초라는 평균 지연시간을 확인할 수 있었다.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2263&quot; data-ke-size=&quot;size16&quot;&gt;물론 QBFT와 IBFT는 blockperiod(블록 생성시간, s), RAFT는 raftblocktime(블록 생성시간, ms) 값에 따라서 지연시간의 차이가 있을 수 있으나, 모두 최소값으로 설정했다는 점을 참고하길 바란다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 85px;&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: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px; text-align: center;&quot;&gt;&lt;b&gt;QBFT&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px; text-align: center;&quot;&gt;&lt;b&gt;IBFT&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px; text-align: center;&quot;&gt;&lt;b&gt;RAFT&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 34px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 34px; text-align: center;&quot;&gt;Instance type&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 34px; text-align: center;&quot;&gt;c5.xlarge(4 vCPU, 8GiB Memory)&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 34px; text-align: center;&quot;&gt;c5.xlarge(4 vCPU, 8GiB Memory)&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 34px; text-align: center;&quot;&gt;c5.xlarge(4 vCPU, 8GiB Memory)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px; text-align: center;&quot;&gt;The number of validator&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px; text-align: center;&quot;&gt;7&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px; text-align: center;&quot;&gt;7&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px; text-align: center;&quot;&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px; text-align: center;&quot;&gt;blocktime&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px; text-align: center;&quot;&gt;1 second&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px; text-align: center;&quot;&gt;1 second&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px; text-align: center;&quot;&gt;1 millisecond&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS을 활용했고, 체인 퍼포먼스에 최적화된 스펙은 아니다. 그래서 스케일업으로 지연시간과 TPS의 성능도 조금 더 개선될 수 있다고 생각한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;868&quot; data-origin-height=&quot;290&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k7RHP/btr0pwxZim7/1CL1ih5G2p38XCYdglaww0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k7RHP/btr0pwxZim7/1CL1ih5G2p38XCYdglaww0/img.png&quot; data-alt=&quot;Raft 테스트 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k7RHP/btr0pwxZim7/1CL1ih5G2p38XCYdglaww0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk7RHP%2Fbtr0pwxZim7%2F1CL1ih5G2p38XCYdglaww0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;868&quot; height=&quot;290&quot; data-origin-width=&quot;868&quot; data-origin-height=&quot;290&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Raft 테스트 결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 테스트에서 네트워크 상태 체크를 위한 간단한 쿼리를 보내 응답받는 시간을 체크하는 것도 중요할 듯하다.&lt;/p&gt;</description>
      <category>DevOps/Chain</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/350</guid>
      <comments>https://tigercoin.tistory.com/350#entry350comment</comments>
      <pubDate>Wed, 22 Feb 2023 21:53:32 +0900</pubDate>
    </item>
    <item>
      <title>Quorum의 Raft 합의 알고리즘</title>
      <link>https://tigercoin.tistory.com/349</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;Raft Consensus Algorithm&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1442&quot; data-origin-height=&quot;725&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgvWX5/btrZr0mu1sT/vIg7ik7Zl2DBkk3ZCpGlF1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgvWX5/btrZr0mu1sT/vIg7ik7Zl2DBkk3ZCpGlF1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgvWX5/btrZr0mu1sT/vIg7ik7Zl2DBkk3ZCpGlF1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbgvWX5%2FbtrZr0mu1sT%2FvIg7ik7Zl2DBkk3ZCpGlF1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1442&quot; height=&quot;725&quot; data-origin-width=&quot;1442&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;Raft는 이해하기 쉽게 디자인된 합의 알고리즘이라고 한다. fault-tolerance(내결함성)와 Performance(성능) 면에서 우수하여 다수의 노드를 클러스터링하는데 많이 사용한다. 대표적으로 etcd와 Hyperledger Fabric, ZooKeeper, Haddop, 요즘 내가 관심이 많은 Quorum 체인에서도 사용되고 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Raft는 합의 알고리즘을 3가지 문제를 나눠서 해결한다. 1) 리더 선출 2) 로그 복제 3) 안정성 보장 이 해결방법이 하나의 컨센서스 모듈로 구현된다고 볼 수 있다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1) Leader Election&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1068&quot; data-origin-height=&quot;702&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/D2lwj/btrZqGWQ5BS/5xsWLNQEQgv2eMzHHEpVxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/D2lwj/btrZqGWQ5BS/5xsWLNQEQgv2eMzHHEpVxk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/D2lwj/btrZqGWQ5BS/5xsWLNQEQgv2eMzHHEpVxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FD2lwj%2FbtrZqGWQ5BS%2F5xsWLNQEQgv2eMzHHEpVxk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1068&quot; height=&quot;702&quot; data-origin-width=&quot;1068&quot; data-origin-height=&quot;702&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 노드는 특정 순간에 하나의 상태를 가지게된다. 모두가 임기 마다 3가지 중에 하나의 역할을 가지는데, 이 임기(Term) 마다 하나의 리더를 선출해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 리더(Leader) : 클러스터는 하나의 리더와 N-1개의 팔로워로 구성되며 리더는 모든 요청을 수신받아 로그를 보관하고 모든 팔로워들에게 전달한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 팔로워(Follwer) : 팔로워는 클라이언트로부터 받은 요청을 리더에게 재전송하고, 리더의 요청은 다시 수신하여 처리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 후보(Candidate) : 다음 임기의 리더 후보다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리더는 주기적으로 heartbeat 메시지를 노드들에게 전파한다. 이 때 노드가 일정 시간동안 리더로부터 메시지를 수신하지 못하면 1) 리더를 새로 선출하는 선거를 진행하거나 2) 본인이 스스로 후보가 되어 자신에게 투표하고 다른 노드들에게 투표 요청 메시지(RequestVote)를 보낸다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 말하는 메시지는 RPC 프로토콜로 함수를 요청하는 것을 말한다. 각 임기는 매번 선거로 시작하고, 스스로 후보가 되어 선거하는 경우는 3가지로 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) 과반수의 투표를 받아 당선&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) 다른 노드가 리더가 되는 경우 (이 경우는 본인이 제출한 임기 번호보다 높은 번호로 당선된 리더가 있을 때, 후보에서 팔로워로 상태 변경후 리더로 등록한다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) 승자가 없이 투표가 종료되는 경우(모든 노드가 스스로에게 투표하여 투표가 결렬되는 경우)&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2) Log Replication&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1082&quot; data-origin-height=&quot;664&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SSZsY/btrZo7HdLq0/eEc2h7x4psOUwPi4VcfnrK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SSZsY/btrZo7HdLq0/eEc2h7x4psOUwPi4VcfnrK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SSZsY/btrZo7HdLq0/eEc2h7x4psOUwPi4VcfnrK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSSZsY%2FbtrZo7HdLq0%2FeEc2h7x4psOUwPi4VcfnrK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1082&quot; height=&quot;664&quot; data-origin-width=&quot;1082&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;Raft의 로그는 위치 값과 임기 번호, 상태 변경 명령의 세 가지로 구성된 Entry의 집합이다. 동일한 인덱스와 임기 번호가 같으면 같은 명령을 저장해야한다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3) Safety&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;팔로워가 리더가 커밋한 메시지를 수신받지 못하면 본인 스스로 리더가 되어 메시지를 덮어버리는 상황이 발생할 수 있다. 이를 막기 위해 여러 방법이 고안되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;선거제약 방법은 리더의 커밋을 보장하는 방법을 통해 안정성을 구현한다. 후보 노드가 당선되기 위해서 클러스터 내 다수의 노드에게 연락해야한다. 연락한 노드들의 다수는 커밋된 로그를 반드시 가지고 있어야하는데, 투표 요청은 후보의 로그가 인자값으로 존재한다. 그래서 투표자는 본인의 임기 번호가 더 높거나 로그 인덱스가 더 큰 경우엔 해당 투표 요청을 거부하게 된다. 이로써 모든 당선된 리더는 반드시 커밋된 로그를 가지고 있음을 보장하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;커밋 규칙은 현재 임기의 메시지가 복제되어야지만 커밋으로 간주하여 안정성을 달성한다. 이전 임기의 메시지가 단순히 과반수 이상의 노드에 복제되어서 발생할 수 있는 문제를 해결할 수 있는데, 커밋은 상태 머신이 어떤 엔트리를 실행할 지 결정하는 값이기 때문에 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ssup2.github.io/theory_analysis/Raft_Consensus_Algorithm/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://ssup2.github.io/theory_analysis/Raft_Consensus_Algorithm/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/curg/raft-consensus-이해-가능한-합의-알고리즘을-위한-여정-f7ecb9f450ab&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://medium.com/curg/raft-consensus-이해-가능한-합의-알고리즘을-위한-여정-f7ecb9f450ab&lt;/a&gt;&lt;/p&gt;</description>
      <category>DevOps/Chain</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/349</guid>
      <comments>https://tigercoin.tistory.com/349#entry349comment</comments>
      <pubDate>Wed, 15 Feb 2023 22:15:25 +0900</pubDate>
    </item>
    <item>
      <title>Ansible UNREACHABLE! Failed to connect to the host via ssh Load key Permission denied (publickey) 오류</title>
      <link>https://tigercoin.tistory.com/348</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;aws의 ec2에 간단한 ping 테스트하려는데 갑자기 아래와 같은 오류가 발생했다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;878&quot; data-origin-height=&quot;211&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4lgTw/btrXQKZggum/nKiM3vbBnwxcuNH9Ip0zHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4lgTw/btrXQKZggum/nKiM3vbBnwxcuNH9Ip0zHK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4lgTw/btrXQKZggum/nKiM3vbBnwxcuNH9Ip0zHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4lgTw%2FbtrXQKZggum%2FnKiM3vbBnwxcuNH9Ip0zHK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;878&quot; height=&quot;211&quot; data-origin-width=&quot;878&quot; data-origin-height=&quot;211&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pem 키 권한 문제도 아닌 것이, 동일한 키로 로컬 pc에서 테스트하면 ssh 접속엔 문제가 없었다. 알고보니, 해당 서버의 pem 파일문제였던 것!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리눅스에서 파일을 생성하지 않고, 사용하던 키 파일을 전송했더니 아래와 같이 테스트가 잘된다...&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;877&quot; data-origin-height=&quot;233&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blFDgf/btrXPVNtTbd/HPlwC04arB3IpYikwAmQrk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blFDgf/btrXPVNtTbd/HPlwC04arB3IpYikwAmQrk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blFDgf/btrXPVNtTbd/HPlwC04arB3IpYikwAmQrk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblFDgf%2FbtrXPVNtTbd%2FHPlwC04arB3IpYikwAmQrk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;877&quot; height=&quot;233&quot; data-origin-width=&quot;877&quot; data-origin-height=&quot;233&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;</description>
      <category>DevOps/Ansible</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/348</guid>
      <comments>https://tigercoin.tistory.com/348#entry348comment</comments>
      <pubDate>Wed, 1 Feb 2023 21:58:41 +0900</pubDate>
    </item>
    <item>
      <title>Quorum 블록체인의 Tessera Config 구성 정리</title>
      <link>https://tigercoin.tistory.com/347</link>
      <description>&lt;h2 id=&quot;테세라(Tessera)&quot; data-renderer-start-pos=&quot;220&quot; data-ke-size=&quot;size26&quot;&gt;테세라(Tessera)&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;234&quot; data-ke-size=&quot;size16&quot;&gt;테세라는 프라이빗 트랜잭션을 암호화, 복호화하는 자바 프로그램으로, 무상태성이며 JDBC 클라이언트와 연결될 수 있다. 테세라는 아래 4개의 서비스로 구성될 수 있다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-indent-level=&quot;1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Tessera Peer to Peer&lt;/li&gt;
&lt;li&gt;Tessera Third Party&lt;/li&gt;
&lt;li&gt;Tessera Admin&lt;/li&gt;
&lt;li&gt;Tessera Quorum to Tessera&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;Tessera-Peer-to-Peer&quot; data-renderer-start-pos=&quot;425&quot; data-ke-size=&quot;size23&quot;&gt;Tessera Peer to Peer&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-renderer-start-pos=&quot;447&quot; data-ke-size=&quot;size16&quot;&gt;이 서비스는 Tessera node간 통신을 위해 사용된다. 이 서비스를 활성화하기 위해서 tessera config 파일에 아래 section을 넣어야 한다.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;538&quot; data-ke-size=&quot;size16&quot;&gt;CommunicationType의 REST와 app의 P2P는 P2P 서비스를 위한 설정이다. auto-discovery를 true로 설정하면 하나의 노드만 연결해도 다른 노드들의 세부 정보를 불러올 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1675166569805&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
&amp;ldquo;app&amp;rdquo;: &amp;ldquo;P2P&amp;rdquo;,
&amp;ldquo;enabled&amp;rdquo;: true,
&amp;ldquo;serverAddress&amp;rdquo;: &amp;ldquo;http://HOST_IP:9000&quot;,
&amp;ldquo;sslConfig&amp;rdquo;: {
&amp;ldquo;tls&amp;rdquo;: &amp;ldquo;OFF&amp;rdquo;
},
&amp;ldquo;communicationType&amp;rdquo;: &amp;ldquo;REST&amp;rdquo;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;Tessera-Third-Party&quot; data-renderer-start-pos=&quot;792&quot; data-ke-size=&quot;size23&quot;&gt;Tessera Third Party&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-renderer-start-pos=&quot;813&quot; data-ke-size=&quot;size16&quot;&gt;외부 어플리케이션의 암호화된 페이로드를 보관하는데 사용된다. 로우 트랜잭션 전송에도 같은 서비스가 사용된다.&lt;/p&gt;
&lt;pre id=&quot;code_1675166626224&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
&amp;ldquo;app&amp;rdquo;: &amp;ldquo;ThirdParty&amp;rdquo;,
&amp;ldquo;enabled&amp;rdquo;: true,
&amp;ldquo;serverAddress&amp;rdquo;: &amp;ldquo;http://HOST_IP:9080&quot;,
&amp;ldquo;communicationType&amp;rdquo;: &amp;ldquo;REST&amp;rdquo;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;Tessera-Admin&quot; data-renderer-start-pos=&quot;986&quot; data-ke-size=&quot;size23&quot;&gt;Tessera Admin&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-renderer-start-pos=&quot;1001&quot; data-ke-size=&quot;size16&quot;&gt;테세라 어플리케이션을 변경하기 위해 사용된다.&lt;/p&gt;
&lt;pre id=&quot;code_1675166635659&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
&amp;ldquo;app&amp;rdquo;: &amp;ldquo;ADMIN&amp;rdquo;,
&amp;ldquo;enabled&amp;rdquo;: true,
&amp;ldquo;serverAddress&amp;rdquo;: &amp;ldquo;http://HOST_IP:9090&quot;,
&amp;ldquo;communicationType&amp;rdquo;: &amp;ldquo;REST&amp;rdquo;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;Tessera-Quorum-to-Tessera&quot; data-renderer-start-pos=&quot;1135&quot; data-ke-size=&quot;size23&quot;&gt;Tessera Quorum to Tessera&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-renderer-start-pos=&quot;1162&quot; data-ke-size=&quot;size16&quot;&gt;Quorum node들과의 인터렉션을 위해 사용된다. Unix socket을 사용하여 노드간 통신한다.&lt;/p&gt;
&lt;pre id=&quot;code_1675166644029&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
&amp;ldquo;app&amp;rdquo;: &amp;ldquo;Q2T&amp;rdquo;,
&amp;ldquo;enabled&amp;rdquo;: true,
&amp;ldquo;serverAddress&amp;rdquo;: &amp;ldquo;unix:/qdata/tm.ipc&amp;rdquo;,
&amp;ldquo;communicationType&amp;rdquo;: &amp;ldquo;REST&amp;rdquo;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;Configuration-items&quot; data-renderer-start-pos=&quot;1324&quot; data-ke-size=&quot;size26&quot;&gt;Configuration items&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-indent-level=&quot;1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;mode : tessera&lt;/li&gt;
&lt;li&gt;useWhiteList : 지정된 피어 이외의 연결은 제한, peer 리스트의 연결만 허용&lt;/li&gt;
&lt;li&gt;jdbc : 데이터베이스 연결&lt;/li&gt;
&lt;li&gt;serverConfigs : Enblave, P2P, Q2T, ThirdParty 설정 각 서버는 TLS와 InfluxDB의 API 메트릭 저장 지원&lt;/li&gt;
&lt;li&gt;peer : 테세라 노드들의 URL list&lt;/li&gt;
&lt;li&gt;keys : key 경로 및 설정&lt;/li&gt;
&lt;li&gt;alwaysSendTo : 모든 트랜잭션의 복사본을 특정 노드로 전송, 감사 목적으로 활용될 수 있음&lt;/li&gt;
&lt;li&gt;bootstrapNode : 부트스트랩노드 사용&lt;/li&gt;
&lt;li&gt;unixSocketFile : Unix socket 파일의 경로&lt;/li&gt;
&lt;li&gt;features : security&amp;amp;privacy 추가 옵션 지정&lt;/li&gt;
&lt;li&gt;encryptor : 암호화 유형 설정&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Tessera-config.json 예제&lt;/h4&gt;
&lt;pre id=&quot;code_1675166664583&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
    &quot;mode&quot;: &quot;${TESSERA_MODE}&quot;,
    &quot;useWhiteList&quot;: false,
    &quot;jdbc&quot;: {
        &quot;username&quot;: &quot;sa&quot;,
        &quot;password&quot;: &quot;&quot;,
        &quot;url&quot;: &quot;jdbc:h2:./data/tm/db;MODE=Oracle;TRACE_LEVEL_SYSTEM_OUT=0&quot;,
        &quot;autoCreateTables&quot;: true
    },
    &quot;serverConfigs&quot;: [
        {
            &quot;app&quot;: &quot;ThirdParty&quot;,
            &quot;enabled&quot;: true,
            &quot;serverAddress&quot;: &quot;http://${HOSTNAME}:9080&quot;,
            &quot;communicationType&quot;: &quot;REST&quot;
        },
        {
            &quot;app&quot;: &quot;Q2T&quot;,
            &quot;enabled&quot;: true,
            &quot;serverAddress&quot;: &quot;http://${HOSTNAME}:9101&quot;,
            &quot;sslConfig&quot;: {
                &quot;tls&quot;: &quot;OFF&quot;
            },
            &quot;communicationType&quot;: &quot;REST&quot;
        },
        {
            &quot;app&quot;: &quot;P2P&quot;,
            &quot;enabled&quot;: true,
            &quot;serverAddress&quot;: &quot;http://${HOSTNAME}:9000&quot;,
            &quot;sslConfig&quot;: {
                &quot;tls&quot;: &quot;OFF&quot;
            },
            &quot;communicationType&quot;: &quot;REST&quot;
        }
    ],
    &quot;peer&quot;: [
        {
            &quot;url&quot;: &quot;http://member1tessera:9000&quot;
        },
        {
            &quot;url&quot;: &quot;http://member2tessera:9000&quot;
        },
        {
            &quot;url&quot;: &quot;http://member3tessera:9000&quot;
        }
    ],
    &quot;keys&quot;: {
        &quot;passwords&quot;: [],
        &quot;keyData&quot;: [
            {
                &quot;privateKeyPath&quot;: &quot;/config/keys/tm.key&quot;,
                &quot;publicKeyPath&quot;: &quot;/config/keys/tm.pub&quot;
            }
        ]
    },
    &quot;alwaysSendTo&quot;: [],
    &quot;bootstrapNode&quot;: false,
    &quot;features&quot;: {
        &quot;enableRemoteKeyValidation&quot;: false,
        &quot;enablePrivacyEnhancements&quot;: false
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.tessera.consensys.net/en/stable/Reference/SampleConfiguration/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://docs.tessera.consensys.net/en/stable/Reference/SampleConfiguration/&lt;/a&gt;&lt;/p&gt;</description>
      <category>DevOps/Chain</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/347</guid>
      <comments>https://tigercoin.tistory.com/347#entry347comment</comments>
      <pubDate>Tue, 31 Jan 2023 21:05:41 +0900</pubDate>
    </item>
    <item>
      <title>Quorum의 Private Transaction manager, Tessera 테세라란?</title>
      <link>https://tigercoin.tistory.com/346</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;쿼럼(quorum)은 JP모건에서 높은 확장성 구현을 위해 이더리움을 하드포크하여 개발한 엔터프라이즈 블록체인이다. 각 노드는 전체 네트워크 합의를 기다리지 않고, 신뢰할 수 있는 특정 노드만이 합의하여 확장성을 크게 개선할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오픈소스기 때문에 많은 기업과 서비스들이 쿼럼을 활용해서 프라이빗 체인을 운용하고 테스트 중에 있는 것으로 보인다.쿼럼같은 엔터프라이즈 체인은 프라이버시가 중요한데, 이를 Tessera 라는 Private Transaction Manager가 역할을 해주고 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Tessera&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테세라는 Consensys가 개발하고 있으며 Goquorum과 Hyperledger Besu에 사용되는 트랜잭션 매니저다. 주요 역할은 아래와 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다른 트랜잭션 매니저와 함께 P2P 네트워크 구현&lt;/li&gt;
&lt;li&gt;Key Management와 데이터 암호화/복호화를 enclave에 위임&lt;/li&gt;
&lt;li&gt;DB로부터 데이터를 저장&lt;/li&gt;
&lt;li&gt;&lt;b&gt;이더리움 클라이언트를 위한 프라이빗 트랜잭션 페이로드 배포&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주로 프라이버시가 설정된 이더리움 클라이언트로부터 받은 페이로드를 배포하는 역할을 한다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Normal private transactions&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1219&quot; data-origin-height=&quot;1119&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cWVepM/btrXgxtQYhR/sLw59Ut2sGyh2OUcKo9C91/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cWVepM/btrXgxtQYhR/sLw59Ut2sGyh2OUcKo9C91/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cWVepM/btrXgxtQYhR/sLw59Ut2sGyh2OUcKo9C91/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcWVepM%2FbtrXgxtQYhR%2FsLw59Ut2sGyh2OUcKo9C91%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1219&quot; height=&quot;1119&quot; data-origin-width=&quot;1219&quot; data-origin-height=&quot;1119&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;일반적인 프라이빗 트랜잭션은 위와같은 라이프사이클로 이루어져있다.&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Participant A가 프라이빗 트랜잭션을 GoQuorum Node A에 전송한다.&lt;/li&gt;
&lt;li&gt;GoQuorum Node A는 데이터를 JSON으로 직렬화하여 Tessera A에 보낸다.&lt;/li&gt;
&lt;li&gt;Tessera A는 data를 암호화하고 그것을 다른 Tessera Node에 전송한다.&lt;/li&gt;
&lt;li&gt;Tessera는 암호화 처리된 data를 GoQuorum Node A에 다시 리턴하고 GoQuorum은 기존 데이터를 암호화된 데이터로 대체한다. 그리고 GoQuorum은 프라이빗 트랜잭션에 사인한다&lt;/li&gt;
&lt;li&gt;GoQuorum은 프라이빗 트랜잭션을 전체 네트워크에 배포한다.&lt;/li&gt;
&lt;li&gt;모든 노드는 트랜잭션을 확인할 수 있다. 그러나 Private transaction을 전송받은 Tessera Node A와 B만 복호화된 원본 데이터를 실행할 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Privacy maker transactions&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1198&quot; data-origin-height=&quot;1106&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yYiPB/btrXjC8jbiU/BVq9c8FUvAhT8YVSB5lMIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yYiPB/btrXjC8jbiU/BVq9c8FUvAhT8YVSB5lMIk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yYiPB/btrXjC8jbiU/BVq9c8FUvAhT8YVSB5lMIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyYiPB%2FbtrXjC8jbiU%2FBVq9c8FUvAhT8YVSB5lMIk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1198&quot; height=&quot;1106&quot; data-origin-width=&quot;1198&quot; data-origin-height=&quot;1106&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Participant A는 GoQuorum Node A에 프라이빗 트랜잭션을 전송한다.&lt;/li&gt;
&lt;li&gt;GoQuorum A는 트랜잭션의 data 값을 JSON으로 직렬화하여 Participant A의 세부 정보와 함께 Tessera A로 보낸다.&lt;/li&gt;
&lt;li&gt;Tessera A는 이를 암호화하여 data 거래의 참여자들에게 배포한다.&lt;/li&gt;
&lt;li&gt;Tessera는 암호화된 data 해시값을 GoQuorum Node A에 리턴한다. GoQuorum은 data 해시 값과 함께 pulbic PMT를 만들고 PMT에 사인한다.&lt;/li&gt;
&lt;li&gt;GoQuorum은 전체 네트워크에 PMT를 배포한다. 모든 노드는 PMT를 볼 수 있다. (PMT는 퍼블릭 트랜잭션과 같은 방법으로 처리된다. PMT의 to 값은 프라이버시 컨트랙트의 주소)&lt;/li&gt;
&lt;li&gt;GoQuorum node B와 C는 PMT와 함께 프라이버시 프리컴파일을 호출한다.&lt;/li&gt;
&lt;li&gt;GoQuorum은 PMT로부터 공개적으로 사용 가능한 해시를 사용하여 Tessera를 통해 복호화된 프라이버시 트랜잭션을 받기 위한 시도를 한다.&lt;/li&gt;
&lt;li&gt;프라이버시 트랜잭션을 받을 수 있는 여부는 트랜잭션 참여자 노드인지에 따라 결정된다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;8번에서 트랜잭션 참여자일 경우에는 복호화된 data를 얻게된다. 물론 이는 Tessera로부터 주어지며 프라이버시 프리컴파일이 트랜잭션을 실행한다. 반면, 참여자가 아닌 경우 복호화된 데이터를 받을 수 없다.&lt;/p&gt;</description>
      <category>DevOps/Chain</category>
      <author>vataops</author>
      <guid isPermaLink="true">https://tigercoin.tistory.com/346</guid>
      <comments>https://tigercoin.tistory.com/346#entry346comment</comments>
      <pubDate>Thu, 26 Jan 2023 21:31:05 +0900</pubDate>
    </item>
  </channel>
</rss>