<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>하루한방울</title>
    <link>https://gunjoon.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Tue, 14 Jul 2026 18:39:04 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>gunjoon98</managingEditor>
    <image>
      <title>하루한방울</title>
      <url>https://tistory1.daumcdn.net/tistory/5504742/attach/2c5965850e2f4b19875afa044de9d112</url>
      <link>https://gunjoon.tistory.com</link>
    </image>
    <item>
      <title>정규화</title>
      <link>https://gunjoon.tistory.com/214</link>
      <description>&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;정규화&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;정규화란 이상 현상이 발생하지 않도록, 릴레이션을 분해하는 과정을 말한다.&amp;nbsp;&lt;/b&gt;데이터베이스 설계 또는 설계 결과를 검증하는 용도로 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 설계 방법 중 적절한 방법을 선택하자.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;E-R 모델과 릴레이션 변환 규칙&lt;/li&gt;
&lt;li&gt;정규화&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;이상 (Anomaly)&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 중복이 발생하여 릴레이션에 대한 데이터 삽입, 수정, 삭제 연산 시의 부작용을 말한다. 정규화 과정을 진행하면 이상 현상이 제거된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이상 현상의 종류&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;삽입 이상 : 새 데이터를 삽입하기 위해 불필요한 데이터도 함께 삽입해야 하는 문제&lt;/li&gt;
&lt;li&gt;갱신 이상 : 중복 튜플 중 일부만 변경하여 데이터가 불일치되는 문제&lt;/li&gt;
&lt;li&gt;삭제 이상 : 튜플을 삭제하면 꼭 필요한 데이터까지 함께 삭제되는 문제&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;결정자&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 릴레이션을 구성하는 속성들의 부분 집합을 X와 Y라고 하자. 어느 시점에서든 &lt;b&gt;X값에 대한 Y값이 항상 하나&lt;/b&gt;면 &quot;X가 Y를 함수적으로 결정한다&quot; 또는 &quot;Y는 X에 함수적 종속되어있다&quot;라고 표현하며 &lt;b&gt;X를 결정자, Y를 종속자&lt;/b&gt;라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본키 또는 후보키는 키의 특성(유일성)으로 다른 모든 속성을 함수적으로 결정한다. 하지만 기본키나 후보키만이 결정자가 되는 것은 아니며 키가 아닌 속성도 결정자가 될 수 있다. 당연하게도 결정자가 같으면 그와 연관된 종속자의 값은 같아야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;가능하면 릴레이션에서 기본키와 후보키만이 결정자가 되도록 릴레이션을 분해하는 것이 정규화이다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1243&quot; data-origin-height=&quot;377&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHUJDk/btsJVEM3q1w/PLS1XrEgEbFNWuTpeA6wx0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHUJDk/btsJVEM3q1w/PLS1XrEgEbFNWuTpeA6wx0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHUJDk/btsJVEM3q1w/PLS1XrEgEbFNWuTpeA6wx0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHUJDk%2FbtsJVEM3q1w%2FPLS1XrEgEbFNWuTpeA6wx0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1243&quot; height=&quot;377&quot; data-origin-width=&quot;1243&quot; data-origin-height=&quot;377&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;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;완전 함수 종속 : 속성 집합 Y가 속성 집합 X 전체에 종속되어 있음, X 집합 일부분에 종속된 것이 아님&lt;/li&gt;
&lt;li&gt;부분 함수 종속 : 속성 집합 Y가 속성 집합 X 일부분에도 종속되어 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그림의 함수 종속 다이어그램을 보면 당첨여부는 완전 함수 종속되어 있으며, 고객이름은 부분 함수 종속되어 있다. 물론 고객 이름도 (고객 아이디, 이벤트 번호)에 종속되어 있다.&lt;/p&gt;
&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;제 1 정규형&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;릴레이션에 속한 모든 속성은 원자 값을 가진다. 릴레이션은 모든 속성이 원자 값을 가져야만 한다.&lt;/p&gt;
&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;제 2 정규형&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;릴레이션이 제 1 정규형에 속하고, 기본키가 아닌 모든 속성이&lt;b&gt; 기본키에 완전 함수 종속되면 &lt;/b&gt;제 2 정규형에 속한다. 부분 함수 종속을 제거하고 모든 속성이 기본키에 완전 함수 종속되도록 릴레이션을 분해하는 과정을 수행하면 제 2 정규형이 된다.&lt;/p&gt;
&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;제 3 정규형&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;릴레이션이 제 2 정규형에 속하고, 기본키가 아닌 모든 속성이 &lt;b&gt;기본키에 이행적 함수 종속이 되지 않으면&lt;/b&gt; 제 3 정규형에 속한다. 이행적 함수 종속이란 3개의 속성 집합 X, Y, Z에 대해 함수 종속 관계 X &amp;rarr; Y, Y &amp;rarr; Z가 존재하면 논리적으로 X &amp;rarr; Z가 성립하며, 이때 속성 집합 Z는 X에 이행적으로 함수 종속되었다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본키가 아닌 다른 속성이 결정자가 되면, 하나의 릴레이션에 종속 관계가 여러 개 생기게 되며, 이로 인해 이행적 함수 종속이 나타날 수 있다.&lt;/p&gt;
&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;보이스/코드 정규형&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BCNF(Boyce/Codd Normal Form)은 제 3 정규형보다 좀 더 엄격한 제약조건을 제시하며 강한 제3정규형이라고도 한다. BCNF를 만족하면 제3정규형에 속하기 때문이다. 반대로 제 3 정규형을 만족해도 BCNF를 만족하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;릴레이션의 함수 종속 관계에서 &lt;b&gt;후보키만이 결정자&lt;/b&gt;가 되면 BCNF에 속한다. 릴레이션은 후보키를 여러개 가질 수 있는데 이때 이상 현상을 방지하기 위해서는 BCNF가 되어야 한다.&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>Computer Science/DataBase</category>
      <author>gunjoon98</author>
      <guid isPermaLink="true">https://gunjoon.tistory.com/214</guid>
      <comments>https://gunjoon.tistory.com/214#entry214comment</comments>
      <pubDate>Sun, 6 Oct 2024 16:44:15 +0900</pubDate>
    </item>
    <item>
      <title>B Tree, B+ Tree</title>
      <link>https://gunjoon.tistory.com/213</link>
      <description>&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;서론&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;B Tree와 B+ Tree는 이진 탐색 트리를 확장해 하나의 노드가 2개 이상의 자식을 가질 수 있게 만든 트리이며 주로 &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;하드 디스크는 블록 단위로 읽기/쓰기 작업을 수행한다. DB의 모든 행은 블록에 저장된다. 만약 특정 행을 조회하는 쿼리를 수행하려면 행이 저장된 모든 블록을 모두 탐색해야하는데 이는 비효율적이다. 그래서 &lt;b&gt;인덱스&lt;/b&gt;를 사용한다. 행의 키를 키로, 블록 주소를 값으로 갖는 인덱스를 사용한다. 인덱스가 저장된 블록 + 1개의 행이 저장된 블록만 탐색하면 되므로 탐색할 블록 개수가 줄어든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;제목 없음.png&quot; data-origin-width=&quot;957&quot; data-origin-height=&quot;901&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bI6rGx/btsJlWGwnZr/064aLZCaMw8wWMYZod9A81/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bI6rGx/btsJlWGwnZr/064aLZCaMw8wWMYZod9A81/img.png&quot; data-alt=&quot;https://youtu.be/aZjYr87r1b8 강의&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bI6rGx/btsJlWGwnZr/064aLZCaMw8wWMYZod9A81/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbI6rGx%2FbtsJlWGwnZr%2F064aLZCaMw8wWMYZod9A81%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;471&quot; data-filename=&quot;제목 없음.png&quot; data-origin-width=&quot;957&quot; data-origin-height=&quot;901&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://youtu.be/aZjYr87r1b8 강의&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;&lt;b&gt;인덱스를 위한 인덱스&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;행이 많아지면 인덱스 블록 개수도 증가한다. 때문에 인덱스를 위한 인덱스(high level index)를 둔다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;제목 없음.png&quot; data-origin-width=&quot;794&quot; data-origin-height=&quot;555&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kCL37/btsJk8HHmEV/MvJUwr3EiWSt28MyERQHb1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kCL37/btsJk8HHmEV/MvJUwr3EiWSt28MyERQHb1/img.png&quot; data-alt=&quot;https://youtu.be/aZjYr87r1b8 강의&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kCL37/btsJk8HHmEV/MvJUwr3EiWSt28MyERQHb1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkCL37%2FbtsJk8HHmEV%2FMvJUwr3EiWSt28MyERQHb1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;419&quot; data-filename=&quot;제목 없음.png&quot; data-origin-width=&quot;794&quot; data-origin-height=&quot;555&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://youtu.be/aZjYr87r1b8 강의&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;DB 행이 증가할수록 인덱스를 계속 만들 것이고, &lt;b&gt;결국 인덱스들은 트리 구조를 형성하며 탐색할 블록 개수는 줄어든다.&lt;/b&gt; 때문에 DB 또는 파일 시스템이 인덱스 저장 용도로 트리를 사용한다.&lt;/p&gt;
&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;M-Way Search Tree&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 트리를 M-Way Search Tree로 표현할 수 있다. M-Way Search Tree란 한 노드가 M개의 자식을 가지며 M-1개의 키를 갖는 탐색 트리를 말한다. BST가 2-Way Search Tree이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;제목 없음.png&quot; data-origin-width=&quot;1223&quot; data-origin-height=&quot;804&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uz8Y6/btsJmLdanzq/A6dsLQEeyaSh3zRthDHBLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uz8Y6/btsJmLdanzq/A6dsLQEeyaSh3zRthDHBLK/img.png&quot; data-alt=&quot;https://youtu.be/aZjYr87r1b8 강의&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uz8Y6/btsJmLdanzq/A6dsLQEeyaSh3zRthDHBLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fuz8Y6%2FbtsJmLdanzq%2FA6dsLQEeyaSh3zRthDHBLK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;394&quot; data-filename=&quot;제목 없음.png&quot; data-origin-width=&quot;1223&quot; data-origin-height=&quot;804&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://youtu.be/aZjYr87r1b8 강의&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;탐색 트리의 중요한 점은 균형을 유지해야한다. 균형이 깨질 경우 최악의 경우 시간 복잡도가 매우 증가한다. 때문에 스스로 균형을 맞추는 B 트리, B+ 트리를 사용한다.&lt;/p&gt;
&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;B 트리, B+ 트리&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;B 트리 특징&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;내부 노드는 ceil(M/2) ~ M개의 자식을 가져야만 하며, 최대 M개의 자식을 가질 수 있는 B 트리를 M차 B 트리라고 함&lt;/li&gt;
&lt;li&gt;모든 리프 노드들은 같은 레벨에 존재&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;B 트리의 모든 노드는 키에 해당하는 DB 행이 저장된 블록 주소(RP)를 가지고 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;images_seanlion_post_5181e745-362f-489d-be13-2cb2e61ce581_Screen Shot 2021-01-08 at 5.05.29 PM.png&quot; data-origin-width=&quot;1582&quot; data-origin-height=&quot;962&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/D50Fu/btsJn7AC4hi/PyPjtOF0y7rAkfn9CVpOq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/D50Fu/btsJn7AC4hi/PyPjtOF0y7rAkfn9CVpOq1/img.png&quot; data-alt=&quot;https://youtu.be/aZjYr87r1b8 강의&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/D50Fu/btsJn7AC4hi/PyPjtOF0y7rAkfn9CVpOq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FD50Fu%2FbtsJn7AC4hi%2FPyPjtOF0y7rAkfn9CVpOq1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;650&quot; height=&quot;395&quot; data-filename=&quot;images_seanlion_post_5181e745-362f-489d-be13-2cb2e61ce581_Screen Shot 2021-01-08 at 5.05.29 PM.png&quot; data-origin-width=&quot;1582&quot; data-origin-height=&quot;962&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://youtu.be/aZjYr87r1b8 강의&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;&lt;b&gt;B+ 트리 특징&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;B+ 트리는 오직 리프 노드에서만 레코드 포인터를 가짐, 대신 리프 노드에 모든 키들이 존재&lt;/li&gt;
&lt;li&gt;모든 리프노드는 연결리스트처럼 연결됨&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리프 노드까지 내려가야만 탐색이 완료된다는 단점이 있지만, &lt;b&gt;범위 탐색&lt;/b&gt;을 빠르게 할 수 있다는 장점이 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;images_seanlion_post_411ddf88-7e5f-4994-81e2-1fdbae09d3fd_Screen Shot 2021-01-08 at 5.10.54 PM.png&quot; data-origin-width=&quot;1630&quot; data-origin-height=&quot;882&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjHGUf/btsJnZims2d/Ewxxkg4RwU8LhsEP7iIbMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjHGUf/btsJnZims2d/Ewxxkg4RwU8LhsEP7iIbMk/img.png&quot; data-alt=&quot;https://youtu.be/aZjYr87r1b8 강의&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjHGUf/btsJnZims2d/Ewxxkg4RwU8LhsEP7iIbMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjHGUf%2FbtsJnZims2d%2FEwxxkg4RwU8LhsEP7iIbMk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;379&quot; data-filename=&quot;images_seanlion_post_411ddf88-7e5f-4994-81e2-1fdbae09d3fd_Screen Shot 2021-01-08 at 5.10.54 PM.png&quot; data-origin-width=&quot;1630&quot; data-origin-height=&quot;882&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://youtu.be/aZjYr87r1b8 강의&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Computer Science/DataStructure</category>
      <author>gunjoon98</author>
      <guid isPermaLink="true">https://gunjoon.tistory.com/213</guid>
      <comments>https://gunjoon.tistory.com/213#entry213comment</comments>
      <pubDate>Fri, 30 Aug 2024 15:12:05 +0900</pubDate>
    </item>
    <item>
      <title>Hash</title>
      <link>https://gunjoon.tistory.com/212</link>
      <description>&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;해시&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인덱스의 범위가 상당히 큰데에 비해 사용되는 공간이 적은 경우를 생각해보자. 예를 들어 인덱스 범위가 1 ~ 1억인 경우 1억 크기 배열을 사용해야하는데 이는 공간 낭비이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 인덱스가 정수가 아닌 문자열이나 객체인 경우 어떻게 해야할까? 이 경우 해시 함수와 해시 테이블을 사용할만 하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;키로 원소를 O(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;해시 테이블 - 원소를 저장하고 있는 공간(배열)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;해시 함수 - 키를 해시 테이블의 인덱스로 바꾸는 함수&lt;/b&gt;. 키를 해시 테이블 인덱스로 쓸 수 있다면 해시 함수가 필요 없겠지만 보통 키의 범위가 너무 크고, 정수형이 아닐기 있기에 변환 함수인 해시 함수가 필요하다. 해시 함수의 결과값을 해시 값이라 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;충돌&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;서로 다른 키의 해시 값이 동일 할 때 충돌이 발생했다고 한다.&lt;/b&gt; 키의 범위가 해시 값 범위보다 크므로 충돌이 발생할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;Chaining : 동일 해시값 데이터들을 연결리스트로 묶어 저장하는 방식이다. 추가 메모리를 사용하며 구현이 단순하다. Java 8의 HashMap은 체이닝 기법을 사용한다. 충돌이 발생할 경우 연결리스트를 순회하기에 O(N)의 시간 복잡도가 소요된다.&lt;/li&gt;
&lt;li&gt;Open Addressing : 추가적인 메모리를 사용하는 체이닝 기법과 다르게 해시 테이블의 &lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;비어있는&lt;span&gt; &lt;/span&gt;&lt;/span&gt;공간을 찾아 넣는 방식이다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Computer Science/DataStructure</category>
      <author>gunjoon98</author>
      <guid isPermaLink="true">https://gunjoon.tistory.com/212</guid>
      <comments>https://gunjoon.tistory.com/212#entry212comment</comments>
      <pubDate>Mon, 29 Jul 2024 21:11:58 +0900</pubDate>
    </item>
    <item>
      <title>Heap</title>
      <link>https://gunjoon.tistory.com/211</link>
      <description>&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;Heap&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;힙은 힙 속성을 만족하는 완전 이진 트리(이진 힙의 경우)이다. 우선 순위가 가장 높은 원소를 빠르게 찾는 용도로 사용된다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;힙을 사용하면, 원소를 추가하는 연산, 가장 우선순위가 높은 연산을 O(logN)으로 수행할 수 있다. 우선순위가 가장 높은 수가 가장 큰수라면 최대힙, 가장 작은 수라면 최소힙이라 부른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;힙 속성 : 부모 노드는, 항상 자식 노드보다 우선순위가 높다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 힙은 힙 속성, 완전 이진 트리를 만족해야한다.&lt;/p&gt;
&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;BBST를 쓰면 안되나?&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BBST보다 힙이 훨씬 빠르다. BBST도 같은 시간 복잡도를 가지며, 심지어 우선 순위가 가장 낮은 원소도 가져올 수 있지만, 같은 시간 복잡도라도 힙은 간단한 작업을 수행하기에 더 빠르다. BBST는 트리의 균형을 맞추기 위해 복잡한 작업을 수행하여 더 느리다. 때문에 같은 일을 한다면 힙 대신 BBST를 쓰는 것은 좋지 않다.&lt;/p&gt;
&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;구현&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;힙은 완전 이진 트리이기 때문에 배열로 쉽게 구현할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열의 0번 인덱스를 루트 노드라 했을 때, i번 노드의 왼쪽 자식은 2 * i + 1, 오른쪽 자식은 2 * i + 2번이며 i번 노드의 부모는 (i-1) / 2번 노드이다. N개의 노드가 있다면 N크기의 배열로 힙을 구현할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;원소 삽입 &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;힙은 힙 속성과 완전 이진 트리 규칙을 만족해야한다. 루트 노드부터 시작해 리프 노드까지 교환해 내려간다면 힙 속성은 만족하지만 완전 이진 트리 규칙을 만족시키는 것이 까다롭다. 이때 &lt;b&gt;완전 이진 트리 규칙부터 만족시키면 쉽게 구현할 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 마지막 리프 노드에 원소를 넣는다(= 완전 이진 트리 규칙 만족)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 1번의 리프 노드부터 시작해 루트 노드까지 교환한다.(= 힙 속성 만족)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;최대 원소 꺼내기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;루트를 삭제한다. 그리고 원소 삽입과 같이 완전 이진 트리 규칙을 먼저 고려하는 것이 쉽다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 마지막 리프 노드를 루트 노드에 덮어 씌운다.(= 완전 이진 트리 규칙 만족)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 루트 노드부터 시작해 리프 노드까지 교환한다. 이때 자식 노드 중 우선 순위가 높은 노드와 교환한다.(= 힙 속성 만족)&lt;/p&gt;
&lt;pre id=&quot;code_1722049511383&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class PQ {
    static final int MAX_SIZE = 10000000;
    int[] arr;
    int size;

    PQ() {
        arr = new int[MAX_SIZE];
        size = 0;
    }

    void offer(int node) {
        arr[size] = node;
        size++;

        int cur = size-1;
        while(cur &amp;gt; 0) {
            int parent = (cur-1) / 2;
            if(arr[parent] &amp;gt;= arr[cur]) break;
            swap(cur, parent);
            cur = parent;
        }
    }

    int poll() {
        int top = arr[0];
        arr[0] = arr[size-1];
        size--;

        int cur = 0;
        int leftChild = cur * 2 + 1;
        int rightChild = cur * 2 + 2;
        while(leftChild &amp;lt; size) {
            int child = leftChild;
            if(rightChild &amp;lt; size &amp;amp;&amp;amp; arr[rightChild] &amp;gt; arr[child]) child = rightChild;

            if(arr[cur] &amp;gt;= arr[child]) break;

            swap(cur, child);
            cur = child;
            leftChild = cur * 2 + 1;
            rightChild = cur * 2 + 2;
        }
        return top;
    }

    boolean isEmpty() {
        return size == 0;
    }

    void swap(int idx1, int idx2) {
        int temp = arr[idx1];
        arr[idx1] = arr[idx2];
        arr[idx2] = temp;
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Computer Science/DataStructure</category>
      <author>gunjoon98</author>
      <guid isPermaLink="true">https://gunjoon.tistory.com/211</guid>
      <comments>https://gunjoon.tistory.com/211#entry211comment</comments>
      <pubDate>Wed, 24 Jul 2024 20:17:43 +0900</pubDate>
    </item>
    <item>
      <title>Git 히스토리 삭제</title>
      <link>https://gunjoon.tistory.com/210</link>
      <description>&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;Git 히스토리 삭제&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GitLab의 저장소가 private라 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;기밀 정보가 들어간&lt;span&gt; application.propeties 파일을 넣으면서 작업했더니 나중에 Github로 미러링할 때 문제가 되었다. (기밀 정보는 넣지 말자)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순히 application.propeties 파일을 삭제하면 안된다. Git은 파일을 삭제하지 않는 구조일 뿐만 아니라 히스토리, 즉 이전 커밋들에 포함되어 있기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(더 상세하게 표현하면 커밋의 트리 파일에 기밀 정보가 포함된 application.propeties에 해당하는 blob 객체가 포함되어 있기 때문)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 명령어를 실행하자. 아래의 명령어는 지정한 파일 또는 폴더를 모든 브랜치와 태그에서 제거하고, 그 과정에서 비어 있는 커밋을 삭제한다. 이 명령어를 사용할 때는 저장소의 히스토리를 재작성하기에 주의해서 사용해야 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1717162278116&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch &amp;lt;파일 경로&amp;gt;' --prune-empty --tag-name-filter cat -- --all&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 후 아래의 명령어로 강제로 원격 저장소에 push 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1717162442513&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; git push origin --force --all&lt;/code&gt;&lt;/pre&gt;</description>
      <category>CM/Git</category>
      <author>gunjoon98</author>
      <guid isPermaLink="true">https://gunjoon.tistory.com/210</guid>
      <comments>https://gunjoon.tistory.com/210#entry210comment</comments>
      <pubDate>Fri, 31 May 2024 22:01:03 +0900</pubDate>
    </item>
    <item>
      <title>YARN</title>
      <link>https://gunjoon.tistory.com/206</link>
      <description>&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;YARN&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;YARN (Yet Another Resource Negotiator)은 하둡 2부터 도입된 클러스터 리소스 관리, 애플리케이션 라이프 사이클 관리를 위한 아키텍처이다. &lt;span style=&quot;background-color: #ffffff; color: #24292f; text-align: start;&quot;&gt;YARN에서는&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #24292f; text-align: start;&quot;&gt;맵리듀스 기반의 애플리케이션외에도 &lt;span style=&quot;background-color: #ffffff; color: #24292f; text-align: start;&quot;&gt;피그, 스톰, 스파크 등 분산 애플리케이션에 대해 클러스터 리소스를 관리 할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;1_B224XlLNk9DfagISzCithQ.jpg&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;540&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/roWFe/btsFD42JYzS/7RFcrAHD9nQSoBSVNiyKak/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/roWFe/btsFD42JYzS/7RFcrAHD9nQSoBSVNiyKak/img.webp&quot; data-alt=&quot;출처 : https://medium.com/@chenglong.w1/demystifying-yarn-understanding-its-architecture-components-and-how-it-works-738dd95ad453&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/roWFe/btsFD42JYzS/7RFcrAHD9nQSoBSVNiyKak/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FroWFe%2FbtsFD42JYzS%2F7RFcrAHD9nQSoBSVNiyKak%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;960&quot; height=&quot;540&quot; data-filename=&quot;1_B224XlLNk9DfagISzCithQ.jpg&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;540&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : https://medium.com/@chenglong.w1/demystifying-yarn-understanding-its-architecture-components-and-how-it-works-738dd95ad453&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;YARN 아키텍처의 세 가지 중요한 요소는 &lt;b&gt;리소스 매니저&lt;/b&gt;, &lt;b&gt;노드 매니저, &lt;/b&gt;&lt;b&gt;애플리케이션 마스터&lt;/b&gt;이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;1_84CHR1DLZUvFdmNRaJ2ncQ.jpg&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;540&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Zlbzx/btsFDzWbhq5/fm1Z8KIQ0vvk6qN0RG2tw0/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Zlbzx/btsFDzWbhq5/fm1Z8KIQ0vvk6qN0RG2tw0/img.webp&quot; data-alt=&quot;출처 : https://medium.com/@chenglong.w1/demystifying-yarn-understanding-its-architecture-components-and-how-it-works-738dd95ad453&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Zlbzx/btsFDzWbhq5/fm1Z8KIQ0vvk6qN0RG2tw0/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZlbzx%2FbtsFDzWbhq5%2Ffm1Z8KIQ0vvk6qN0RG2tw0%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;960&quot; height=&quot;540&quot; data-filename=&quot;1_84CHR1DLZUvFdmNRaJ2ncQ.jpg&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;540&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : https://medium.com/@chenglong.w1/demystifying-yarn-understanding-its-architecture-components-and-how-it-works-738dd95ad453&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;리소스 매니저&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리소스 매니저(Resource Manager)는 하둡 클러스터의 마스터 노드에 실행되는 자바 프로세서로 노드 매니저로부터 전달받은 정보를 이용하여&amp;nbsp;클러스터에서 CPU, 메모리, 디스크 등의 자원을 관리한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클러스터 상태 모니터링&amp;nbsp; : 클러스터 내 노드의 상태를 모니터링하고 노드 장애 발생 시 리소스 장애 조치 수행&lt;/li&gt;
&lt;li&gt;클러스터 자원 할당 : 애플리케이션 마스터로부터 자원 요청을 받아 애플리케이션 실행에 필요한 자원 할당&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리소스 매니저는 애플리케이션 마스터의 요청을 받아 자원을 할당하는데 이때 자원 할당을 위한 정책을 스케줄러라고 한다. FIFO, Fair, Capacity 스케줄러 등이 있으며 하둡 2의 기본 스케줄러는 Capacity 스케줄러이다. 스케줄러는 &lt;span style=&quot;background-color: #ffffff; color: #24292f; text-align: start;&quot;&gt;yarn-site.xml에서 설정할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;노드 매니저&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;노드 매니저(Node Manager)는 클러스터의 각 슬레이브(워커) 노드에서 실행되는 자바 프로세서로, 현재 노드의 자원 상태를 관리하고 리소스 매니저에 현재 자원 상태를 보고한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;노드 상태 보고 : 각 노드 매니저는 리소스 매니저에게 주기적으로 하트 비트를 보내 메모리 및 가상 코어를 포함한 노드 상태와 정보를 제공. 만약 노드에 장애가 발생하면 리소스 매니저에게 문제 보고&lt;/li&gt;
&lt;li&gt;컨테이너 시작 : 노드 매니저는 리소스 매니저의 지시를 받아 지정된 자원의 제약조건으로 컨테이너를 구축&lt;/li&gt;
&lt;li&gt;컨테이너 관리 : 노드 매니저는 컨테이너 라이프 사이클, 종속성, 리소스 사용량, 로그, 리스(leases)를 관리&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;애플리케이션 마스터&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애플리케이션 마스터(Application Master)는 Spark 드라이버 프로그램와 같은 애플리케이션 메인 함수를 실행하는 프로세스이다.&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;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;컨테이너&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨테이너는 클러스터의 워커 노드를 나타내는 추상화된 리소스 할당 단위이다. 컨테이너에서 MapReduce 작업 또는 Spark 작업와 같은 애플리케이션 작업을 실행한다.&amp;nbsp;각 컨테이너에는 CPU, 메모리, 디스크 공간 등의 리소스가 할당되어 있으며 컨테이너마다 격리된 환경에서 작업을 실행한다.&lt;/p&gt;
&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;YARN에서 애플리케이션이 실행되는 방식&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 YARN에서 Spark 애플리케이션을 실행할 때, 처리 과정을 나타낸 그림이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;그레이 레드 깔끔한 회사 소개 프레젠테이션의 사본 (1).gif&quot; data-origin-width=&quot;1152&quot; data-origin-height=&quot;648&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/br21x6/btsFWjY5oTG/YduRmfVLK7bfgyg2isKEo0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/br21x6/btsFWjY5oTG/YduRmfVLK7bfgyg2isKEo0/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/br21x6/btsFWjY5oTG/YduRmfVLK7bfgyg2isKEo0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/br21x6/btsFWjY5oTG/YduRmfVLK7bfgyg2isKEo0/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1152&quot; height=&quot;648&quot; data-filename=&quot;그레이 레드 깔끔한 회사 소개 프레젠테이션의 사본 (1).gif&quot; data-origin-width=&quot;1152&quot; data-origin-height=&quot;648&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;앱 실행 1 : 클라이언트는 spark-submit을 사용해 YARN 리소스 매니저에게 job을 제출한다. 제출된 job은 리소스 매니저의 스케줄러 대기열에 들어가 실행 되기를 기다린다.&lt;/li&gt;
&lt;li&gt;앱 실행 2 : job이 실행될 때가 되면 리소스 매니저는 컨테이너를 실행할 수 있는 노드 매니저를 찾고 애플리케이션 마스터(컨테이너)를 할당한다.&lt;/li&gt;
&lt;li&gt;앱 실행 3 : 애플리케이션 마스터는 드라이버 프로그램을 실행한다.&lt;/li&gt;
&lt;li&gt;앱 실행 4 : 애플리케이션 마스터는 작업에 필요한 리소스를 계산하고, 리소스 매니저에게 이그제큐터를 시작하도록 요청한다.&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;앱 실행 5 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;리소스 매니저는 요청받은 리소스에 맞춰 워커 노드에 이그제큐터 컨테이너를 할당한다.&lt;/li&gt;
&lt;li&gt;앱 실행 6 : 드라이버 프로그램은 이그제큐터 컨테이너에 task를 할당하고 task 상태를 추적한다.&lt;/li&gt;
&lt;li&gt;앱 실행 7 : 이그제큐터 컨테이너는 task를 실행하고 결과를 드라이버 프로그램으로 리턴한다. 드라이버 프로그램은 결과를 집계하여 최종 출력을 생성한다.&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 widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;1_bnW_o3Iz6dV2qR4G198cgQ.webp&quot; data-origin-width=&quot;828&quot; data-origin-height=&quot;509&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZFJCM/btsFGVRwu30/a4Hdn2AUzkMDeToo9vk6xK/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZFJCM/btsFGVRwu30/a4Hdn2AUzkMDeToo9vk6xK/img.webp&quot; data-alt=&quot;Spark YARN Cluster Mode&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZFJCM/btsFGVRwu30/a4Hdn2AUzkMDeToo9vk6xK/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZFJCM%2FbtsFGVRwu30%2Fa4Hdn2AUzkMDeToo9vk6xK%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;828&quot; height=&quot;509&quot; data-filename=&quot;1_bnW_o3Iz6dV2qR4G198cgQ.webp&quot; data-origin-width=&quot;828&quot; data-origin-height=&quot;509&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Spark YARN Cluster Mode&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;YARN 메모리 설정&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;YARN 메모리 설정은 yarn-site 파일을 수정하여 변경할 수 있다. 노드매니저의 메모리, CPU 개수와 컨테이너에 할당할 수 있는 최대, 최소 메모리 등을 설정할 수 있다. 기본 값은 yarn-default.xml 파일을 확인하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #24292f; text-align: left;&quot;&gt;yarn.nodemanager.resource.memory-mb&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;/li&gt;
&lt;li&gt;노드의 OS를 운영할 메모리를 제외하고 설정&lt;/li&gt;
&lt;li&gt;기본값은 장비에 설정된 메모리의 80%&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #24292f; text-align: left;&quot;&gt;yarn.nodemanager.resource.cpu-vcores&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;클러스터 각 노드에서 컨테이너 운영에 설정할 수 있는 CPU 코어 개수&lt;/li&gt;
&lt;li&gt;기본값은 장비에 설치된 CPU 코어의 80%&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #24292f; text-align: left;&quot;&gt;yarn.scheduler.maximum-allocation-mb&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;/li&gt;
&lt;li&gt;8G가 기본 값&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #24292f; text-align: left;&quot;&gt;yarn.scheduler.minimum-allocation-mb&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;/li&gt;
&lt;li&gt;1G가 기본 값&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #24292f; text-align: left;&quot;&gt;yarn.nodemanager.vmem-pmem-ratio&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;/li&gt;
&lt;li&gt;mapreduce.map.memory.mb * 설정값의 비율로 사용 가능&lt;/li&gt;
&lt;li&gt;메모리를 1G로 설정하고, 이 값을 10으로 설정하면 가상메모리를 10G 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #24292f; text-align: left;&quot;&gt;yarn.nodemanager.vmem-check-enabled&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #24292f; text-align: left;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가상 메모리에 대한 제한이 있는지 확인하여, true 일 경우 메모리 사용량을 넘어서면 컨테이너를 종료&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #24292f; text-align: left;&quot;&gt;yarn.nodemanager.pmem-check-enabled&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #24292f; text-align: left;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;물리 메모리에 대한 제한이 있는지 확인하여, true 일 경우 메모리 사용량을 넘어서면 컨테이너를 종료&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;참고&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/@chenglong.w1/demystifying-yarn-understanding-its-architecture-components-and-how-it-works-738dd95ad453&quot;&gt;https://medium.com/@chenglong.w1/demystifying-yarn-understanding-its-architecture-components-and-how-it-works-738dd95ad453&lt;/a&gt; &lt;/p&gt;
&lt;figure id=&quot;og_1710904994843&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;Demystifying YARN: Understanding Its Architecture, Components, and How It Works&quot; data-og-description=&quot;An In-Depth Guide to Hadoop YARN: Resource Management and Task Scheduling for Large-Scale Distributed Systems&quot; data-og-host=&quot;medium.com&quot; data-og-source-url=&quot;https://medium.com/@chenglong.w1/demystifying-yarn-understanding-its-architecture-components-and-how-it-works-738dd95ad453&quot; data-og-url=&quot;https://medium.com/@chenglong.w1/demystifying-yarn-understanding-its-architecture-components-and-how-it-works-738dd95ad453&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cvtjm4/hyVAHEfyg2/2kEKsygrCK9olmiPWrwFdk/img.png?width=960&amp;amp;height=540&amp;amp;face=0_0_960_540,https://scrap.kakaocdn.net/dn/hCyaq/hyVAFGpsQv/sFwaqb7tUPujWkNhCxD3Mk/img.png?width=960&amp;amp;height=540&amp;amp;face=0_0_960_540&quot;&gt;&lt;a href=&quot;https://medium.com/@chenglong.w1/demystifying-yarn-understanding-its-architecture-components-and-how-it-works-738dd95ad453&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://medium.com/@chenglong.w1/demystifying-yarn-understanding-its-architecture-components-and-how-it-works-738dd95ad453&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cvtjm4/hyVAHEfyg2/2kEKsygrCK9olmiPWrwFdk/img.png?width=960&amp;amp;height=540&amp;amp;face=0_0_960_540,https://scrap.kakaocdn.net/dn/hCyaq/hyVAFGpsQv/sFwaqb7tUPujWkNhCxD3Mk/img.png?width=960&amp;amp;height=540&amp;amp;face=0_0_960_540');&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;Demystifying YARN: Understanding Its Architecture, Components, and How It Works&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;An In-Depth Guide to Hadoop YARN: Resource Management and Task Scheduling for Large-Scale Distributed Systems&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;medium.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://eyeballs.tistory.com/82&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://eyeballs.tistory.com/82&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1710900216520&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;[Spark] YARN 위에서 Application 을 실행하는 단계&quot; data-og-description=&quot;스파크 어플리케이션이 YARN에서 실행되면 먼저 어플리케이션 마스터(Application Master) 프로세스가 생성이 되는 데 이것이 바로 Spark Driver를 실행하는 컨테이너가 됩니다. 그리고 이 Spark Driver가 YARN&quot; data-og-host=&quot;eyeballs.tistory.com&quot; data-og-source-url=&quot;https://eyeballs.tistory.com/82&quot; data-og-url=&quot;https://eyeballs.tistory.com/82&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/WQMBx/hyVDtK7hkJ/yI4gA2MClJNsAyjfa4cDfk/img.jpg?width=720&amp;amp;height=960&amp;amp;face=0_0_720_960,https://scrap.kakaocdn.net/dn/u4UYy/hyVAD2TvIQ/84fS6Jd6bfIGnx4otIYC5k/img.jpg?width=720&amp;amp;height=960&amp;amp;face=0_0_720_960,https://scrap.kakaocdn.net/dn/bNdvTq/hyVDIBuLLf/Yf3pC5Yav7vEwtUOsj3pk1/img.png?width=2048&amp;amp;height=846&amp;amp;face=0_0_2048_846&quot;&gt;&lt;a href=&quot;https://eyeballs.tistory.com/82&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://eyeballs.tistory.com/82&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/WQMBx/hyVDtK7hkJ/yI4gA2MClJNsAyjfa4cDfk/img.jpg?width=720&amp;amp;height=960&amp;amp;face=0_0_720_960,https://scrap.kakaocdn.net/dn/u4UYy/hyVAD2TvIQ/84fS6Jd6bfIGnx4otIYC5k/img.jpg?width=720&amp;amp;height=960&amp;amp;face=0_0_720_960,https://scrap.kakaocdn.net/dn/bNdvTq/hyVDIBuLLf/Yf3pC5Yav7vEwtUOsj3pk1/img.png?width=2048&amp;amp;height=846&amp;amp;face=0_0_2048_846');&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;[Spark] YARN 위에서 Application 을 실행하는 단계&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;스파크 어플리케이션이 YARN에서 실행되면 먼저 어플리케이션 마스터(Application Master) 프로세스가 생성이 되는 데 이것이 바로 Spark Driver를 실행하는 컨테이너가 됩니다. 그리고 이 Spark Driver가 YARN&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;eyeballs.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;</description>
      <category>Hadoop Echo System</category>
      <author>gunjoon98</author>
      <guid isPermaLink="true">https://gunjoon.tistory.com/206</guid>
      <comments>https://gunjoon.tistory.com/206#entry206comment</comments>
      <pubDate>Fri, 8 Mar 2024 15:57:21 +0900</pubDate>
    </item>
    <item>
      <title>스파크 애플리케이션 제출</title>
      <link>https://gunjoon.tistory.com/203</link>
      <description>&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;스파크 애플리케이션 제출&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spark bin 폴더의 spark-submit 스크립트로 사용자가 작성한 애플리케이션을 클러스터에 배포할 수 있다. spark-submit은 모든 클러스터 매니저와 같이 사용할 수 있으므로 클러스터 매니저에 따라 애플리케이션을 변경할 필요는 없다.&lt;/p&gt;
&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;종속성이 있는 애플리케이션 번들링&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 애플리케이션의 코드에 의존성이 있는 경우 의존성과 함께 코드를 패키징해야한다. 따라서 코드와 종속성을 포함하는 어셈블리 jar(또는 jber jar)을 만든다. 어셈블리 jar을 만들기 위해 sbt, maven와 같은 어셈블리 플러그인을 사용할 수 있다. 어셈블리 jar을 만들 때 Spark 및 Hadoop 종속성을 provided 종속성으로 지정한다. 클러스터 매니저가 런타임 시에 해당 종속성을 제공하므로 같이 번들로 묶을 필요가 없다.&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;파이썬의 경우, spark-submit의 --py-files 옵션을 사용해 애플리케이션과 함께 배포할 .py, .zip, .egg 파일을 추가할 수 있다. 여러 파이썬 파일에 의존하는 경우 .zip, .egg로 패키징하는 것이 좋다.&lt;/p&gt;
&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;Spark Submit&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;spark의 bin/spark-submit 스크립트로 애플리케이션을 클러스터에 배포, 제출할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1709523238027&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;./bin/spark-submit \
  --class &amp;lt;main-class&amp;gt; \
  --master &amp;lt;master-url&amp;gt; \
  --deploy-mode &amp;lt;deploy-mode&amp;gt; \
  --conf &amp;lt;key&amp;gt;=&amp;lt;value&amp;gt; \
  ... # other options
  &amp;lt;application-jar&amp;gt; \
  [application-arguments]&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;--class : 애플리케이션의 시작 클래스(e.g. org.apache.spark.examples.SparkPi)&lt;/li&gt;
&lt;li&gt;--master : 클러스터의 master URL (e.g. spark://23.195.26.187:7077)&lt;/li&gt;
&lt;li&gt;--deploy-mode : 배포 모드, cluster 또는 client를 지정한다. default는 client&lt;/li&gt;
&lt;li&gt;--conf : 키 값 형식의 Spark 구성 속성&lt;/li&gt;
&lt;li&gt;application-jar : 애플리케이션과 모든 종속성이 포함된 jar의 경로, URL은 클러스터의 모든 노드가 접근할 수 있어야한다. (e.g hdfs://, file://)&lt;/li&gt;
&lt;li&gt;application-argument : 메인 클래스의 메인 메서드가 전잘되는 인자 (있는 경우만)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬 애플리케이션의 경우 &amp;lt;application-jar&amp;gt; 대신 .py 파일을 전달하고 --py--files 옵션으로 Python .zip, .egg, .py 파일을 추가한다. 참고로 standalone 모드는 python 애플리케이션의 클러스터 모드를 지원하지 않는다.&lt;/p&gt;
&lt;pre id=&quot;code_1709531976994&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Run application locally on 8 cores
./bin/spark-submit \
  --class org.apache.spark.examples.SparkPi \
  --master local[8] \
  /path/to/examples.jar \
  100

# Run on a Spark standalone cluster in client deploy mode
./bin/spark-submit \
  --class org.apache.spark.examples.SparkPi \
  --master spark://207.184.161.138:7077 \
  --executor-memory 20G \
  --total-executor-cores 100 \
  /path/to/examples.jar \
  1000
  
  # Run a Python application on a Spark standalone cluster
./bin/spark-submit \
  --master spark://207.184.161.138:7077 \
  examples/src/main/python/pi.py \
  1000

# Run on a YARN cluster in cluster deploy mode
export HADOOP_CONF_DIR=XXX
./bin/spark-submit \
  --class org.apache.spark.examples.SparkPi \
  --master yarn \
  --deploy-mode cluster \
  --executor-memory 20G \
  --num-executors 50 \
  /path/to/examples.jar \
  1000

# Run on a Kubernetes cluster in cluster deploy mode
./bin/spark-submit \
  --class org.apache.spark.examples.SparkPi \
  --master k8s://xx.yy.zz.ww:443 \
  --deploy-mode cluster \
  --executor-memory 20G \
  --num-executors 50 \
  http://path/to/examples.jar \
  1000&lt;/code&gt;&lt;/pre&gt;
&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;Master URL&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;master url 옵션에는 아래 형식이 들어갈 수 있다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 102px;&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: 50%; height: 17px;&quot;&gt;마스터 URL&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 17px;&quot;&gt;의미&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 17px;&quot;&gt;local&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 17px;&quot;&gt;하나의 워커 스레드로 로컬에서 Spark 실행 (병렬 처리가 없음)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 17px;&quot;&gt;local[K]&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 17px;&quot;&gt;K개의 워커 스레드로 로컬에서 Spark 실행 (이상적으로는 로컬 컴퓨터의 코어 수로 지정)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 17px;&quot;&gt;spark://HOST:PORT&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 17px;&quot;&gt;지정된 Spark Standalone cluster의 마스터와 연결, 기본적으로 7077포트 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 17px;&quot;&gt;yarn&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 17px;&quot;&gt;배포 모드에 따라 클라이언트 또는 클러스터 모드에서 yarn 클러스터와 연결&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 17px;&quot;&gt;k8s://HOST:PORT&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 17px;&quot;&gt;배포 모드에 따라 클라이언트 또는 클러스터 모드에서 kubernest 클러스터와 연결&lt;br /&gt;kubernetes의 API 서버가 지정됨&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>Hadoop Echo System</category>
      <author>gunjoon98</author>
      <guid isPermaLink="true">https://gunjoon.tistory.com/203</guid>
      <comments>https://gunjoon.tistory.com/203#entry203comment</comments>
      <pubDate>Mon, 4 Mar 2024 12:19:00 +0900</pubDate>
    </item>
    <item>
      <title>스파크 클러스터</title>
      <link>https://gunjoon.tistory.com/202</link>
      <description>&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;스파크 클러스터&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;998&quot; data-origin-height=&quot;530&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJnThk/btsFCAsNrtb/EGquWGobubak9lupbGVeUK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJnThk/btsFCAsNrtb/EGquWGobubak9lupbGVeUK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJnThk/btsFCAsNrtb/EGquWGobubak9lupbGVeUK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJnThk%2FbtsFCAsNrtb%2FEGquWGobubak9lupbGVeUK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;998&quot; height=&quot;530&quot; data-origin-width=&quot;998&quot; data-origin-height=&quot;530&quot;/&gt;&lt;/span&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;드라이버 프로그램&lt;/b&gt;은 SparkSession 객체를 초기화하고 &lt;b&gt;클러스터 매니저&lt;/b&gt;와 통신하며 스파크 이그제큐터를 위한 필요한 자원(cpu, memory)를 요청한다. 또한 모든 스파크 작업을 DAG 연산 형태로 변환해 스케줄링하며 각 실행 단위를 태스크로 나누어 스파크 이그제큐터(Executor)에 분배한다. 자원이 할당되면 그 다음부터 드라이버 프로그램은 이그제큐터와 직접 통신한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;스파크 2.0에서&lt;/span&gt;&lt;b&gt; 스파크 세션&lt;/b&gt;은 모든 스파크 연산과 데이터에 대한 통합 연결 채널이 되었다. 이전의 SparkContext, SQLContext, HiveContext, SparkConf, StreamingContext 등을 합쳐 놓았으며 스파크 작업을 훨씬 간단하고 쉽게 만들어준다. SparkSession을 통해 JVM 실행 파라미터를 만들고, 데이터 프레임이나 데이터세트를 정의하고, 데이터 소스에서 데이터를 읽고, 메타데이터에 접근하고, 스파크 SQL 질의를 실행할 수 있다. 즉 SparkSession은 모든 스파크 기능을 한 군데에서 접근할 수 있는 시작점을 제공한다.&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;주요 용어&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Application : Spark에서 수행되는 사용자 프로그램으로, 드라이버 프로그램와 여러 이그제큐터 프로세스로 구성됨&lt;/li&gt;
&lt;li&gt;Application jar : 사용자 프로그램이 포함된 jar 파일, 사용자의 jar 파일에는 하둡 또는 스파크 라이브러리가 포함되지 않고 런타임 시에 추가됨&lt;/li&gt;
&lt;li&gt;Driver Program : 애플리케이션의 main 함수를 실행시키고 스파크 세션 객체를 생성하는 프로그램&lt;/li&gt;
&lt;li&gt;Cluster manager : 클러스터의 리소스를 관리하는 외부 서비스 (Standalone, Mesos, YARN, Kubernetes)&lt;/li&gt;
&lt;li&gt;Worker node : 애플리케이션 코드를 실행하는 클러스터의 노드&lt;/li&gt;
&lt;li&gt;Executor : 워커 노드에서 동작하며 드라이버 프로그램이 요청한 Task를 실제로 수행하는 프로세스, Task를 실행하고 메모리 또는 디스크에 데이터를 보관, 스파크 애플리케이션마다 Executor를 할당되어 실행&lt;/li&gt;
&lt;li&gt;Job : 애플리케이션에서 스파크에 요청하는 일련의 작업, 여러 개의 Task로 나뉘어 실행됨&lt;/li&gt;
&lt;li&gt;Task : 이그제큐터 프로세스가 실행하는 최소 작업 단위&lt;/li&gt;
&lt;li&gt;Deploy mode : 배포 모드는 클러스터 모드와 클라이언트 모드로 나뉨&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;배포 모드&lt;/span&gt;&lt;/h2&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;클라이언트 모드 :&amp;nbsp; 클러스터 외부의 클라이언트에서 드라이버 프로그램 실행, spark shell을 사용하면 클라이언트 모드로 동작한다.&lt;/li&gt;
&lt;li&gt;클러스터 모드 : 클러스터 노드 중 하나에서 드라이버 프로그램 실행&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;Cluster Manager&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스파크는 여러 종류의 클러스터 매니저(또는 Resource Manager)와 같이 사용될 수 있다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 87px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style4&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 19px; text-align: center;&quot;&gt;모드&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px; text-align: center;&quot;&gt;스파크 드라이버&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px; text-align: center;&quot;&gt;스파크 이그제큐터&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px; text-align: center;&quot;&gt;클러스터 매니저&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;로컬&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;단일 JVM 위에서 동작&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;드라이버와 동일한 JVM 위에서 동작&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;동일한 호스트에서 실행&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;standalone&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;클러스터의 아무 노드에서나 동작 가능&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;클러스터의 각 노드가 자제적인 이그제큐터 JVM을 실행&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;클러스터의 아무 노드에서나 할당 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;Yarn(클라이언트)&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;클러스터 외부의 클라이언트에서 동작&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;yarn의 노드매니저의 컨테이너에서 동작&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;yarn의 리소스 매니저가 yarn의 애플리케이션 마스터와 연계하여 노드 매니저에 이그제큐터를 위한 컨테이너 할당&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;Yarn(클러스터)&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;yarn 애플리케이션 마스터에서 동작&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;yarn(클러스터) 모드와 동일&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;yarn(클러스터) 모드와 동일&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;kubernetes&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;쿠버네티스 pod에서 동작&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;쿠버네티스 pod에서 동작&lt;/td&gt;
&lt;td style=&quot;width: 25%; 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;
&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;Monitoring&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 드라이버 프로그램에는 일반적으로 포트 4040에 실행중인 task, executor, storage 사용량에 대한 정보를 표시하는 웹 UI가 있다. 웹 브라우저에서 드라이버 프로그램이 실행되고 있는 노드에서 http://&amp;lt;driver-node&amp;gt;:4040로 이동하면 해당 웹 UI를 볼 수 있다.&lt;/p&gt;
&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;참고&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://spark.apache.org/docs/latest/cluster-overview.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://spark.apache.org/docs/latest/cluster-overview.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1710899189523&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;Cluster Mode Overview - Spark 3.5.1 Documentation&quot; data-og-description=&quot;Cluster Mode Overview This document gives a short overview of how Spark runs on clusters, to make it easier to understand the components involved. Read through the application submission guide to learn about launching applications on a cluster. Components &quot; data-og-host=&quot;spark.apache.org&quot; data-og-source-url=&quot;https://spark.apache.org/docs/latest/cluster-overview.html&quot; data-og-url=&quot;https://spark.apache.org/docs/latest/cluster-overview.html&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cTJWyc/hyVADu3CkW/sKJTg7uo7prQDqHsHjkWc1/img.png?width=596&amp;amp;height=286&amp;amp;face=0_0_596_286&quot;&gt;&lt;a href=&quot;https://spark.apache.org/docs/latest/cluster-overview.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://spark.apache.org/docs/latest/cluster-overview.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cTJWyc/hyVADu3CkW/sKJTg7uo7prQDqHsHjkWc1/img.png?width=596&amp;amp;height=286&amp;amp;face=0_0_596_286');&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;Cluster Mode Overview - Spark 3.5.1 Documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Cluster Mode Overview This document gives a short overview of how Spark runs on clusters, to make it easier to understand the components involved. Read through the application submission guide to learn about launching applications on a cluster. Components&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;spark.apache.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.samsungsds.com/kr/insights/spark-cluster-job-server.html?referrer=https://eyeballs.tistory.com/82&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.samsungsds.com/kr/insights/spark-cluster-job-server.html?referrer=https://eyeballs.tistory.com/82&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1710899198726&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;클러스터 리소스 최적화를 위한 Spark 아키텍처 ①  | 인사이트리포트 | 삼성SDS&quot; data-og-description=&quot;클러스터 리소스 최적화에 대해 쉽게 설명한 글입니다. Spark Cluster에 대한 기본적인 개념과 Spark Job Server를 활용한 효율적인 리소스 관리 방법에 대한 궁금증을 해결해 보세요.&quot; data-og-host=&quot;www.samsungsds.com&quot; data-og-source-url=&quot;https://www.samsungsds.com/kr/insights/spark-cluster-job-server.html?referrer=https://eyeballs.tistory.com/82&quot; data-og-url=&quot;https://www.samsungsds.com/kr/insights/spark-cluster-job-server.html&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/pzkzj/hyVDGRcPJJ/hw59JVjiJ6z8IZnZvZbDk1/img.jpg?width=900&amp;amp;height=600&amp;amp;face=0_0_900_600,https://scrap.kakaocdn.net/dn/HOH5E/hyVDucaZh6/BhF3LK4RIHgab45ryzgldk/img.jpg?width=900&amp;amp;height=600&amp;amp;face=0_0_900_600,https://scrap.kakaocdn.net/dn/HvQNs/hyVDyeAeGE/s3jf347DIyOcdZHGdkkHDk/img.jpg?width=844&amp;amp;height=306&amp;amp;face=0_0_844_306&quot;&gt;&lt;a href=&quot;https://www.samsungsds.com/kr/insights/spark-cluster-job-server.html?referrer=https://eyeballs.tistory.com/82&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.samsungsds.com/kr/insights/spark-cluster-job-server.html?referrer=https://eyeballs.tistory.com/82&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/pzkzj/hyVDGRcPJJ/hw59JVjiJ6z8IZnZvZbDk1/img.jpg?width=900&amp;amp;height=600&amp;amp;face=0_0_900_600,https://scrap.kakaocdn.net/dn/HOH5E/hyVDucaZh6/BhF3LK4RIHgab45ryzgldk/img.jpg?width=900&amp;amp;height=600&amp;amp;face=0_0_900_600,https://scrap.kakaocdn.net/dn/HvQNs/hyVDyeAeGE/s3jf347DIyOcdZHGdkkHDk/img.jpg?width=844&amp;amp;height=306&amp;amp;face=0_0_844_306');&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;클러스터 리소스 최적화를 위한 Spark 아키텍처 ① | 인사이트리포트 | 삼성SDS&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;클러스터 리소스 최적화에 대해 쉽게 설명한 글입니다. Spark Cluster에 대한 기본적인 개념과 Spark Job Server를 활용한 효율적인 리소스 관리 방법에 대한 궁금증을 해결해 보세요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.samsungsds.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;</description>
      <category>Hadoop Echo System</category>
      <author>gunjoon98</author>
      <guid isPermaLink="true">https://gunjoon.tistory.com/202</guid>
      <comments>https://gunjoon.tistory.com/202#entry202comment</comments>
      <pubDate>Sun, 3 Mar 2024 22:12:37 +0900</pubDate>
    </item>
    <item>
      <title>쿠버네티스 클러스터 구축</title>
      <link>https://gunjoon.tistory.com/201</link>
      <description>&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;사전 진행&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필자는 AWS 계정에서 두 대의 EC2를 만들어 진행함&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;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;최소 2개의 리눅스 머신 노드 (master 노드 1, worker 노드 1개)가 필요, 요구 사항에 따라 더 많은 작업자 노드가 필요할 수 있음&lt;/li&gt;
&lt;li&gt;master 노드에는 최소&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&amp;nbsp;&lt;/span&gt;2개의 vCPU와 2GB RAM이&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;있어야하며, &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;worker 노드는 최소 1vCPU 및 2GB RAM 권장&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;클러스터의 모든 노드는 서로 통신이 가능해야함&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;클러스터의 모든 노드는 스왑 비활성화 (활성화 되어 있으면 &lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: left;&quot;&gt;kubelet이 제대로 작동하지 않음)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;클러스터의 모든 노드는 &lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: left;&quot;&gt;고유한 호스트 이름, MAC 주소 및 product_uuid 가져야함&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: left;&quot;&gt;2. 포트 허용&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #222222;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;아래 그림을 참고해 마스터 노드(컨트롤 플레인) 및 워커 노드의 포트를 허용, 필자는 ec2간 방화벽 정책을 모든 트래픽 허용으로 했으며 src/dist check를 비활성으로 했다. 그 이유는 발생한 이슈에 적어두었다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;722&quot; data-origin-height=&quot;371&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cW9CP4/btsFg5tPuFO/u2khkm6CxrkfkYctsqx0h1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cW9CP4/btsFg5tPuFO/u2khkm6CxrkfkYctsqx0h1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cW9CP4/btsFg5tPuFO/u2khkm6CxrkfkYctsqx0h1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcW9CP4%2FbtsFg5tPuFO%2Fu2khkm6CxrkfkYctsqx0h1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;650&quot; height=&quot;334&quot; data-origin-width=&quot;722&quot; data-origin-height=&quot;371&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;669&quot; data-origin-height=&quot;215&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfefjS/btsFfd7mFAy/jCgT13WIsuzHLit4n5P7G1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfefjS/btsFfd7mFAy/jCgT13WIsuzHLit4n5P7G1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfefjS/btsFfd7mFAy/jCgT13WIsuzHLit4n5P7G1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfefjS%2FbtsFfd7mFAy%2FjCgT13WIsuzHLit4n5P7G1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;650&quot; height=&quot;209&quot; data-origin-width=&quot;669&quot; data-origin-height=&quot;215&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: #222222;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;참고 글) &lt;a href=&quot;https://kubernetes.io/docs/reference/networking/ports-and-protocols/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://kubernetes.io/docs/reference/networking/ports-and-protocols/&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1708751852365&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;Ports and Protocols&quot; data-og-description=&quot;When running Kubernetes in an environment with strict network boundaries, such as on-premises datacenter with physical network firewalls or Virtual Networks in Public Cloud, it is useful to be aware of the ports and protocols used by Kubernetes components.&quot; data-og-host=&quot;kubernetes.io&quot; data-og-source-url=&quot;https://kubernetes.io/docs/reference/networking/ports-and-protocols/&quot; data-og-url=&quot;https://kubernetes.io/docs/reference/networking/ports-and-protocols/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/chKp3Y/hyVmXU0APY/LZ94uRXgUtJ0Mm73KTlivk/img.png?width=1727&amp;amp;height=373&amp;amp;face=0_0_1727_373,https://scrap.kakaocdn.net/dn/cGiBQz/hyVmQO7tL5/7ANYYa673ZTZ7LwglQlszk/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512&quot;&gt;&lt;a href=&quot;https://kubernetes.io/docs/reference/networking/ports-and-protocols/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://kubernetes.io/docs/reference/networking/ports-and-protocols/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/chKp3Y/hyVmXU0APY/LZ94uRXgUtJ0Mm73KTlivk/img.png?width=1727&amp;amp;height=373&amp;amp;face=0_0_1727_373,https://scrap.kakaocdn.net/dn/cGiBQz/hyVmQO7tL5/7ANYYa673ZTZ7LwglQlszk/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Ports and Protocols&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;When running Kubernetes in an environment with strict network boundaries, such as on-premises datacenter with physical network firewalls or Virtual Networks in Public Cloud, it is useful to be aware of the ports and protocols used by Kubernetes components.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;kubernetes.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 모든 노드에서 iptables 브리지 트래픽 활성화&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1708500593276&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cat &amp;lt;&amp;lt;EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF

sudo modprobe overlay
sudo modprobe br_netfilter

# sysctl params required by setup, params persist across reboots
cat &amp;lt;&amp;lt;EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables  = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward                 = 1
EOF

# Apply sysctl params without reboot
sudo sysctl --system&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. 모든 노드에서 스왑 비활성화&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1708500668253&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo swapoff -a
(crontab -l 2&amp;gt;/dev/null; echo &quot;@reboot /sbin/swapoff -a&quot;) | crontab - || true&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5. 모든 노드에서 컨테이너 런타임 설치&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파드에서 컨테이너를 실행하기 위해, 쿠버네티스는 컨테이너 런타임 인터페이스(CRI)을 사용한다. 쿠버네티스는 CRI를 사용해 사용자가 지정한&amp;nbsp;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: left;&quot;&gt;컨테이너 런타임과 연결한다. 아래의 &lt;/span&gt;컨테이너 런타임이 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CRI-O&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: left;&quot;&gt;containerd&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: left;&quot;&gt;docker-engine (cri-dockerd 사용)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt; &lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: left;&quot;&gt;런타임을 지정하지 않으면, kubeadm은 잘 알려진 엔드포인트(소켓 위치)를 스캔하여 설치된 컨테이너 런타임을 자동으로 감지하려고 한다. 만약 &lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: left;&quot;&gt;컨테이너 런타임이 여러 개 감지되거나 하나도 감지되지 않은 경우, kubeadm은 에러를 반환하고 사용자가 어떤 것을 사용할지를 명시하도록 요청한다. &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;쿠버네티스의 컨테이너 런타임으로 도커 엔진을 사용하려면 추가적으로 &lt;a style=&quot;color: #3371e3; text-align: left;&quot; href=&quot;https://github.com/Mirantis/cri-dockerd&quot;&gt;cri-dockerd&lt;/a&gt;를 설치해야한다. &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;도커 엔진의 컨테이너 런타임이 CRI를 만족하지 않기 때문이다. &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt; &lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: left;&quot;&gt;아래 표는 리눅스의 잘 알려진 엔드포인트이다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 50px;&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: 50%; height: 17px;&quot;&gt;CRI-O&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 17px;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: left;&quot;&gt;/var/run/crio/crio.sock&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 13px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 13px;&quot;&gt;containerd&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 13px;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: left;&quot;&gt;/var/run/containerd/containerd.sock&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 20px;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: left;&quot;&gt;docker-engine &lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: left;&quot;&gt;(cri-dockerd 사용)&lt;/span&gt; &lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 20px;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: left;&quot;&gt;/var/run/cri-dockerd.sock&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글에서는 컨테이너 런타임으로 CRI-O를 사용한다. 아래와 같이 CRI-O를 설치하자. 필자는 우분투(22.04)를 사용한다.&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;cri-o 버전 1.28에 대한&lt;span&gt;&amp;nbsp;&lt;/span&gt;cri-o&lt;span&gt;&amp;nbsp;&lt;/span&gt;저장소 활성화&lt;/p&gt;
&lt;pre id=&quot;code_1708757516600&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;OS=&quot;xUbuntu_22.04&quot;
VERSION=&quot;1.28&quot;

cat &amp;lt;&amp;lt;EOF | sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/ /
EOF
cat &amp;lt;&amp;lt;EOF | sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable:cri-o:$VERSION.list
deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o:/$VERSION/$OS/ /
EOF&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #404953; text-align: left;&quot;&gt;CRI-O용 GPG 키를 시스템의 신뢰할 수 있는 키 목록에 추가&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1708757574375&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;curl -L https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable:cri-o:$VERSION/$OS/Release.key | sudo apt-key --keyring /etc/apt/trusted.gpg.d/libcontainers.gpg add -
curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/Release.key | sudo apt-key --keyring /etc/apt/trusted.gpg.d/libcontainers.gpg add -&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;업데이트하고 crio, cri-tools 설치&lt;/p&gt;
&lt;pre id=&quot;code_1708757615327&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo apt-get update -y
sudo apt-get install cri-o cri-o-runc cri-tools -y&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #404953; text-align: left;&quot;&gt;systemd 구성을 다시 로드하고 cri-o를 활성화&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1708757646964&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo systemctl daemon-reload
sudo systemctl enable crio --now&lt;/code&gt;&lt;/pre&gt;
&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;모든 노드에 kubeadm, kubelet, kubectl 설치&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿠버네티스를 사용하려면 kubelet, kubeadm, kubectl 패키지가 필요하다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;kubelet : 클러스터의 모든 노드에서 실행되는 컴포넌트로 파드 및 컨테이너의 생성 / 실행 등과 같은 작업을 수행&lt;/li&gt;
&lt;li&gt;kubeadm : 쿠버네티스의 클러스터를 구축하기 위해 사용&lt;/li&gt;
&lt;li&gt;kubectl : 클러스터와 통신하기 위한 커맨드라인 유틸&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #404953; text-align: left;&quot;&gt;필요한 종속성을 설치&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1708759701130&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo apt-get update -y
sudo apt-get install -y apt-transport-https ca-certificates curl -y&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #404953; text-align: left;&quot;&gt;Kubernetes APT 저장소의 GPG 키를 다운로드&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1708759720793&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://dl.k8s.io/apt/doc/apt-key.gpg&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #404953; text-align: left;&quot;&gt;Kubernetes APT 저장소를 시스템에 추가&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1708759776281&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;echo &quot;deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main&quot; | sudo tee /etc/apt/sources.list.d/kubernetes.list&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #404953; text-align: left;&quot;&gt;저장소 업데이트&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1708759787988&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo apt-get update -y&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치&lt;/p&gt;
&lt;pre id=&quot;code_1708759823435&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 최신 버전 설치
sudo apt-get install kubelet kubeadm kubectl -y

# 버전 지정 설치
sudo apt-get install kubelet=1.28.2-00 kubectl=1.28.2-00 kubeadm=1.28.2-00 -y&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;업그레이드 방지 (갑자기 업그레이드 되면 노드 간의 버전이 달라져 문제가 발생할 수 있음)&lt;/p&gt;
&lt;pre id=&quot;code_1708759873051&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo apt-mark hold kubelet kubeadm kubectl&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;KUBELET_EXTRA_ARGS를 노드의 사설 ip로 설정한다.&lt;/p&gt;
&lt;pre id=&quot;code_1708777535164&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;private_ip=&quot;your_private_ip&quot;
sudo bash -c &quot;echo KUBELET_EXTRA_ARGS=--node-ip=$private_ip &amp;gt; /etc/default/kubelet&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;마스터 노드에서 kubeadm 초기화&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래의 환경 변수 설정&lt;/p&gt;
&lt;pre id=&quot;code_1708777639318&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;IPADDR=$private_ip
NODENAME=$(hostname -s)
POD_CIDR=&quot;192.168.0.0/16&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kubeadm init 명령어 수행, 앞에서 이미 swap을 비활성화했기에 --ignore-preflight-errors Swap은 굳이 안써도 된다. kubeadm init시 아래와 같이--apiserver-advertise-address 옵션으로 사설 ip를 사용할 수도 있고 --control-plane-endpoint 옵션으로 공인 ip를 지정할수도 있지만 왠만하면 사설 ip를 사용하는 것이 좋다. 공인 ip를 사용하면 누구나 클러스터에 연결을 시도할 수 있기 때문이다. &lt;b&gt;클러스터의 모든 노드는 같은 내부망을 가지고 내부망에서만 서로 통신하는 것이 안전하다.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1708777685745&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo kubeadm init --apiserver-advertise-address=$IPADDR  --apiserver-cert-extra-sans=$IPADDR  --pod-network-cidr=$POD_CIDR --node-name $NODENAME --ignore-preflight-errors Swap&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초기화에 성공하면 아래 그림과 같이 출력된다. 토큰이 포함된 join 명령을 복사해 따로 저장한다. 해당 명령은 worker 노드가 마스터에 연결되기 위해 필요하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;제목 없음.png&quot; data-origin-width=&quot;937&quot; data-origin-height=&quot;440&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AuQE6/btsFhhPm1Ta/6cbIR5bG78fAHLoDpO8fRK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AuQE6/btsFhhPm1Ta/6cbIR5bG78fAHLoDpO8fRK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AuQE6/btsFhhPm1Ta/6cbIR5bG78fAHLoDpO8fRK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAuQE6%2FbtsFhhPm1Ta%2F6cbIR5bG78fAHLoDpO8fRK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;937&quot; height=&quot;440&quot; data-filename=&quot;제목 없음.png&quot; data-origin-width=&quot;937&quot; data-origin-height=&quot;440&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 로그에서 말하는대로 아래 명령어를 수행한다.&lt;/p&gt;
&lt;pre id=&quot;code_1708777913651&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 마스터 노드에서는 파드가 실행되지 않는다. 마스터 노드에도 Pod를 실행시킬려면 아래의 명령어를 수행한다.&lt;/p&gt;
&lt;pre id=&quot;code_1708778029531&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;kubectl taint nodes --all node-role.kubernetes.io/control-plane-&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kubectl get po -n kube-system을 수행하여 pod를 확인할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1708785884652&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;kubectl get po -n kube-system&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #404953; text-align: left;&quot;&gt;아래 명령을 사용하여 모든 클러스터 구성 요소 상태를 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1708785898961&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;kubectl get --raw='/readyz?verbose'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 명령을 사용하여 클러스터 정보를 확인할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1708785926500&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;kubectl cluster-info&lt;/code&gt;&lt;/pre&gt;
&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;마스터 노드에서 CNI 플러그인 설치&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서로 다른 노드에 있는 Pod들이 통신하기 위해서는 오버레이 네트워크가 필요하다. 오버레이 네트워크란 노드에서 사용하는 물리적인 네트워크 위에 가상의 네트워크를 구성하는 것이다. 오버레이 네트워크가 구축되면 클러스터로 묶인 모든 노드에 떠 있는 파드 간 통신이 가능하다.&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;쿠버네티스에서 오버레이 네트워크를 구성하기 위해 CNI 플러그인을 설치해야한다. CNI 플러그인에는 플라넬, 칼리코, 실리움, 멀터스 등이 있으며 이 글에서는 칼리코(Calico)를 설치한다.&lt;/p&gt;
&lt;pre id=&quot;code_1708778408819&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/tigera-operator.yaml

curl https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/custom-resources.yaml -O

kubectl create -f custom-resources.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;워커 노드를 마스터 노드에 조인&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;워커 노드를 클러스터에 포함시킨다. 앞에서 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;kubeadm init 명령어를 수행해 얻은 join 명령어를 입력한다. 만약 join 명령 복사를 놓친경우 아래의 명령어를 마스터 노드에 수행해 다시 명령어를 얻는다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1708778507459&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;kubeadm token create --print-join-command&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래의 명령어를 워커 노드에서 수행해 워커 노드를 클러스터에 포함시킨다.&lt;/p&gt;
&lt;pre id=&quot;code_1708778534300&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo kubeadm join 10.128.0.37:6443 --token j4eice.33vgvgyf5cxw4u8i \
    --discovery-token-ca-cert-hash sha256:37f94469b58bcc8f26a4aa44441fb17196a585b37288f85e22475b00c36f1c61&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;성공적으로 수행되면 아래와 같이 클러스터에 조인됬다는 문구가 뜬다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;kubeadm-1024x576.png.webp&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;576&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bn32QK/btsFjUza9cm/BzSd5xo6X7JkNfG1QVAUOK/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bn32QK/btsFjUza9cm/BzSd5xo6X7JkNfG1QVAUOK/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bn32QK/btsFjUza9cm/BzSd5xo6X7JkNfG1QVAUOK/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbn32QK%2FbtsFjUza9cm%2FBzSd5xo6X7JkNfG1QVAUOK%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;1024&quot; height=&quot;576&quot; data-filename=&quot;kubeadm-1024x576.png.webp&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;576&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;마스터 노드에서 kubectl 명령을&lt;span&gt;&amp;nbsp;&lt;/span&gt;실행하여 해당 노드가 마스터에 추가되었는지 확인한다.&lt;/p&gt;
&lt;pre id=&quot;code_1708778596529&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;kubectl get nodes&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1708778609334&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;root@master-node:/home/vagrant# kubectl get nodes
NAME            STATUS   ROLES           AGE     VERSION
controlplane     Ready    control-plane   14m     v1.28.2
node01           Ready    &amp;lt;none&amp;gt;          2m13s   v1.28.2
node02           Ready    &amp;lt;none&amp;gt;          2m5s    v1.28.2&lt;/code&gt;&lt;/pre&gt;
&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;간편하게 구축&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞에 설명한 명령어를 하나의 sh 파일로 만들어두면 쉽게 마스터 노드, 워커 노드를 만들 수 있다.&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;master.sh (&lt;b&gt;변수 값만 적절히 수정&lt;/b&gt;)&lt;/p&gt;
&lt;pre id=&quot;code_1708786034708&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#!/bin/bash

# Variables, 적절한 값으로 수정
KUBERNETES_VERSION=&quot;1.28.2-00&quot;
OS=&quot;xUbuntu_22.04&quot;
VERSION=&quot;1.28&quot;
private_ip=&quot;your_private_ip&quot;

# iptables 브리지 트래픽 활성화
cat &amp;lt;&amp;lt;EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF

sudo modprobe overlay
sudo modprobe br_netfilter

cat &amp;lt;&amp;lt;EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables  = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward                 = 1
EOF

sudo sysctl --system

# 스왑 비활성화
sudo swapoff -a
(crontab -l 2&amp;gt;/dev/null; echo &quot;@reboot /sbin/swapoff -a&quot;) | crontab - || true

# 컨테이너 런타임, CRI-O 설치
cat &amp;lt;&amp;lt;EOF | sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/ /
EOF
cat &amp;lt;&amp;lt;EOF | sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable:cri-o:$VERSION.list
deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o:/$VERSION/$OS/ /
EOF

curl -L https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable:cri-o:$VERSION/$OS/Release.key | sudo apt-key --keyring /etc/apt/trusted.gpg.d/libcontainers.gpg add -
curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/Release.key | sudo apt-key --keyring /etc/apt/trusted.gpg.d/libcontainers.gpg add -

sudo apt-get update -y
sudo apt-get install cri-o cri-o-runc cri-tools -y

sudo systemctl daemon-reload
sudo systemctl enable crio --now

# kubeadm, kubelet, kubectl 설치
sudo apt-get update -y
sudo apt-get install -y apt-transport-https ca-certificates curl -y
sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://dl.k8s.io/apt/doc/apt-key.gpg
echo &quot;deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main&quot; | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update -y

sudo apt-get install kubelet=&quot;$KUBERNETES_VERSION&quot; kubectl=&quot;$KUBERNETES_VERSION&quot; kubeadm=&quot;$KUBERNETES_VERSION&quot; -y
sudo apt-mark hold kubelet kubeadm kubectl

sudo bash -c &quot;echo KUBELET_EXTRA_ARGS=--node-ip=$private_ip &amp;gt; /etc/default/kubelet&quot;

# kubeadm 초기화
IPADDR=$private_ip
NODENAME=$(hostname -s)
POD_CIDR=&quot;192.168.0.0/16&quot;

sudo kubeadm init --apiserver-advertise-address=$IPADDR  --apiserver-cert-extra-sans=$IPADDR  --pod-network-cidr=$POD_CIDR --node-name $NODENAME --ignore-preflight-errors Swap

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

kubectl taint nodes --all node-role.kubernetes.io/control-plane-

# Calico 설치
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/tigera-operator.yaml
curl https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/custom-resources.yaml -O
kubectl create -f custom-resources.yaml&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;worker.sh (&lt;b&gt;변수 값만 적절히 수정&lt;/b&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;워커 노드에서는 아래 sh을 수행하고 위 글에서 &quot;워커 노드를 마스터 노드에 조인&quot; 파트만 추가로 수행하면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1708786128942&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#!/bin/bash

# Variables, 적절한 값으로 수정
KUBERNETES_VERSION=&quot;1.28.2-00&quot;
OS=&quot;xUbuntu_22.04&quot;
VERSION=&quot;1.28&quot;
private_ip=&quot;your_private_ip&quot;

# iptables 브리지 트래픽 활성화
cat &amp;lt;&amp;lt;EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF

sudo modprobe overlay
sudo modprobe br_netfilter

cat &amp;lt;&amp;lt;EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables  = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward                 = 1
EOF

sudo sysctl --system

# 스왑 비활성화
sudo swapoff -a
(crontab -l 2&amp;gt;/dev/null; echo &quot;@reboot /sbin/swapoff -a&quot;) | crontab - || true

# 컨테이너 런타임, CRI-O 설치
cat &amp;lt;&amp;lt;EOF | sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/ /
EOF
cat &amp;lt;&amp;lt;EOF | sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable:cri-o:$VERSION.list
deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o:/$VERSION/$OS/ /
EOF

curl -L https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable:cri-o:$VERSION/$OS/Release.key | sudo apt-key --keyring /etc/apt/trusted.gpg.d/libcontainers.gpg add -
curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/Release.key | sudo apt-key --keyring /etc/apt/trusted.gpg.d/libcontainers.gpg add -

sudo apt-get update -y
sudo apt-get install cri-o cri-o-runc cri-tools -y

sudo systemctl daemon-reload
sudo systemctl enable crio --now

# kubeadm, kubelet, kubectl 설치
sudo apt-get update -y
sudo apt-get install -y apt-transport-https ca-certificates curl -y
sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://dl.k8s.io/apt/doc/apt-key.gpg
echo &quot;deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main&quot; | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update -y

sudo apt-get install kubelet=&quot;$KUBERNETES_VERSION&quot; kubectl=&quot;$KUBERNETES_VERSION&quot; kubeadm=&quot;$KUBERNETES_VERSION&quot; -y
sudo apt-mark hold kubelet kubeadm kubectl

sudo bash -c &quot;echo KUBELET_EXTRA_ARGS=--node-ip=$private_ip &amp;gt; /etc/default/kubelet&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;발생한 이슈&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 쿠버네티스 공식 문서에서 나온 대로 포트를 허용하고 쿠버네티스 클러스터를 구축했지만 쿠버네티스 상에서 노드 간 통신이 되지 않았다. 아래 글을 읽어보고 해결했다. aws 네트워크 정책와 cailco 공부가 필요할 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/60806708/kubernetes-with-calico-on-aws-cannot-ping-pods-on-on-different-nodes&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://stackoverflow.com/questions/60806708/kubernetes-with-calico-on-aws-cannot-ping-pods-on-on-different-nodes&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1710829557224&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;Kubernetes with Calico on AWS -- Cannot ping pods on on different nodes&quot; data-og-description=&quot;Just getting started with Kubernetes. I cannot seem to connect pods running on different nodes to communicate with each other. I set up a Kubernetes Cluster with Calico networking on three AWS ...&quot; data-og-host=&quot;stackoverflow.com&quot; data-og-source-url=&quot;https://stackoverflow.com/questions/60806708/kubernetes-with-calico-on-aws-cannot-ping-pods-on-on-different-nodes&quot; data-og-url=&quot;https://stackoverflow.com/questions/60806708/kubernetes-with-calico-on-aws-cannot-ping-pods-on-on-different-nodes&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dfgGQi/hyVDHoTSsc/CHZmzEoN07VBhkrEoaibr0/img.png?width=316&amp;amp;height=316&amp;amp;face=0_0_316_316&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/60806708/kubernetes-with-calico-on-aws-cannot-ping-pods-on-on-different-nodes&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://stackoverflow.com/questions/60806708/kubernetes-with-calico-on-aws-cannot-ping-pods-on-on-different-nodes&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dfgGQi/hyVDHoTSsc/CHZmzEoN07VBhkrEoaibr0/img.png?width=316&amp;amp;height=316&amp;amp;face=0_0_316_316');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Kubernetes with Calico on AWS -- Cannot ping pods on on different nodes&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Just getting started with Kubernetes. I cannot seem to connect pods running on different nodes to communicate with each other. I set up a Kubernetes Cluster with Calico networking on three AWS ...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;stackoverflow.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 서로 다른 사용자를 가진 AWS EC2를 묶어 쿠버네티스 클러스터를 구축하려했지만 연결되지 않았다. 아래 참고글의 aws에서 cailco 구성 글을 이해해야 될 것 같다.&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;3. &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;윈도우에서 sh 파일을 작성하고 우분투로 복사했더니, 줄 바꿈 문자에서 오류가 났다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;윈도우는 줄 바꿈 문자로 CR(&lt;span style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: left;&quot;&gt;carriage return&lt;/span&gt;)와 LF(line feed)를 모두 사용하지만, 리눅스에서는 LF만 사용하기에 sh에 포함된 CR 문자를 인식하지 못해 오류가 났다. 아래 명령어로 sh에 포함된 CR 문자를 모두 제거했다.&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1710829474042&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sed -i 's/\r//' your_script.sh&lt;/code&gt;&lt;/pre&gt;
&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;참고 글&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿠버네티스 공식 글 : &lt;a href=&quot;https://kubernetes.io/docs/setup/production-environment/container-runtimes/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://kubernetes.io/docs/setup/production-environment/container-runtimes/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1708778704500&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;Container Runtimes&quot; data-og-description=&quot;Note: Dockershim has been removed from the Kubernetes project as of release 1.24. Read the Dockershim Removal FAQ for further details. You need to install a container runtime into each node in the cluster so that Pods can run there. This page outlines what&quot; data-og-host=&quot;kubernetes.io&quot; data-og-source-url=&quot;https://kubernetes.io/docs/setup/production-environment/container-runtimes/&quot; data-og-url=&quot;https://kubernetes.io/docs/setup/production-environment/container-runtimes/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/N98U3/hyVqlUiZto/1VPVbuAjUjEKSm8BwbQLIk/img.png?width=1727&amp;amp;height=373&amp;amp;face=0_0_1727_373,https://scrap.kakaocdn.net/dn/blUEPQ/hyVm38OVWo/mKXsGdfRhcne7kKEwNrkqk/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512&quot;&gt;&lt;a href=&quot;https://kubernetes.io/docs/setup/production-environment/container-runtimes/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://kubernetes.io/docs/setup/production-environment/container-runtimes/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/N98U3/hyVqlUiZto/1VPVbuAjUjEKSm8BwbQLIk/img.png?width=1727&amp;amp;height=373&amp;amp;face=0_0_1727_373,https://scrap.kakaocdn.net/dn/blUEPQ/hyVm38OVWo/mKXsGdfRhcne7kKEwNrkqk/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Container Runtimes&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Note: Dockershim has been removed from the Kubernetes project as of release 1.24. Read the Dockershim Removal FAQ for further details. You need to install a container runtime into each node in the cluster so that Pods can run there. This page outlines what&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;kubernetes.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿠버네티스 공식 글 : &lt;a href=&quot;https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1708778733086&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;Installing kubeadm&quot; data-og-description=&quot;This page shows how to install the kubeadm toolbox. For information on how to create a cluster with kubeadm once you have performed this installation process, see the Creating a cluster with kubeadm page. This installation guide is for Kubernetes v1.29. If&quot; data-og-host=&quot;kubernetes.io&quot; data-og-source-url=&quot;https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/&quot; data-og-url=&quot;https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/I7TuF/hyVqiQNhoj/aPlOkfMx8zBDKLuaNFGOKk/img.png?width=1727&amp;amp;height=373&amp;amp;face=0_0_1727_373,https://scrap.kakaocdn.net/dn/dsqIsr/hyVmYl70hr/JKWbCcSb29qNYnKnr9gKX0/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512,https://scrap.kakaocdn.net/dn/c6viJW/hyVqltcUY4/NLOk5d7zXb9woKgQfYLKn1/img.png?width=1292&amp;amp;height=1475&amp;amp;face=0_0_1292_1475&quot;&gt;&lt;a href=&quot;https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/I7TuF/hyVqiQNhoj/aPlOkfMx8zBDKLuaNFGOKk/img.png?width=1727&amp;amp;height=373&amp;amp;face=0_0_1727_373,https://scrap.kakaocdn.net/dn/dsqIsr/hyVmYl70hr/JKWbCcSb29qNYnKnr9gKX0/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512,https://scrap.kakaocdn.net/dn/c6viJW/hyVqltcUY4/NLOk5d7zXb9woKgQfYLKn1/img.png?width=1292&amp;amp;height=1475&amp;amp;face=0_0_1292_1475');&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;Installing kubeadm&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;This page shows how to install the kubeadm toolbox. For information on how to create a cluster with kubeadm once you have performed this installation process, see the Creating a cluster with kubeadm page. This installation guide is for Kubernetes v1.29. If&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;kubernetes.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cri-o 공식 글 : &lt;a href=&quot;https://cri-o.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://cri-o.io/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1708778783628&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;cri-o&quot; data-og-description=&quot;Try Now Minikube: Use CRI-O as the container runtime kubeadm: Checkout this kubeadm guide to setup kubeadm to use CRI-O Kubic: Configured to use CRI-O out of the box in both its kubeadm and microOS system roles Join #crio on Kubernetes Slack Distribution P&quot; data-og-host=&quot;cri-o.io&quot; data-og-source-url=&quot;https://cri-o.io/&quot; data-og-url=&quot;https://cri-o.io/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/QODTe/hyVqmMnL3k/J6cpiywkczRKTzwCr99PI1/img.png?width=2673&amp;amp;height=1605&amp;amp;face=0_0_2673_1605,https://scrap.kakaocdn.net/dn/coa054/hyVqkgJBp0/DhvtqbcKuGxH8ZliCBAadk/img.png?width=1681&amp;amp;height=267&amp;amp;face=0_0_1681_267&quot;&gt;&lt;a href=&quot;https://cri-o.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://cri-o.io/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/QODTe/hyVqmMnL3k/J6cpiywkczRKTzwCr99PI1/img.png?width=2673&amp;amp;height=1605&amp;amp;face=0_0_2673_1605,https://scrap.kakaocdn.net/dn/coa054/hyVqkgJBp0/DhvtqbcKuGxH8ZliCBAadk/img.png?width=1681&amp;amp;height=267&amp;amp;face=0_0_1681_267');&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;cri-o&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Try Now Minikube: Use CRI-O as the container runtime kubeadm: Checkout this kubeadm guide to setup kubeadm to use CRI-O Kubic: Configured to use CRI-O out of the box in both its kubeadm and microOS system roles Join #crio on Kubernetes Slack Distribution P&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;cri-o.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치 관련 블로그 글 : &lt;a href=&quot;https://devopscube.com/setup-kubernetes-cluster-kubeadm/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://devopscube.com/setup-kubernetes-cluster-kubeadm/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1708778804439&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;How To Setup Kubernetes Cluster Using Kubeadm&quot; data-og-description=&quot;In this blog post, I have covered the step-by-step guide to setting up a kubernetes cluster using Kubeadm&quot; data-og-host=&quot;devopscube.com&quot; data-og-source-url=&quot;https://devopscube.com/setup-kubernetes-cluster-kubeadm/&quot; data-og-url=&quot;https://devopscube.com/setup-kubernetes-cluster-kubeadm/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bjWIkB/hyVqowIpGD/zHkFrvpCfnXrSvDGoWN4p0/img.png?width=1160&amp;amp;height=680&amp;amp;face=0_0_1160_680,https://scrap.kakaocdn.net/dn/eWdzn/hyVqmMq7lx/HmXL8hFhifvCA27kq1RfPk/img.png?width=1160&amp;amp;height=680&amp;amp;face=0_0_1160_680,https://scrap.kakaocdn.net/dn/5N1h0/hyVm2a0Wqw/GmE8gYCoeuwtYEHVytU20k/img.png?width=1160&amp;amp;height=680&amp;amp;face=0_0_1160_680&quot;&gt;&lt;a href=&quot;https://devopscube.com/setup-kubernetes-cluster-kubeadm/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devopscube.com/setup-kubernetes-cluster-kubeadm/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bjWIkB/hyVqowIpGD/zHkFrvpCfnXrSvDGoWN4p0/img.png?width=1160&amp;amp;height=680&amp;amp;face=0_0_1160_680,https://scrap.kakaocdn.net/dn/eWdzn/hyVqmMq7lx/HmXL8hFhifvCA27kq1RfPk/img.png?width=1160&amp;amp;height=680&amp;amp;face=0_0_1160_680,https://scrap.kakaocdn.net/dn/5N1h0/hyVm2a0Wqw/GmE8gYCoeuwtYEHVytU20k/img.png?width=1160&amp;amp;height=680&amp;amp;face=0_0_1160_680');&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;How To Setup Kubernetes Cluster Using Kubeadm&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;In this blog post, I have covered the step-by-step guide to setting up a kubernetes cluster using Kubeadm&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;devopscube.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;칼리코 설치 : &lt;a href=&quot;https://docs.tigera.io/calico/latest/getting-started/kubernetes/quickstart&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.tigera.io/calico/latest/getting-started/kubernetes/quickstart&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1709547677797&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;Quickstart for Calico on Kubernetes | Calico Documentation&quot; data-og-description=&quot;Install Calico on a single-host Kubernetes cluster for testing or development in under 15 minutes.&quot; data-og-host=&quot;docs.tigera.io&quot; data-og-source-url=&quot;https://docs.tigera.io/calico/latest/getting-started/kubernetes/quickstart&quot; data-og-url=&quot;https://docs.tigera.io/calico/latest/getting-started/kubernetes/quickstart&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.tigera.io/calico/latest/getting-started/kubernetes/quickstart&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.tigera.io/calico/latest/getting-started/kubernetes/quickstart&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;Quickstart for Calico on Kubernetes | Calico Documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Install Calico on a single-host Kubernetes cluster for testing or development in under 15 minutes.&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 data-ke-size=&quot;size16&quot;&gt;calico the hard way : &lt;a href=&quot;https://docs.tigera.io/calico/latest/getting-started/kubernetes/hardway/standing-up-kubernetes&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.tigera.io/calico/latest/getting-started/kubernetes/hardway/standing-up-kubernetes&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1709547579507&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;Stand up Kubernetes | Calico Documentation&quot; data-og-description=&quot;Get a Kubernetes cluster up and running.&quot; data-og-host=&quot;docs.tigera.io&quot; data-og-source-url=&quot;https://docs.tigera.io/calico/latest/getting-started/kubernetes/hardway/standing-up-kubernetes&quot; data-og-url=&quot;https://docs.tigera.io/calico/latest/getting-started/kubernetes/hardway/standing-up-kubernetes&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.tigera.io/calico/latest/getting-started/kubernetes/hardway/standing-up-kubernetes&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.tigera.io/calico/latest/getting-started/kubernetes/hardway/standing-up-kubernetes&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;Stand up Kubernetes | Calico Documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Get a Kubernetes cluster up and running.&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 data-ke-size=&quot;size16&quot;&gt;aws에서 calico 구성 : &lt;a href=&quot;https://docs.tigera.io/calico/latest/reference/public-cloud/aws&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.tigera.io/calico/latest/reference/public-cloud/aws&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1709547746875&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Amazon Web Services | Calico Documentation&quot; data-og-description=&quot;Advantages of using Calico in AWS.&quot; data-og-host=&quot;docs.tigera.io&quot; data-og-source-url=&quot;https://docs.tigera.io/calico/latest/reference/public-cloud/aws&quot; data-og-url=&quot;https://docs.tigera.io/calico/latest/reference/public-cloud/aws&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.tigera.io/calico/latest/reference/public-cloud/aws&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.tigera.io/calico/latest/reference/public-cloud/aws&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;Amazon Web Services | Calico Documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Advantages of using Calico in AWS.&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 data-ke-size=&quot;size16&quot;&gt;쉽게 시작하는 쿠버네티스(서지영) 책 참고&lt;/p&gt;</description>
      <category>Infra/쿠버네티스</category>
      <author>gunjoon98</author>
      <guid isPermaLink="true">https://gunjoon.tistory.com/201</guid>
      <comments>https://gunjoon.tistory.com/201#entry201comment</comments>
      <pubDate>Wed, 21 Feb 2024 13:10:15 +0900</pubDate>
    </item>
    <item>
      <title>SpringBoot, Vue3 프로젝트 CI/CD (2)</title>
      <link>https://gunjoon.tistory.com/199</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이번 글에서는 이전 글에 이어서 젠킨스 설정(소나 큐브와 연동), Nginx Proxy Manager 설정을 진행한다. 진행하기 전 소나 큐브와 포테이너에 접속해 계정을 만들고, 어떤 기능이 있는지 한번 살펴보자. 포테이너의 웹 UI로 편하게 컨테이너를 관리하고 모니터링 할 수 있으며 소나 큐브의 웹 UI로 정적 분석 결과를 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;젠킨스 시작&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;젠킨스란 빌드, 배포 과정을 자동화할 수 있는 소프트웨어이다. 설치형이기에 설치와 설정이 필요하다는 단점이 있지만 비용(돈)이 들지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #353638; text-align: left;&quot;&gt;웹 브라우저 URL 검색 창에 호스트 서버 IP:9090을 검색했을 때 아래의 화면이 나오면 정상 설치 된 것이다. 젠킨스는 편리하게 사용할 수 있도록 웹 인터페이스를 제공한다. 처음 접속 시 계정을 설정해야한다. &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;다운로드.png&quot; data-origin-width=&quot;1020&quot; data-origin-height=&quot;1288&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9kVLv/btsD3kssMTH/9rcxTDe9uIFhyoOytRfcXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9kVLv/btsD3kssMTH/9rcxTDe9uIFhyoOytRfcXK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9kVLv/btsD3kssMTH/9rcxTDe9uIFhyoOytRfcXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9kVLv%2FbtsD3kssMTH%2F9rcxTDe9uIFhyoOytRfcXK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1020&quot; height=&quot;1288&quot; data-filename=&quot;다운로드.png&quot; data-origin-width=&quot;1020&quot; data-origin-height=&quot;1288&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;젠킨스 컨테이너에 접속 후(docker exec 명령어 사용) 아래 명령어를 실행하고, 화면에 출력된 비밀번호를 Administrator password에 입력한다.&lt;/p&gt;
&lt;pre id=&quot;code_1706342137890&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cat /var/jenkins_home/secrets/initialAdminPassword&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #353638; text-align: left;&quot;&gt;Install suggested plugins 버튼을 눌러 인기있는 플러그인을 설치한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;다운로드 (1).png&quot; data-origin-width=&quot;1009&quot; data-origin-height=&quot;1288&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tFTdq/btsD4FCEv5g/enIqKOFgypaQTLHp5LGMg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tFTdq/btsD4FCEv5g/enIqKOFgypaQTLHp5LGMg1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tFTdq/btsD4FCEv5g/enIqKOFgypaQTLHp5LGMg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtFTdq%2FbtsD4FCEv5g%2FenIqKOFgypaQTLHp5LGMg1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1009&quot; height=&quot;1288&quot; data-filename=&quot;다운로드 (1).png&quot; data-origin-width=&quot;1009&quot; data-origin-height=&quot;1288&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;다운로드 (2).png&quot; data-origin-width=&quot;1006&quot; data-origin-height=&quot;1287&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zG8Kn/btsD2w1hc32/TkncbLv2RHOEdXK8GkKa51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zG8Kn/btsD2w1hc32/TkncbLv2RHOEdXK8GkKa51/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zG8Kn/btsD2w1hc32/TkncbLv2RHOEdXK8GkKa51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzG8Kn%2FbtsD2w1hc32%2FTkncbLv2RHOEdXK8GkKa51%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1006&quot; height=&quot;1287&quot; data-filename=&quot;다운로드 (2).png&quot; data-origin-width=&quot;1006&quot; data-origin-height=&quot;1287&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: #353638; text-align: left;&quot;&gt;아래 정보를 입력해 계정을 생성한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;다운로드 (3).png&quot; data-origin-width=&quot;1011&quot; data-origin-height=&quot;1280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c8efYp/btsDZ20NmdD/PYfH30YN2ltKOnuRX1kxtk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c8efYp/btsDZ20NmdD/PYfH30YN2ltKOnuRX1kxtk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c8efYp/btsDZ20NmdD/PYfH30YN2ltKOnuRX1kxtk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc8efYp%2FbtsDZ20NmdD%2FPYfH30YN2ltKOnuRX1kxtk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1011&quot; height=&quot;1280&quot; data-filename=&quot;다운로드 (3).png&quot; data-origin-width=&quot;1011&quot; data-origin-height=&quot;1280&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;background-color: #ffffff; color: #353638; text-align: left;&quot;&gt;Jenkins 관리 &amp;rarr; Plugins &amp;rarr; Available plugins&lt;/span&gt; 들어가 아래의 플러그인을 설치한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SonarQube Scanner : &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;소나 큐브 사용을 위함&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;maven Integration : 메이븐 설치를 위함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;nodeJS : nodeJS 설치를 위함&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1336&quot; data-origin-height=&quot;237&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dPMMao/btsD4TngBR4/XhHretbNdJzPTduVEewFR1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dPMMao/btsD4TngBR4/XhHretbNdJzPTduVEewFR1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dPMMao/btsD4TngBR4/XhHretbNdJzPTduVEewFR1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdPMMao%2FbtsD4TngBR4%2FXhHretbNdJzPTduVEewFR1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1336&quot; height=&quot;237&quot; data-origin-width=&quot;1336&quot; data-origin-height=&quot;237&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;Credentials 생성&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;Credentials는 외부 서버, 시스템에 대한 인증 정보(비밀키, 패스워드, 토큰값)을 말한다. &lt;b&gt;&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;Credentials로 인증 정보를 저장해두고 젠킨스가 해당 &lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;Credentials을 통해 외부 서버의 접근 권한을 얻는다.&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;젠킨스는 원격 저장소(GitHub, GitLab)로부터 git clone을 하여 원격 저장소의 파일을 가져와 빌드를 수행한다. 이를 위해서는 원격 저장소에 접근할 수 있는 권한이 필요하다. 때문에 gitlab의 access token을 발급받아 credentials을 만든다. 또한 필자의 젠킨스는 소나 큐브 서버에도 접근하므로 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;소나 큐브의 token을 발급받아&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;credentials을 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #353638; text-align: left;&quot;&gt;Jenkins 관리 &amp;rarr; Credentials로 이동한다. 아래와 같이 Add credentials 버튼을 누른다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;다운로드 (4).png&quot; data-origin-width=&quot;1234&quot; data-origin-height=&quot;552&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buSzPy/btsD6utZ417/JIF98Te5fjbqWwut1Jn0Xk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buSzPy/btsD6utZ417/JIF98Te5fjbqWwut1Jn0Xk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buSzPy/btsD6utZ417/JIF98Te5fjbqWwut1Jn0Xk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbuSzPy%2FbtsD6utZ417%2FJIF98Te5fjbqWwut1Jn0Xk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1234&quot; height=&quot;552&quot; data-filename=&quot;다운로드 (4).png&quot; data-origin-width=&quot;1234&quot; data-origin-height=&quot;552&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: #353638; text-align: left;&quot;&gt;kind는 Username and Password를 선택한다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Username :&lt;span&gt; 원격 저장소(GitLab, GitHub)의 닉네임&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 style=&quot;background-color: #ffffff;&quot;&gt;Password :&lt;span&gt; &lt;/span&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;gitlab의 토큰값 저장&lt;/span&gt;&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 style=&quot;background-color: #ffffff;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;ID : 임의로 지정&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;제목 없음.png&quot; data-origin-width=&quot;1771&quot; data-origin-height=&quot;807&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Npzek/btsDZ2mdci2/4cP0LRCHMUobNKjgPI2rVK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Npzek/btsDZ2mdci2/4cP0LRCHMUobNKjgPI2rVK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Npzek/btsDZ2mdci2/4cP0LRCHMUobNKjgPI2rVK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNpzek%2FbtsDZ2mdci2%2F4cP0LRCHMUobNKjgPI2rVK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1771&quot; height=&quot;807&quot; data-filename=&quot;제목 없음.png&quot; data-origin-width=&quot;1771&quot; data-origin-height=&quot;807&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 방식으로 소나 큐브의 토큰 값을 저장한 credentials을 만든다. (kind는 secret text로 지정한다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Secret : 소나 큐브의 토큰 값&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ID : 임의로 지정&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1762&quot; data-origin-height=&quot;643&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/n056E/btsD09egEBC/AqO1LfC41ri4YIpw8K9Nb1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/n056E/btsD09egEBC/AqO1LfC41ri4YIpw8K9Nb1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/n056E/btsD09egEBC/AqO1LfC41ri4YIpw8K9Nb1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fn056E%2FbtsD09egEBC%2FAqO1LfC41ri4YIpw8K9Nb1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1762&quot; height=&quot;643&quot; data-origin-width=&quot;1762&quot; data-origin-height=&quot;643&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같이 소나 큐브에 접속하여 토큰을 발급받을 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;캡처3.PNG&quot; data-origin-width=&quot;1386&quot; data-origin-height=&quot;379&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cbRkCI/btsD4vUtRaU/Kkl4LNmwX2YAaPbLv7IOJk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cbRkCI/btsD4vUtRaU/Kkl4LNmwX2YAaPbLv7IOJk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cbRkCI/btsD4vUtRaU/Kkl4LNmwX2YAaPbLv7IOJk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcbRkCI%2FbtsD4vUtRaU%2FKkl4LNmwX2YAaPbLv7IOJk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1386&quot; height=&quot;379&quot; data-filename=&quot;캡처3.PNG&quot; data-origin-width=&quot;1386&quot; data-origin-height=&quot;379&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1264&quot; data-origin-height=&quot;353&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buqoa6/btsD3NujoCK/ow21SJiv6iec42DwbyeGL1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buqoa6/btsD3NujoCK/ow21SJiv6iec42DwbyeGL1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buqoa6/btsD3NujoCK/ow21SJiv6iec42DwbyeGL1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbuqoa6%2FbtsD3NujoCK%2Fow21SJiv6iec42DwbyeGL1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/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;353&quot; data-origin-width=&quot;1264&quot; data-origin-height=&quot;353&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;SonarQube와 연동&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Jenkins 관리 &lt;span style=&quot;background-color: #ffffff; color: #353638; text-align: left;&quot;&gt;&amp;rarr; System으로 이동하고 아래와 같이 SonarQube server를 작성한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #353638; text-align: left;&quot;&gt;name : 소나 큐브 서버의 이름 (임의로 작성)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #353638; text-align: left;&quot;&gt;Server URL : 소나 큐브 서버의 URL&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #353638;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt; &lt;span style=&quot;background-color: #ffffff; color: #14141f; text-align: start;&quot;&gt;Server authentication token&lt;/span&gt; : 위에서 만든 credentials&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2153&quot; data-origin-height=&quot;747&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SdgpC/btsDZ3elwYI/qerpkrNEzQ9uqpdNrv8XOK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SdgpC/btsDZ3elwYI/qerpkrNEzQ9uqpdNrv8XOK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SdgpC/btsDZ3elwYI/qerpkrNEzQ9uqpdNrv8XOK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSdgpC%2FbtsDZ3elwYI%2FqerpkrNEzQ9uqpdNrv8XOK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2153&quot; height=&quot;747&quot; data-origin-width=&quot;2153&quot; data-origin-height=&quot;747&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;JDK 경로 지정, Maven와 NodeJS 설치&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;jenkins 관리&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #353638; text-align: left;&quot;&gt;&amp;rarr; Tool로 이동한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring Boot 앱 빌드에 사용되는 jdk가 jenkins 컨테이너 안에 있어야한다. jenkins 컨테이너를 받으면서 이미 jdk가 포함되어 있으므로 해당 jdk를 사용한다. (&lt;b&gt;필자의 jdk의 경로는 /opt/java/openjdk이며 이미 환경변수가 설정되어 있다.&lt;/b&gt;) 아래와 같이 jdk 경로를 지정한다. 만약 설치되어 있지 않다면 &lt;span style=&quot;background-color: #ffffff; color: #14141f; text-align: start;&quot;&gt;Install automatically 체크박스를 체크한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;캡처1.PNG&quot; data-origin-width=&quot;2149&quot; data-origin-height=&quot;503&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/broKgh/btsD27Uw0V7/p3RkrmHBTKuFqkAy4GKbn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/broKgh/btsD27Uw0V7/p3RkrmHBTKuFqkAy4GKbn0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/broKgh/btsD27Uw0V7/p3RkrmHBTKuFqkAy4GKbn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbroKgh%2FbtsD27Uw0V7%2Fp3RkrmHBTKuFqkAy4GKbn0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2149&quot; height=&quot;503&quot; data-filename=&quot;캡처1.PNG&quot; data-origin-width=&quot;2149&quot; data-origin-height=&quot;503&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 Spring Boot 앱 빌드에 사용되는 maven이 jenkins 컨테이너 안에 있어야한다. &lt;span style=&quot;background-color: #ffffff; color: #353638; text-align: left;&quot;&gt;아래와 같이 maven 정보를 등록하며 &lt;span style=&quot;background-color: #ffffff; color: #14141f; text-align: start;&quot;&gt;Install automatically 체크박스를 체크해 자동 설치를 진행한다.&lt;/span&gt; &lt;span style=&quot;background-color: #ffffff; color: #14141f; text-align: start;&quot;&gt;만약 이미 maven이 깔려 있다면 체크박스를 해제하고 maven 경로를 지정한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1744&quot; data-origin-height=&quot;551&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1VPWE/btsD2vuxKkw/Yex8aHnVvuw5t6CLSgOOf0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1VPWE/btsD2vuxKkw/Yex8aHnVvuw5t6CLSgOOf0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1VPWE/btsD2vuxKkw/Yex8aHnVvuw5t6CLSgOOf0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1VPWE%2FbtsD2vuxKkw%2FYex8aHnVvuw5t6CLSgOOf0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1744&quot; height=&quot;551&quot; data-origin-width=&quot;1744&quot; data-origin-height=&quot;551&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 vue3 프로젝트를 빌드할 것이므로 jenkins 컨테이너 안에 nodeJS가 있어야한다. 아래와 같이 NodeJS 정보를 등록한다. &lt;span style=&quot;background-color: #ffffff; color: #14141f; text-align: start;&quot;&gt;Install automatically 체크박스를 체크해 자동 설치를 진행한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2156&quot; data-origin-height=&quot;879&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLjOVZ/btsD2vH53wH/SI13Bi4fDA64UuNoKGDBI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLjOVZ/btsD2vH53wH/SI13Bi4fDA64UuNoKGDBI1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLjOVZ/btsD2vH53wH/SI13Bi4fDA64UuNoKGDBI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLjOVZ%2FbtsD2vH53wH%2FSI13Bi4fDA64UuNoKGDBI1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2156&quot; height=&quot;879&quot; data-origin-width=&quot;2156&quot; data-origin-height=&quot;879&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;jenkins 관리&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #353638; text-align: left;&quot;&gt;&amp;rarr; Tool에서 &lt;span style=&quot;background-color: #ffffff; color: #14141f; text-align: start;&quot;&gt;Install automatically 체크박스를 체크해 설치한 Tool은 언제 설치되고, 어디에 저장될까? &lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #353638; text-align: left;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #14141f; text-align: start;&quot;&gt;아래 파이프라인을 보자. &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #353638; text-align: left;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #14141f; text-align: start;&quot;&gt;젠킨스&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;는 Pipeline 내에서 &lt;/span&gt;tools에 정의된 Tool을 설치하며 (이미 설치되었다면 설치하지 않는다.) Tool의 경로를 &lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;Jenkins 에이전트에게 알려준다. 따라서 별다른 환경 변수 설정 없이 해당 Tool을 사용할 수 있다. &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #353638; text-align: left;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #14141f; text-align: start;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;참고로 &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #353638; text-align: left;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #14141f; text-align: start;&quot;&gt;젠킨스가 설치한 툴은&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #14141f; text-align: start;&quot;&gt;&lt;span style=&quot;color: #374151;&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;/var/jenkins_home/tools에 저장된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1706626860816&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pipeline {
    agent any
    
    tools {
        maven &quot;maven&quot; // Specify the Maven tool name configured in Jenkins
    }
    
    stages {
        stage('Build') {
            steps {
                script {
                    sh 'mvn -version' // Maven을 사용할 수 있음을 확인하기 위한 명령
                }
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위&amp;nbsp;파이프라인의 tools 부분에서 maven &quot;maven&quot;을 넣었다. maven은 tool의 이름을 나타내며 옆의 문자열은 &lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;Global Tool Configuration에서 도구를 추가할 때의 이름을 지정한다. (&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;필자는 위에서 메이븐을 추가할 때 이름을 maven으로 지었다.) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #374151;&quot;&gt;tool의 이름은 이미 정의되어 있으므로 잘못 지정하면 파이프라인 작동 시 아래와 같은 오류가 뜬다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1706968157359&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Started by user admin
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
WorkflowScript: 5: Invalid tool type &quot;nodes&quot;. Valid tool types: [ant, hudson.tasks.Ant$AntInstallation, git, hudson.plugins.git.GitTool, gradle, hudson.plugins.gradle.GradleInstallation, jdk, hudson.model.JDK, jgit, org.jenkinsci.plugins.gitclient.JGitTool, jgitapache, org.jenkinsci.plugins.gitclient.JGitApacheTool, maven, hudson.tasks.Maven$MavenInstallation, nodejs, jenkins.plugins.nodejs.tools.NodeJSInstallation, hudson.plugins.sonar.SonarRunnerInstallation, hudson.plugins.sonar.MsBuildSQRunnerInstallation] @ line 5, column 9.
           nodes &quot;nodeJS&quot;
           ^

1 error

	at org.codehaus.groovy.control.ErrorCollector.failIfErrors(ErrorCollector.java:309)
	at org.codehaus.groovy.control.CompilationUnit.applyToPrimaryClassNodes(CompilationUnit.java:1107)
	at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:624)
	at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:602)
	at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:579)
	at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:323)
	at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:293)
	at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.GroovySandbox$Scope.parse(GroovySandbox.java:163)
	at org.jenkinsci.plugins.workflow.cps.CpsGroovyShell.doParse(CpsGroovyShell.java:190)
	at org.jenkinsci.plugins.workflow.cps.CpsGroovyShell.reparse(CpsGroovyShell.java:175)
	at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution.parseScript(CpsFlowExecution.java:636)
	at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution.start(CpsFlowExecution.java:582)
	at org.jenkinsci.plugins.workflow.job.WorkflowRun.run(WorkflowRun.java:335)
	at hudson.model.ResourceController.execute(ResourceController.java:101)
	at hudson.model.Executor.run(Executor.java:442)
Finished: FAILURE&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;젠킨스 파이프라인&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링 부트 앱, vue3를 빌드, 배포하는 파이프라인을 각각 만든다. &lt;span style=&quot;background-color: #ffffff; color: #353638; text-align: left;&quot;&gt;아래와 같이 pipeline을 생성한다. &lt;b&gt;(자신의 상황에 맞게 수정하자) &lt;/b&gt;파이프라인이 좋은 점은 UI로 쉽게 Stage별 성공 여부를 확인할 수 있고 커스텀이 자유롭다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- spring boot 앱 빌드 / 배포&lt;/p&gt;
&lt;pre id=&quot;code_1706349555033&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pipeline {
    agent any
    
    tools {
        maven &quot;maven&quot; // Specify the Maven tool name configured in Jenkins
    }
    
    stages {
        stage('Clone Repository') {
            steps {
                script {
                    git branch: 'back_master', credentialsId: 'gitlab-access-token', url: 'https://gitlab.com/username/yourProject.git'
                }
            }
        }
        
        stage('Build') { 
            steps {
	            dir('backend/Exhale') {
                    sh 'mvn clean package -DskipTests'
        	    }
            }
        }
        
        stage('SonarQube analysis') {
             steps {
	             withSonarQubeEnv('sonarqube') {
                        dir('backend/Exhale') {
                            sh 'mvn sonar:sonar'
        	            }
                  }
             }
         }
         
         //테스트 과정 생략
         
        stage('Deploy') { 
            steps {
                sh 'ssh ubuntu@서버IP &quot;sudo sh ~/deploy/backend/deploy.sh&quot;'
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- vue3 앱 빌드 / 배포&lt;/p&gt;
&lt;pre id=&quot;code_1706351867243&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pipeline {
    agent any
    
    tools {
        nodejs &quot;nodeJS&quot;
    }
    
    stages {
        stage('Clone Repository') {
            steps {
                script {
                    git branch: 'front_master', credentialsId: 'gitlab-access-token', url: 'https://gitlab.com/username/yourProject.git'
                }
            }
        }
        
        stage('Install Dependencies') {
            steps {
                dir('frontend/Exhale') {
                    sh 'npm install'
        	    }
            }
        }

        stage('Build') {
            steps {
                dir('frontend/Exhale') {
                    sh 'npm run build:production'
        	    }
            }
        }
        
        stage('Deploy') {
            steps {
                sh 'ssh ubuntu@서버IP &quot;sudo sh ~/deploy/frontend/deploy.sh&quot;'
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;배포 과정&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 파이프라인의 Deploy 스테이지를 보면 ssh을 통해 전에 작성한 배포 쉘 스크립트를 실행한다. &lt;b&gt;따라서 사전에 젠킨스 컨테이너에서 EC2(호스트)로 ssh 연결이 가능하도록 만들어야한다.&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;배포의 방법은 여러가지다. 대표적인 방법은 2개가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 빌드 결과물을 ssh 혹은 scp을 통해, 동작중인 개발/운영 컨테이너에 전달&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 빌드 결과물이 담긴 컨테이너 이미지를 만들고 이미지를 EC2(호스트)에 전달하거나 hub에 등록, 호스트에서 이미지를 받아 컨테이너로 만든 후 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 외에도 여러 방법이 있지만 필자는 1번 방식을 사용했다. 2번 방식도 많이 쓰는 것 같다.&lt;/p&gt;
&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;Webhook을 통한 빌드 유발&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #353638; text-align: left;&quot;&gt;GitLab, GitHub의 WebHook 기능을 통해 자동 배포를 수행할 수 있다. &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;파이프라인 구성&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #353638; text-align: left;&quot;&gt;&amp;rarr;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Build Triggers&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #353638; text-align: left;&quot;&gt;&amp;rarr; Build when a change is pushed to GitLab webhook URL 버튼을 클릭하고 아래와 같이 &lt;span style=&quot;background-color: #ffffff; color: #353638; text-align: left;&quot;&gt;GitLab Webhook URL와 Secret token을 확인한다.&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;다운로드 (3).png&quot; data-origin-width=&quot;708&quot; data-origin-height=&quot;254&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Q5C9L/btsEWKx2b7n/DzYuLZ05OdtwCQwc3jleNk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Q5C9L/btsEWKx2b7n/DzYuLZ05OdtwCQwc3jleNk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Q5C9L/btsEWKx2b7n/DzYuLZ05OdtwCQwc3jleNk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQ5C9L%2FbtsEWKx2b7n%2FDzYuLZ05OdtwCQwc3jleNk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;708&quot; height=&quot;254&quot; data-filename=&quot;다운로드 (3).png&quot; data-origin-width=&quot;708&quot; data-origin-height=&quot;254&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;다운로드.png&quot; data-origin-width=&quot;855&quot; data-origin-height=&quot;859&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cIJ4oM/btsEZQRfKiw/E6yKUUsVHcKAweUmpTuAAK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cIJ4oM/btsEZQRfKiw/E6yKUUsVHcKAweUmpTuAAK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cIJ4oM/btsEZQRfKiw/E6yKUUsVHcKAweUmpTuAAK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcIJ4oM%2FbtsEZQRfKiw%2FE6yKUUsVHcKAweUmpTuAAK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;855&quot; height=&quot;859&quot; data-filename=&quot;다운로드.png&quot; data-origin-width=&quot;855&quot; data-origin-height=&quot;859&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;background-color: #ffffff; color: #353638; text-align: left;&quot;&gt;아래와 같이 GitLab에서 Webhook 설정을 진행한다. URL에는 위의 GitLab Webhook URL를 Secret token에는 위의 Secret token 값을 넣는다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;다운로드 (1).png&quot; data-origin-width=&quot;1004&quot; data-origin-height=&quot;1219&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qKE9M/btsE0G8vwug/ID6dlr79oH2f21l6XRIfV1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qKE9M/btsE0G8vwug/ID6dlr79oH2f21l6XRIfV1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qKE9M/btsE0G8vwug/ID6dlr79oH2f21l6XRIfV1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqKE9M%2FbtsE0G8vwug%2FID6dlr79oH2f21l6XRIfV1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1004&quot; height=&quot;1219&quot; data-filename=&quot;다운로드 (1).png&quot; data-origin-width=&quot;1004&quot; data-origin-height=&quot;1219&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: #353638; text-align: left;&quot;&gt;Test 버튼을 통해 Webhook 설정이 잘 되었는지 확인하자.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;다운로드 (4).png&quot; data-origin-width=&quot;1010&quot; data-origin-height=&quot;322&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LIPly/btsEZyXtcf8/KdVfE8fGJvrApKAQLLYBl0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LIPly/btsEZyXtcf8/KdVfE8fGJvrApKAQLLYBl0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LIPly/btsEZyXtcf8/KdVfE8fGJvrApKAQLLYBl0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLIPly%2FbtsEZyXtcf8%2FKdVfE8fGJvrApKAQLLYBl0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1010&quot; height=&quot;322&quot; data-filename=&quot;다운로드 (4).png&quot; data-origin-width=&quot;1010&quot; data-origin-height=&quot;322&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 style=&quot;border-left: 8px solid #febf00; padding: 5px 15px; margin: 80px 0px 40px 0px;&quot; data-ke-size=&quot;size26&quot;&gt;Nginx 설정&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;http://domain으로 보낸 모든 요청은 nginx 서버가 수신한다. nginx 서버로 보내는 요청 중 /api로 시작하는 요청, 즉 백엔드 요청을 백엔드 서버로 프록시하는 설정을 진행한다. 해당 설정을 하고나서 http://domain/api로 요청을 보내면 nginx가 해당 요청을 백엔드 서버로 보내준다. 또한 스프링 앱의 context root 경로가 /api로 설정되어 있어야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;docker exce 명령어 혹은 포테이너로 nginx 컨테이너에 접속한다. 설정 파일을 작성해야 되기에 vim 도구를 설치해야한다. 아래와 같이 vim 도구를 설치할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1706966693416&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apt update
apt install vim&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후 nginx 설정 파일로 이동하여 편집한다.&lt;/p&gt;
&lt;pre id=&quot;code_1706966828226&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;vi /etc/nginx/conf.d/default.conf&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같이 location /api를 추가한다. /api로 시작하는 요청은 백엔드 서버로 프록시한다는 설정이다. 혹시 프록시가 안된다면 &lt;b&gt;nginx 컨테이너와 백엔드 서버가 동작중인 컨테이너가 통신이 되는지 ping 명령어로 확인해보자.&amp;nbsp;&lt;/b&gt;필자는 같은 도커 네트워크로 묶어주었음에도 서로 간 통신이 되지 않아 컨테이너를 재시작하거나 둘 컨테이너의 도커 네트워크를 disconnect 했다가 connect 시켜줬더니 통신이 되었다.&lt;/p&gt;
&lt;pre id=&quot;code_1706966878170&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;server {
    listen       80;
    listen  [::]:80;
    server_name  localhost;

    #access_log  /var/log/nginx/host.access.log  main;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    location /api {
            proxy_pass http://백엔드서버IP(또는 컨테이너 명):8080;
    }

    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    #
    #location ~ \.php$ {
    #    proxy_pass   http://127.0.0.1;
    #}

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    #location ~ \.php$ {
    #    root           html;
    #    fastcgi_pass   127.0.0.1:9000;
    #    fastcgi_index  index.php;
    #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
    #    include        fastcgi_params;
    #}

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /\.ht {
    #    deny  all;
    #}
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Infra/CI&amp;amp;CD</category>
      <author>gunjoon98</author>
      <guid isPermaLink="true">https://gunjoon.tistory.com/199</guid>
      <comments>https://gunjoon.tistory.com/199#entry199comment</comments>
      <pubDate>Sat, 27 Jan 2024 16:45:06 +0900</pubDate>
    </item>
  </channel>
</rss>