<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>jongviet</title>
    <link>https://jongviet.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Sat, 20 Jun 2026 12:53:59 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>jongviet</managingEditor>
    <item>
      <title>March 3, 2024 - 오토스케일링으로 매번 흐트러지는 노드 별 파드 수, 균형을 어떻게 맞출 수 있을까?</title>
      <link>https://jongviet.tistory.com/177</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*3월3일&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;eks 오토스케일링을 통해 트래픽에 맞춰 노드가 죽고 뜬다. 내부에 속한 파드 또한 이리 저리 이동하면서 자리 잡게 되는데 노드 확대 &amp;amp; 축소가 여러번 반복되다보면 특정 디플로이먼트의 파드가 균형없이 여러 노드에 배정되게 된다. 결과적으로 새로 뜬 노드에 주요한 디플로이먼트가 배정되지 않는 상황도 초래하고 노드 별 CPU가 불균형하게 사용되게 된다.&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;트래픽을 많이 발생시키는 디플로이먼트의 파드들은 기본적으로 HPA를 적용했었고, 적용된 디플로이먼트는 노드 수를 초과하는 수의 파드를 최소한 가지게 된다.&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;&lt;b&gt;*HPA란(HorizontalPodAutoscaler)&lt;/b&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;-&amp;nbsp;디플로이먼트&amp;nbsp;단위로&amp;nbsp;워크로드&amp;nbsp;크기에&amp;nbsp;따라&amp;nbsp;자동으로&amp;nbsp;파드&amp;nbsp;수를&amp;nbsp;조절해주는&amp;nbsp;기능&lt;br /&gt;-&amp;nbsp;디플로이먼트&amp;nbsp;단위로&amp;nbsp;yaml을&amp;nbsp;제작하며,&amp;nbsp;CPU&amp;nbsp;사용률&amp;nbsp;타겟을&amp;nbsp;설정&amp;nbsp;할&amp;nbsp;수&amp;nbsp;있다.&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 아래 표와 같이 어떤 노드는 특정 디플로이먼트의 파드 5개를 가지고, 또 다른 노드를 2개 밖에 가지지 못하는 상황이 생긴다. 과한 트래픽을 발생시키는 주요 디플로이먼트라고 가정했을 때 특정 노드에 트래픽이 몰려 CPU와 메모리 사용률을 과하게 유발하고 이는 해당 노드로 들어오는 요청에 매우 늦은 응답을 제공 할 수 밖에 없게 만든다.&lt;/p&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;411&quot; data-origin-height=&quot;506&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bw61Js/btsFp7qWqYR/39CMaHZd9ynNBFMXe3tcwk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bw61Js/btsFp7qWqYR/39CMaHZd9ynNBFMXe3tcwk/img.png&quot; data-alt=&quot;적용 전 특정 디플로이먼트의 노드 별 배정&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bw61Js/btsFp7qWqYR/39CMaHZd9ynNBFMXe3tcwk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbw61Js%2FbtsFp7qWqYR%2F39CMaHZd9ynNBFMXe3tcwk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;411&quot; height=&quot;506&quot; data-origin-width=&quot;411&quot; data-origin-height=&quot;506&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;적용 전 특정 디플로이먼트의 노드 별 배정&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서칭을 통해 Descheduler를 helm 적용 했음에도 이러한 현상은 파드 배정 불균형 현상은 크게 개선되지 않았다. 그러던 와중 이러한 고민을 해결 해줄 수 있는 topologySpreadConstraints라는 설정값을 외부 조언을 통해 알게 되었다. 이는 파드의 균등한 분포를 위한 설정인데, 주요한 설정값은 아래와 같다.&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;maxSkew // 적용된 숫자만큼의 차이만 동일 디플로이먼트가 각 노드에 배정 될 때 허용. 해당 값이 1이면 3,3,3,3,4,4 정도와 같은 노드 별 파드 배정을 가지게 됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;topologyKey // 어느 단위로 차이를 따질 지 정하는 필드. kubernetes.io/hostname는 노드 기준으로 차이를 따짐. 그 외 다양한 기준이 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;whenUnsatisfiable // 만약 maxSkew가 적용 될 수 없는 상황이라면 어떻게 처리할지에 대한 설정값. DoNotSchedule은 maxSkew 값이 만족되지 못하는 상황일 때 스케쥴러에 신규 파드를 배정 조차 하지 않도록 하는 것이고 ScheduleAnyway는 최대한 적합한 곳에 배정하는 것이다.&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;설정값을 적용하면 아래와 같이 완벽한 수준의 노드 별 파드 배치를 가지게된다. 물론 DoNotSchedule이라는 설정값으로 인해 노드가 새로 뜨고 죽을 때 일부 파드가 pending 상태로 잠시 동안 남아 있게 되지만 오랜 시간이 소요 되지 않는 것으로 확인했다.&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-origin-width=&quot;409&quot; data-origin-height=&quot;424&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/chIMXv/btsFqLH0rHl/w8q62kZbUnhopNK9gBKzUK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/chIMXv/btsFqLH0rHl/w8q62kZbUnhopNK9gBKzUK/img.png&quot; data-alt=&quot;적용 후 특정 디플로이먼트의 노드 별 배정&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/chIMXv/btsFqLH0rHl/w8q62kZbUnhopNK9gBKzUK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FchIMXv%2FbtsFqLH0rHl%2Fw8q62kZbUnhopNK9gBKzUK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;409&quot; height=&quot;424&quot; data-origin-width=&quot;409&quot; data-origin-height=&quot;424&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;적용 후 특정 디플로이먼트의 노드 별 배정&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주요 디플로이먼트에 해당 설정을 적용한 이후, 노드 별 CPU 사용률이 꽤 균등하게 배정되게 되었고 전반적으로 균형있는 자원 사용이 이루어질 수 있었다.&lt;/p&gt;</description>
      <category>kubernetes</category>
      <category>Kubernetes</category>
      <category>topologySpreadConstraints</category>
      <author>jongviet</author>
      <guid isPermaLink="true">https://jongviet.tistory.com/177</guid>
      <comments>https://jongviet.tistory.com/177#entry177comment</comments>
      <pubDate>Sun, 3 Mar 2024 15:46:00 +0900</pubDate>
    </item>
    <item>
      <title>Feb 29, 2024 - 쿠버네티스 내 배치 서버 파드, 오토스케일링으로 인해 갑자기 죽을 때 하던일은 마저하고 떠나보낼 수는 없을까..?</title>
      <link>https://jongviet.tistory.com/176</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*2월29일&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;트래픽 폭증으로 인해 AWS EKS 오토스케일링을 적용하면서 다양한 문제가 생기게 되었다. 그 중 배치 서버의 파드가 cron으로 돌아가는 테스크를 완료 하지 않은 시점에 지속적으로 종료되는 문제가 발생했다.&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;새로운 EC2에 배치 서버를 띄우면 쉽게 해결이 되지만,&amp;nbsp; 여러 보안 설정, 다른 배포 방법 등.. 너무 귀찮고 관리 범위도 많아진다. 그렇다고 배치서버의 파드를 2개로 증가시키면 멱등성이 확보되지 않은 상황에서 중복된 일을 하게 되는 문제 또한 발생한다.&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;이러한 고민을 해결해주는 설정값을 외부 조언을 통해 확인 할 수 있었는데, 바로 terminationGracePeriodSeconds이다. 직역하자면 종료 유예 기간 초 정도이다.&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;배치 서버 yaml 내 아래 설정값만 넣으면 오토스케일링을 통해 축소 노드에 속한 파드가 죽어도 해당 시간 동안의 실행을 보장한다. 일반적으로 하기 설정값이 별도로 지정되지 않으면 30초 정도의 시간을 가진 후 종료(sigterm)하는데, 이 시간을 인위적으로 조정할 수 있다. &lt;b&gt;yaml 내 정확하게 어디에 넣어야 하는게 궁금하다면.. phind로 가서 적용하고자 하는 yaml을 넣고 넣어달라고 하면된다.&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;일단 오토스케일링으로 인해 축소 명령을 받은 노드에 속한 파드는 terminating 상태로 전환되고, 전환되는 시점에 Iptable에서 해당 파드의 ip가 제거되기에 추가적인 요청이 들어올 일은 전혀 없다. 다만 본 종료유예기간을 너무 긴 시간 동안 가지면 적절하게 노드가 죽지 못하고 바로 바로 죽지 않는 노드로 인해 비용 문제로 이어질 수 있다. 따라서 배치서버에 적용한다면 각 프로세스가 너무 과한 시간을 잡아먹지 않도록 로직을 손보는 것이 먼저 선행되어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*리눅스 종료 신호 관련&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-sigterm: 이 신호를 받은 프로세스는 별도 세팅이 있지 않는 한 기본적으로 부여된 30초의 시간 내 프로세스를 마무리하고 정상 종료함. 다만 해당 유예 기간 동안 프로세스가 종료되지 않으면 sigkill을 보내서 즉시 종료 처리해버림&lt;br /&gt;-sigkill: 프로세스에게 시간을 주지 않고 즉시 종료&lt;br /&gt;-sigint: 로컬 터미널에서 프로세스 종료할 때의 케이스(ctrl + c)&lt;/p&gt;</description>
      <category>kubernetes</category>
      <category>Kubernetes</category>
      <category>SIGKILL</category>
      <category>sigterm</category>
      <category>terminationGracePeriodSeconds</category>
      <author>jongviet</author>
      <guid isPermaLink="true">https://jongviet.tistory.com/176</guid>
      <comments>https://jongviet.tistory.com/176#entry176comment</comments>
      <pubDate>Thu, 29 Feb 2024 07:51:58 +0900</pubDate>
    </item>
    <item>
      <title>Feb 28, 2024 - 3일만에 900만건의 데이터 생성.. RDB 파티셔닝 / 인덱싱 적용</title>
      <link>https://jongviet.tistory.com/175</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;*2월28일&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;너무 오랜만에 포스팅을 한다. 게을러진 탓도 있고 실무에서 벌어지는 일들을 대응하느라 마음의 여유가 부족했다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;회사 비즈니스 모델이 전환되면서 엄청난 규모의 데이터가 매일 생성되게 되었다. (일 기준 약 300만..) 제휴를 맺고 있는 각 파트너에게 다양한 방향에서 여러 지표를 제공해야해서 다양한 이벤트(유저 동작)으로 인해 파생되는 로우데이터가 매우 잘게 나뉘어 생성되고, 그에 따라 매일 생성되는 데이터의 수도 압도적으로 많아졌다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그전까지 NoSQL을 사내에서 주력으로 사용하다보니 여러 개념이 부족했었는데 이번 기회에 RDB에 데이터를 축적하면서 RDB에 대해 많이 익히게 되었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;먼저 RDB 파티셔닝에 대한 개념이 없어서 엄청나게 많은 수가 생성되는 데이터 타입을 별도 테이블로 이관 하는 작업을 하고 있었다... 마이그레이션 작업을 함과 동시에 진짜 이게 맞나 싶어 서칭을 했고, 파티셔닝을 통해서 동일한 테이블 내에서 여러 테이블로 논리적으로 분리 할 수 있다는 개념을 알게 되었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;파티셔닝에는 아래와 같은 개념이 있고,&lt;/span&gt;&lt;/p&gt;
&lt;div style=&quot;color: #333333; text-align: start;&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;수직적 파티셔닝:&amp;nbsp;&amp;nbsp;칼럼 단위 째는 것. 즉 칼럼 단위 테이블 분할임&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;수평적 파티셔닝: 테이블의 row를 분할하여 여러개로 나누는 것. 범위 분할(날짜), 목록 분할(특정 타입 칼럼 기준) 등이 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;결과적으로 날짜 범위 파티셔닝을 적용한 후 아래와 같이 월 별 파티셔닝을 별도 생성하였다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;기본적인 커맨드는 서칭해보면 쉽게 나오지만 아래와 같다. 해당 날짜 범위에 속하지 않는 데이터가 삽입될 시 에러가 뜬다. 자동으로 굴러가도록 설정할 방법이 있긴 한 것 같은데 현재 급한 상황이라 수동으로 현재~25년까지 월 별로 파티셔닝을 별도 생성했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;create&amp;nbsp;table&amp;nbsp;{partition_table_name}&amp;nbsp;partition&amp;nbsp;of&amp;nbsp;{source_table}&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;for&amp;nbsp;values&amp;nbsp;from&amp;nbsp;('2025-04-30T15:00:00.000Z')&amp;nbsp;to&amp;nbsp;('2025-05-31T14:59:59.999Z');&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;기존 테이블 -&amp;gt; 파티셔닝된 테이블로 마이그레이션 시 아래와 같이 실행시간을 먼저 확인해보고 진행하는게 낫다. 아래는 두 테이블 칼럼이 모두 같다는 가정하에 진행하는 것이고, 칼럼이 다르거나 특정 칼럼의 값이 변경되어야 한다면 별도 수정이 필요하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;BEGIN; // 실 테이블에 적용 없이 테스팅만 할 때 사용&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;EXPLAIN ANALYZE // 본 쿼리 분석하여 결과 값 리턴&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;INSERT INTO new_table&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;SELECT * FROM original_table;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;ROLLBACK; // 실 테이블에 적용 없이 테스팅만 할 때 사용&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;다시 하나의 테이블이 900만 건의 데이터를 몰아 넣다보니 당연히 인덱싱이 필요하게 되었다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;인덱싱의 경우, 카디널리티, 선택도, 활용도, 전체 테이블 로우의 수를 감안하여 설정하였다. 서칭해보면 다 독립적으로 카디널리티가 높을 수록 좋다 / 선택도가 낮을 수록 좋다... 와 함께 원론적인 소리만해서 &amp;ldquo;그래서 어떤 칼럼에 적용을 하란거냐...&amp;rdquo;가 입밖으로 뛰쳐 나왔다.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;결론적으로 전체 테이블 로우의 수와 활용도가 매우 중요하다. 현재까지 약 900만 로우의 데이터가 쌓였는데,  사용중인 DB(postgresql)와 같은 칼럼이 존재해서 선택도가 100%로 나오지 않는 이상, 대부분이 매우 낮은 선택도가 나오게 된다. (100%의 선택도는 사실상 풀스캔... 인덱싱하면서 오버헤드만 잡아먹음..) 인덱싱 걸린 칼럼 내 값 기준으로 어쨌든 서칭 범위를 좁혀 주기에 WHERE절에서 많이 활용하는 칼럼은 인덱싱 해주는게 실 효과가 좋았다. (비교 테스트 완료)&lt;/span&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;아직 개념이 부족한 부분이 많아서 추가적인 수정이 들어갈 수 있을 것 같다.&lt;/span&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;추가적으로 인덱싱 시 주요하게 활용한 지표들의 개념은 아래와 같다.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;카디널리티 -&amp;nbsp;특정 데이터 집합의 유니크한 값의 개수&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;선택도 - 특정 id값 감안 시, 약 6천개의 특정 값 &amp;rarr; 6000 / 9million = 0.000666...&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;활용도 - 말그대로 조건절 등에서 자주 활용되는 칼럼&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;전체 데이터 로우 수 - 9m.. &amp;rarr; 월 별 파티셔닝이 적용되어 있지만 향후 범위 넓게 조회 시 수천만~수억&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;*인덱싱 관련 아래 인프런 질문&amp;amp;답변 링크와 함께 연결된 원문 링크에서 매우 큰 도움을 받았다.&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;a href=&quot;https://www.inflearn.com/questions/720337/%EC%9D%B8%EB%8D%B1%EC%8A%A4-%EC%B9%B4%EB%94%94%EB%84%90%EB%A6%AC%ED%8B%B0-%EB%B6%80%EB%B6%84-%EC%A7%88%EB%AC%B8%EC%9D%B4%EC%9E%88%EC%8A%B5%EB%8B%88%EB%8B%A4&quot;&gt;https://www.inflearn.com/questions/720337/%EC%9D%B8%EB%8D%B1%EC%8A%A4-%EC%B9%B4%EB%94%94%EB%84%90%EB%A6%AC%ED%8B%B0-%EB%B6%80%EB%B6%84-%EC%A7%88%EB%AC%B8%EC%9D%B4%EC%9E%88%EC%8A%B5%EB%8B%88%EB%8B%A4&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;a href=&quot;https://expertoracle.com/2017/11/15/db-tuning-basics-1-selectivity-and-cardinality/&quot;&gt;https://expertoracle.com/2017/11/15/db-tuning-basics-1-selectivity-and-cardinality/&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>indexing</category>
      <category>Partitioning</category>
      <category>RDB</category>
      <category>선택도</category>
      <category>카디널리티</category>
      <author>jongviet</author>
      <guid isPermaLink="true">https://jongviet.tistory.com/175</guid>
      <comments>https://jongviet.tistory.com/175#entry175comment</comments>
      <pubDate>Wed, 28 Feb 2024 18:57:03 +0900</pubDate>
    </item>
    <item>
      <title>May 29, 2023 - Jenkins 활용 CI/CD 세팅 방법</title>
      <link>https://jongviet.tistory.com/172</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*5월29일&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;-전전 개발 직장에서 git action과 Jenkins를 활용하여 CI/CD를 구축한 시니어분이 있었다. 당시에는 그냥 사용해보기만 했었는데 현 직장에서 깃 푸시에 맞춰 빌드 후 쿠버네티스 pod를 띄우는 과정까지 처리하게 되었다. 최초 세팅이고 아직 테스트 쪽이 빠져있어 어떻게 세팅했는지만 개인적으로 정리해보고자 한다.&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;$df -h // 용량&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$free -h //메모리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$sudo find / -name 'swap.*&amp;rsquo; // 파일찾기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$cat // 파일 터미널 상 표시&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$ls -al // 숨김 파일 포함 전체 파일 표시&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$vi&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$vim&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.적절한 AWS EC2 인스턴스를 선택해서 생성 후 보안그룹, swap memory 처리까지 해보자.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-일단 일부 웹 프로젝트에만 선제적으로 적용할 계획이고 jenkins 세팅을 통해 동시 빌드가 불가능하도록 세팅해 최소한의 사양만 가지고 가기로 했다.&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;ubuntu 20.04 LTS, x86 / 16gb gp3 / rsa key pair / 2gb memory - 프리티어보다 한 단계 높은 수준&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;-보안그룹은 22, 80, 443, jenkinsPort 정도 내 아이피 기준으로 최소한으로 열고, 추가적으로 git webhook용으로 하기를 뚫어줘야 push 이후 jenkins 빌드 작업이 된다.&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;192.30.252.0/22, 140.82.112.0/20&amp;nbsp; &amp;nbsp; // gitwebhook&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;-swap memory 설정은 저사양 ec2 인스턴스 사용 시 거의 필수적으로 적용하는데 ec2 메모리가 너무 작아서 실제 디스크의 용량을 좀 당겨 쓰는 개념이다. 일반적으로 ec2 메모리 기준 2배 정도가 추천된다고 한다. (터지게 하지 않는 정도의 목적.. 스왑메모리를 통한다면 당연히 속도는 좀 더 느리다)&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;$ sudo dd if=/dev/zero of=/swapfile bs=128M count=32&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; // bs*count가 최종 용량이라고 생각하면된다.&lt;br /&gt;$ sudo chmod 600 /swapfile&lt;br /&gt;$ sudo mkswap /swapfile&lt;br /&gt;$ sudo swapon /swapfile&lt;br /&gt;$ sudo swapon -s&lt;br /&gt;$ sudo vi /etc/fstab&amp;nbsp; &amp;nbsp; // 맨 아래줄에 '/swapfile swap swap defaults 0 0' 삽입&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;-free -h를 통해 보면 적절하게 할당되었음을 볼 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;total&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;used&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;free&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;shared&amp;nbsp;&amp;nbsp;buff/cache&amp;nbsp;&amp;nbsp;&amp;nbsp;available&lt;br /&gt;Mem:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;1.9Gi&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;829Mi&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;166Mi&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;0.0Ki&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;977Mi&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;970Mi&lt;br /&gt;Swap:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;4.0Gi&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;0B&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;4.0Gi&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;$&amp;nbsp;sudo&amp;nbsp;swapoff&amp;nbsp;-v&amp;nbsp;/swapfile&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$ sudo vi /etc/fstab // '/swapfile swap swap defaults 0 0' 주석처리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$ sudo rm /swapfile&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;-이렇게 해준다면 적어도... 0.5gb 메모리 기준으로도 yarn 하다가 터지지는 않는다. (물론 프로젝트 사이즈 별로 다름..)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2.Jenkins 셋업&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;$ curl -fsSL &lt;a href=&quot;https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key&lt;/a&gt;&amp;nbsp;|&amp;nbsp;sudo&amp;nbsp;tee&amp;nbsp;\&lt;br /&gt;&amp;nbsp;&amp;nbsp;/usr/share/keyrings/jenkins-keyring.asc&amp;nbsp;&amp;gt;&amp;nbsp;/dev/null&lt;br /&gt;echo&amp;nbsp;deb&amp;nbsp;[signed-by=/usr/share/keyrings/jenkins-keyring.asc]&amp;nbsp;\&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;https://pkg.jenkins.io/debian-stable&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://pkg.jenkins.io/debian-stable&lt;/a&gt;&amp;nbsp;binary/&amp;nbsp;|&amp;nbsp;sudo&amp;nbsp;tee&amp;nbsp;\&lt;br /&gt;&amp;nbsp;&amp;nbsp;/etc/apt/sources.list.d/jenkins.list&amp;nbsp;&amp;gt;&amp;nbsp;/dev/null&lt;br /&gt;sudo&amp;nbsp;apt-get&amp;nbsp;update&lt;br /&gt;sudo&amp;nbsp;apt-get&amp;nbsp;install&amp;nbsp;jenkins&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;-public IP로 웹에서 접근하여 초기 비밀번호를 요구하면 아래에서 받아서 입력&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;sudo&amp;nbsp;cat&amp;nbsp;/var/lib/jenkins/secrets/initialAdminPassword&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;-많이 세팅 해봤다면 본인이 필요한 플러그인을 잡고 아니라면 suggested plugin 기준으로 설치&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-origin-width=&quot;681&quot; data-origin-height=&quot;402&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/clva5q/btshAALzOaw/lwiYAV1XyW1WzEg2JYjZ1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/clva5q/btshAALzOaw/lwiYAV1XyW1WzEg2JYjZ1k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/clva5q/btshAALzOaw/lwiYAV1XyW1WzEg2JYjZ1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fclva5q%2FbtshAALzOaw%2FlwiYAV1XyW1WzEg2JYjZ1k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;681&quot; height=&quot;402&quot; data-origin-width=&quot;681&quot; data-origin-height=&quot;402&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;-다 설치가되면 새로운 item 추가를 통해 여러가지 방식으로 빌드 처리를 할 수 있다. freeStyle / pipeline 정도로 진행해봤는데 freeStyle은 마치 lambda를 콘솔에서 처리하는 방식처럼 편리하지만 프로젝트 내 jenkinsFile을 넣고 깃을 통해 함께 관리하는 방식과 같이 협업에 맞지 않는 것 같아서 pipeline 방식으로 최종 가기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-ec2 사양이 충분하다면 모르겠지만... 아니라면 아래와 같이 동시 빌드 미허용으로 가자.. 추가적으로 같은 파이프라인에 빌드 요청이 왔을 때 이전 빌드가 진행중이면 중단 시키는 세팅이 있는데 이는 팀 내 협업 방식에 따라 맞게 가자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;-추가적으로 오래된 빌드 삭제 세팅을 통해 일부 용량을 세이브 할 수 있다. 로그 관리와 같이 원하는 기간 만큼 보관 할 수 있고 최대 보관 개수를 설정할 수 있다. (path는 /var/lib/jenkins/workspace/ 이므로 테스트 단계에서 용량이 부족하다면 직접 지워가면서... 그럴일은 없을듯하긴 하다)&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;689&quot; data-origin-height=&quot;544&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bArn3m/btshBiXO2zG/GDVCuafpmZaAYXTry3NWi0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bArn3m/btshBiXO2zG/GDVCuafpmZaAYXTry3NWi0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bArn3m/btshBiXO2zG/GDVCuafpmZaAYXTry3NWi0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbArn3m%2FbtshBiXO2zG%2FGDVCuafpmZaAYXTry3NWi0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;689&quot; height=&quot;544&quot; data-origin-width=&quot;689&quot; data-origin-height=&quot;544&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-빌드 트리거는 github hook trigger for GITScm polling로 잡아서 특정 깃 내 특정 브랜치에 푸시 되었을 때 폴링하고 있던 jenkins가 반응하도록 처리. 약어가 궁금해서 찾아본 SCM은 아래와 같다.&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;SCM stands for Source Control Management&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-origin-width=&quot;598&quot; data-origin-height=&quot;300&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d3GQAK/btshG79a8Me/SVrYWCufjkRm55EZuEJZU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d3GQAK/btshG79a8Me/SVrYWCufjkRm55EZuEJZU0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d3GQAK/btshG79a8Me/SVrYWCufjkRm55EZuEJZU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd3GQAK%2FbtshG79a8Me%2FSVrYWCufjkRm55EZuEJZU0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;598&quot; height=&quot;300&quot; data-origin-width=&quot;598&quot; data-origin-height=&quot;300&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;-파이프라인은 pipeline script from SCM으로 잡아 프로젝트 루트 경로 내 JenkinsFile을 쓰도록 하자.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-Repo를 연결해주고 credentials는 id &amp;amp; git personal token을 이용해서 뚫어주자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;576&quot; data-origin-height=&quot;714&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZ481q/btshG63xp40/Jgs1k4oviYtKrgqA2hiZ91/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZ481q/btshG63xp40/Jgs1k4oviYtKrgqA2hiZ91/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZ481q/btshG63xp40/Jgs1k4oviYtKrgqA2hiZ91/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZ481q%2FbtshG63xp40%2FJgs1k4oviYtKrgqA2hiZ91%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;576&quot; height=&quot;714&quot; data-origin-width=&quot;576&quot; data-origin-height=&quot;714&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;-빌드할 브랜치, jenkinsFile path&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;557&quot; data-origin-height=&quot;544&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b30k4Y/btshChxM96E/IBc2JfBdm6pIoodHIiC0XK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b30k4Y/btshChxM96E/IBc2JfBdm6pIoodHIiC0XK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b30k4Y/btshChxM96E/IBc2JfBdm6pIoodHIiC0XK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb30k4Y%2FbtshChxM96E%2FIBc2JfBdm6pIoodHIiC0XK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;557&quot; height=&quot;544&quot; data-origin-width=&quot;557&quot; data-origin-height=&quot;544&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-추가적으로 global tool configuration에서 필요한 Nodejs, docker, JDK 버전 등이 있다면 별도로 셋업해주면 된다. 거기에 이름으로 적은 명칭을 JenkinsFile 내 툴 명칭으로 연결해주면 된다.&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;&amp;nbsp;tools&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;nodejs 'myNodejs'&amp;nbsp;&lt;br /&gt;&amp;nbsp;&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;-스크립트 는 예시가 많으니 필요에 따라 구성하면되고, 각 스테이지가 jenkins admin 내 아래와 같이 표시된다고 보면 된다. 좀 더 세부적으로 구분할 필요가 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;708&quot; data-origin-height=&quot;170&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zvwpM/btshAAY61dI/PCvJa0WT7zhmaSZD3qpfVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zvwpM/btshAAY61dI/PCvJa0WT7zhmaSZD3qpfVk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zvwpM/btshAAY61dI/PCvJa0WT7zhmaSZD3qpfVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzvwpM%2FbtshAAY61dI%2FPCvJa0WT7zhmaSZD3qpfVk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/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;170&quot; data-origin-width=&quot;708&quot; data-origin-height=&quot;170&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;stage('Yarn')&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;steps&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;echo 'yarn installing...' // 젠킨스 로그 상 남길 수 있다.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sh 'yarn' // 실제 쉘 스크립트 상 실행할 명령어&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-슬랙 알림의 경우 상단에 def로 변수 지정 후 사용해도 되고, 다른 방식으로 적용해도 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-셋업의 경우 젠킨스 관리 -&amp;gt; 시스템 구성으로 넘어가 본인 workspace, 슬랙 통합 토큰 자격 증명 그리고 채널명등을 활용하여 셋업하면 된다.&lt;/p&gt;
&lt;pre class=&quot;nginx&quot; style=&quot;background-color: #2b2b2b; color: #a9b7c6;&quot;&gt;&lt;code&gt;post {
  failure {
      slackSend (
          channel: SLACK_CHANNEL,
          message: &quot;배포 실패 REPO: ${REPO_NAME} / ENV: ${NAMESPACE}&quot;
      )
  }
  success {
      slackSend (
          channel: SLACK_CHANNEL,
          message: &quot;배포 성공 REPO: ${REPO_NAME} / ENV: ${NAMESPACE}&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;&lt;b&gt;3.git 관련 설정&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-CI/CD를 적용하고자 하는 프로젝트 setting -&amp;gt; webhooks로 이동한다. payload URL은 당연히 jenkins와 같이 잡고 뒤에 /github-webhook/ 을 붙여주면 된다.&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;ex)http://1.2.3.4:{jenkins-port}/github-webhook/&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;-Recent deliveries 탭에서 특정 브랜치 코드 푸시 이후 POST로 잘 전달 되었는지 내역을 볼 수 있다. 여기서 주로 전달이 안되는 경우는 보안그룹 문제나 payload URL 문제이므로 잡아주면 된다.&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-origin-width=&quot;594&quot; data-origin-height=&quot;133&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/80hoY/btshAwhYE1y/CMvpoK6lTesJUpM33pKa71/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/80hoY/btshAwhYE1y/CMvpoK6lTesJUpM33pKa71/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/80hoY/btshAwhYE1y/CMvpoK6lTesJUpM33pKa71/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F80hoY%2FbtshAwhYE1y%2FCMvpoK6lTesJUpM33pKa71%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;594&quot; height=&quot;133&quot; data-origin-width=&quot;594&quot; data-origin-height=&quot;133&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;-EC2 내 깃도 미리 추가해두고 본인 깃 계정 SSH Key 설정도 해두자&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;$sudo apt-get install git&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;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;#java&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$sudo apt update&lt;br /&gt;$sudo apt install openjdk-11-jdk&lt;br /&gt;$java -vercion&lt;br /&gt;$javac&amp;nbsp;-version&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;$vim ~/.bashrc&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;export JAVA_HOME=$(dirname $(dirname $(readlink -f $(which java))))&lt;br /&gt;export&amp;nbsp;PATH=$PATH:$JAVA_HOME/bin&lt;br /&gt;&lt;br /&gt;$source ~/.bashrc&lt;br /&gt;$echo&amp;nbsp;$JAVA_HOME&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;#docker&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$sudo apt install -y &lt;a href=&quot;http://docker.io/&quot;&gt;docker.io&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$sudo chmod 666 /var/run/docker.sock&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$sudo user add jenkins&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$grep docker /etc/group&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$sudo user mod -a -G docker jenkins&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$grep docker /etc/group&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;docker:x:123:jenkins&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;분명히 jenkins admin password를 똑바로 쳤는데도 패스워드가 틀렸다고 돌게 만드는 경우가 있다. 그렇다면 아래 실행&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;sudo&amp;nbsp;vi&amp;nbsp;/etc/sudoers&lt;br /&gt;jenkins&amp;nbsp;ALL=(ALL)&amp;nbsp;NOPASSWD:&amp;nbsp;ALL&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;sudo&amp;nbsp;service&amp;nbsp;docker&amp;nbsp;start&lt;br /&gt;$&amp;nbsp;sudo&amp;nbsp;systemctl&amp;nbsp;enable&amp;nbsp;docker.service&lt;br /&gt;$ docker run hello-world // 작동 테스트&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;#kubernetes 및 helm 셋업&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;$ curl -o kubectl // &lt;b&gt;본인의 쿠버 버전 url curl&lt;/b&gt;&lt;br /&gt;$&amp;nbsp;chmod&amp;nbsp;+x&amp;nbsp;./kubectl&lt;br /&gt;$&amp;nbsp;mkdir&amp;nbsp;-p&amp;nbsp;$HOME/bin&amp;nbsp;&amp;amp;&amp;amp;&amp;nbsp;cp&amp;nbsp;./kubectl&amp;nbsp;$HOME/bin/kubectl&amp;nbsp;&amp;amp;&amp;amp;&amp;nbsp;export&amp;nbsp;PATH=$PATH:$HOME/bin&lt;br /&gt;$&amp;nbsp;echo&amp;nbsp;'export&amp;nbsp;PATH=$PATH:$HOME/bin'&amp;nbsp;&amp;gt;&amp;gt;&amp;nbsp;~/.bashrc&lt;br /&gt;$ kubectl version --short&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;curl&amp;nbsp;&lt;a href=&quot;https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3&lt;/a&gt;&amp;nbsp;&amp;gt;&amp;nbsp;get_helm.sh&lt;br /&gt;$&amp;nbsp;chmod&amp;nbsp;700&amp;nbsp;get_helm.sh&lt;br /&gt;$&amp;nbsp;./get_helm.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;-그후 eks도 연동 후 쿠버네티스 경로 관련 문제가 생기면 kubectl client를 /usr/local/bin으로 옮겨주자! kubectl get pods로 테스트!&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;#aws cli&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;$sudo apt install awscli&lt;br /&gt;$aws&amp;nbsp;configure&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;#nodejs&amp;nbsp;&amp;amp;&amp;nbsp;yarn&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;$sudo apt-get install nodejs&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;$curl -sS&amp;nbsp;&lt;a href=&quot;https://dl.yarnpkg.com/debian/pubkey.gpg&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://dl.yarnpkg.com/debian/pubkey.gpg&lt;/a&gt;&amp;nbsp;|&amp;nbsp;sudo&amp;nbsp;apt-key&amp;nbsp;add&amp;nbsp;-&lt;br /&gt;$echo &quot;deb&amp;nbsp;&lt;a href=&quot;https://dl.yarnpkg.com/debian/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://dl.yarnpkg.com/debian/&lt;/a&gt;&amp;nbsp;stable&amp;nbsp;main&quot;&amp;nbsp;|&amp;nbsp;sudo&amp;nbsp;tee&amp;nbsp;/etc/apt/sources.list.d/yarn.list&lt;br /&gt;$sudo apt update&lt;br /&gt;$sudo apt install yarn&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5.기타 짜증나는 것들...&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;-ssh로 직접 ec2 접근하여 진행 시 문제는 없던것들이 젠킨스 빌드 통해서 진행하면 자꾸 접근 권한 문제 등이 생긴다.&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;error:&amp;nbsp;the&amp;nbsp;server&amp;nbsp;doesn't&amp;nbsp;have&amp;nbsp;a&amp;nbsp;resource&amp;nbsp;type&amp;nbsp;&quot;deploy&amp;rdquo;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Got&amp;nbsp;permission&amp;nbsp;denied&amp;nbsp;while&amp;nbsp;trying&amp;nbsp;to&amp;nbsp;connect&amp;nbsp;to&amp;nbsp;the&amp;nbsp;Docker&amp;nbsp;daemon&amp;nbsp;socket&amp;nbsp;at&amp;nbsp;unix:///var/run/docker.sock:&amp;nbsp;Post&amp;nbsp;&quot;&lt;a href=&quot;http://%2Fvar%2Frun%2Fdocker.sock/v1.24/auth&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;http://%2Fvar%2Frun%2Fdocker.sock/v1.24/auth&lt;/a&gt;&quot;:&amp;nbsp;dial&amp;nbsp;unix&amp;nbsp;/var/run/docker.sock:&amp;nbsp;connect:&amp;nbsp;permission&amp;nbsp;denied&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kubectl not found..&lt;br /&gt;docker not found...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Failed&amp;nbsp;to&amp;nbsp;initialize&amp;nbsp;Kubernetes&amp;nbsp;secret&amp;nbsp;provider&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;$sudo su jenkins&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$aws configure // 적절한 IAM 권한 및 eks 연동&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <author>jongviet</author>
      <guid isPermaLink="true">https://jongviet.tistory.com/172</guid>
      <comments>https://jongviet.tistory.com/172#entry172comment</comments>
      <pubDate>Mon, 29 May 2023 13:08:21 +0900</pubDate>
    </item>
    <item>
      <title>May 21, 2023 - DynamoDB ttl &amp;amp; stream 이용  Lambda 트리거하기</title>
      <link>https://jongviet.tistory.com/171</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*5월21일&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;-대용량 파일 다운로드를 SQS &amp;amp; Lambda 조합으로 본 서버 외에 자원을 사용하는 식으로 구성하다가, 다운로드 내역과 만료 처리가 필요함을 팀 내부에서 느꼈다. 리더분께서 DynamoDB TTL과 stream을 이용하면 Lambda를 트리거할 수 있다고 제안해주셨고 스터디를 통해서 '대용량 파일 다운로드 요청' -&amp;gt; '백엔드 서버' -&amp;gt; 'SQS' -&amp;gt; '파일 추출 및 생성용 Lambda 작업 진행 후 히스토리 데이터 &amp;amp; TTL용 데이터 put' -&amp;gt; 'DynamoDB TTL' 발동 후 'DynamoDB Stream'을 통해 만료 처리용 Lambda에 도달 -&amp;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;1.Stream 연동 방법&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; &lt;/b&gt;-Stream은 DynamoDB 콘솔을 통해 특정 테이블에 기능을 켜고 끌 수 있다. 테이블 -&amp;gt; 업데이트 설정 -&amp;gt; 내보내기 및 스트림에 지정하면 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;588&quot; data-origin-height=&quot;446&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/P9qfz/btsgD9Hx5pj/spc2tXyQfVPImtYxlkv3S0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/P9qfz/btsgD9Hx5pj/spc2tXyQfVPImtYxlkv3S0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/P9qfz/btsgD9Hx5pj/spc2tXyQfVPImtYxlkv3S0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FP9qfz%2FbtsgD9Hx5pj%2Fspc2tXyQfVPImtYxlkv3S0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;588&quot; height=&quot;446&quot; data-origin-width=&quot;588&quot; data-origin-height=&quot;446&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-테이블의 경우 지정된 테이블 내에서 일어나는 모든 INSERT, UPDATE, REMOVE에 대해 연동된 lambda로 이벤트를 던지기에 새로운 테이블을 만드는 편이 낫다고 생각했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-TTL은 unix timestamp second를 기준으로 작동하고, 해당 시간을 터치했을 때 즉시 발동되지 않고 어느정도의 시간이 흐른후 작동된다. INSERT, UPDATE, REMOVE 모두 LAMBDA로 넘어온 EVENT 데이터의 구성이 다르다. 당연히 INSERT는 새로운 데이터 형태가 전체 넘어오고, UPDATE는 OLD &amp;amp; NEW, REMOVE는 OLD에 대해서만 넘어온다. 넘어온 데이터의 ID 값이나 기타 본인이 지정한 값을 활용하여 추가적인 처리를 해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2.람다 트리거 및 이벤트 분기처리&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-하기 이미지와 같이 연동해주고, 넘어온 이벤트는 하기와 같이 분기처리해서 사용하면된다.&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;const&amp;nbsp;eventName&amp;nbsp;=&amp;nbsp;event.Records[0].eventName;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;if(eventName === 'REMOVE') {} else if(eventName === 'UPDATE') {}....&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;418&quot; data-origin-height=&quot;226&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/t8L4z/btsgDNFeJjV/aKK14R5cr95MgnkNC4pNkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/t8L4z/btsgDNFeJjV/aKK14R5cr95MgnkNC4pNkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/t8L4z/btsgDNFeJjV/aKK14R5cr95MgnkNC4pNkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ft8L4z%2FbtsgDNFeJjV%2FaKK14R5cr95MgnkNC4pNkK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;418&quot; height=&quot;226&quot; data-origin-width=&quot;418&quot; data-origin-height=&quot;226&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;b&gt;3.추가적인 기능.. 생각..&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-단순 내부 직원들만 쓰는 것이 아니라 다양한 유저들이 사용한다면 stream event에 따라 만료 1일 전 메일링, 만료 1시간 전 알람 등과 같은 부가 기능을 넣을 수도 있을 것 같다.&lt;/p&gt;</description>
      <author>jongviet</author>
      <guid isPermaLink="true">https://jongviet.tistory.com/171</guid>
      <comments>https://jongviet.tistory.com/171#entry171comment</comments>
      <pubDate>Sun, 21 May 2023 13:38:58 +0900</pubDate>
    </item>
    <item>
      <title>May 7, 2023 - AWS Summit 2023</title>
      <link>https://jongviet.tistory.com/170</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*5월 7일&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;-5월2일~3일 일정으로 회사 개발팀 전체 함께 AWS Summit 2023에 참가했다. 들었던 각종 내용들과 앞으로 좀 더 대비하거나 알아봐야할 내용을 조금은 정제된 메모장과 같이 정리해보도록 하자.&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;&lt;b&gt;1.기조연설&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;-기조 연설은 Nandini Ramani AWS 모니터링 담당 부사장님, 함기호 AWS Korea 대표이사, 오순영 KB국민은행 센터장, 이준영 야놀자 엔지니어링 수석 부대표분이 진행해주셨다. Nandini Ramani 분이 메인으로 진행하면서 중간 중간 다른 연사들이 나와 특정 주제에 대해 PT 하는 방식이었다. 확실히 서방과 한국식 PT의 차이를 느낄 수 있었고, 모두들 매끄럽게 잘 진행해주셨던 것 같다. 기조 연설 시작 전 Nandini Ramani분의 영상을 좀 찾아봤는데, 당일 옷도 그렇고 확실히 빨간옷을 좋아하시는듯 하다. 본인 퍼스널 컬러인 것 같고 잘 어울리는 듯 하다. ㅎㅎ&lt;/div&gt;
&lt;div&gt;-야놀자 이준영 연사분께서는 야놀자의 &amp;lsquo;모텔 예약 앱&amp;rsquo;이라는 이미지를 지우기 위해 역시 노력하셨다. 실제 작년 인터파크 인수, 클라우드 쪽 투자 확대 등으로 영업이익이 급감 한 것도 있고, 좀 더 확장하기 위해 많은 노력을 하고 있는 것 같다. 그러나&amp;hellip; 일반인 입장에서 빨간 로고, 그리고 yanolja라는 이름에서 오는 이미지가 도저히 쉽게 바뀔 것 같지는 않다. 메타처럼.. 사명을 바꾸는 시도라도 하는게&amp;hellip; ㅎㅎ&lt;/div&gt;
&lt;div&gt;-확실히 시장에서 가장 높은 점유율을 가지고 있는 AWS에서도 후발주자들과 시장 상황을 고려 했는지 차이를 만들어 내는 것은 혁신이라는 점을 많이 강조했다. 인프라 구축은 거대 자본이 있으면 후발주자라도 언제든지 따라올 수 있다고 느끼고 있는것 같고, 검색 시장에서 절대적이던 구글이 요즘 시장 점유율을 조금씩 내어 주는 상황을 지켜보면서 조금 더 긴장하고 있다는 것을 느꼈다.&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2.Data lake &amp;amp; data warehouse&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;-Data Lake: raw data 그대로 저장, 별도 사용 목적 두지 않고 저장, 별도 정제 과정이 없으므로 빠른 업데이트&lt;/div&gt;
&lt;div&gt;-Data Warehouse: 별도 정제 과정을 거쳐서 목적에 맞게 데이터 저장&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;-무수한 데이터들이 실시간으로 엄청나게 쌓이고, 별도 목적을 지정해두지 않았던 raw data에서 인사이트를 얻을 수 있는 경우도 있으므로 data lake식으로 저장하는 방식이 큰 기업일 수록 선호 되는 듯 하다. 데이터 분석은 별도 데이터 사이언티스트가 진행하거나 AWS의 각종 기능들을 이용하여 충분히 각종 지표를 찾아 낼 수 있어 그런듯 하다. AWS datazone과 같은 서비스를 활용하여 권한 관리를 통한 접근 설정을 통해 각 데이터 마다 레벨링을 해둘 수 있다.&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;-sendbird 또한 ec2만 수천, eks만 수백을 굴리는 규모인데 데이터를 선택적으로 수집하면 추후 활용에 문제가 될 수 있기에 전체를 저장하고 AMP, AMG등을 활용하여 매니징 하고 있다고 한다.&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;b&gt;3.Monitoring과 observability의 차이&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;-모니터링은 단순히 어디에서 문제가 생겼는지 확인. 즉 로그 확인과 같이 심어놓은 로그를 활용하여 버그 픽스 등에 활용. observability는 무엇이 문제인지, 각종 환경, 최종 사용자에게 어떠한 영향을 미치는지 파악하는 좀 더 큰 개념.&lt;/div&gt;
&lt;div&gt;-AWS native monitoring options, cloud watch, metrics, x-ray 및 각종 오픈소스 기반&amp;nbsp;&lt;/div&gt;
&lt;div&gt;-삼성은 prometheus, grafana 오픈 소스 기반으로 사용하다가 보관 문제, 각종 config 값 변경 등의 문제로 Amazon-managed prometheus, grafana(AMP, AMG)등으로 갈아 탔다고 한다.&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4.FLO와 netFUNNEL&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;-FLO(음악 스트리밍 서비스)에서 On-premises -&amp;gt; AWS로 전체 마이그레이션을 진행하며 일어난 일들에 대해 발표했다.&lt;/div&gt;
&lt;div&gt;-마이그레이션 진행 시 아주 세세한 플래닝을 준비했고, 부하테스트, 외부 연동 방화벽 처리, 데이터 동기화, 리허설, 각 작업자 별 태스크 정리 등을 어떻게 했는지 상세히 말씀해주셨다. 단순한 데이터 테이블 하나 마이그레이션 하는 것도 상당히 신경 쓸 부분이 많은데, 서비스 전체를 옮길 때 얼마나 고생하셨을지 상상이 가지 않는다.&lt;/div&gt;
&lt;div&gt;-아마존 스케일링 서비스를 통해 피크타임 서버 대수 유연한 대응을 한다고 하고, 새벽 시간대를 활용하여 cron을 돌려 개인화된 추천을 처리한다고 한다. (스포티파이는 거의 실시간으로 내 취향의 노래를 추천 하는 것 같은데.. 이걸 어떻게 하는지 궁금하긴 하다.)&lt;/div&gt;
&lt;div&gt;-앱은.. 스포티파이 느낌이 너무 많이 났고, 별로 갈아 타고 싶은 매력은 느끼지 못했다..&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;610&quot; data-origin-height=&quot;275&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uqiZT/btsd4ej0Hj9/oYBKxwyUP1J48AaPrJWfn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uqiZT/btsd4ej0Hj9/oYBKxwyUP1J48AaPrJWfn1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uqiZT/btsd4ej0Hj9/oYBKxwyUP1J48AaPrJWfn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuqiZT%2Fbtsd4ej0Hj9%2FoYBKxwyUP1J48AaPrJWfn1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;610&quot; height=&quot;275&quot; data-origin-width=&quot;610&quot; data-origin-height=&quot;275&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;-netFUNNEL이 명절 기차 예약 서비스 트래픽을 담당하는 것을 처음 알게 되었다&amp;hellip; 수강 신청 등 그동안 이러한 서비스들이 각자 트래픽을 관리한다고 생각했는데 나의 착각이었다.&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;-netFUNNEL은 서버와 앱 사이에서 동작하고, 서버가 처리 가능한 트래픽만 보내주는 역할을 한다고 한다. 기존 구축형으로만 제공하다가 AWS와 협업하여 현재는 SaaS 형태로 제공 중이라고 한다. 곧 AWS market place에도 나올 예정이라고 하신다.&lt;/div&gt;
&lt;div&gt;-현재 netFUNNEL을 포함해 다양한 기능을 더 넣은 surffy라는 서비스를 개발 중이시라고 한다.&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;725&quot; data-origin-height=&quot;387&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/biPA0D/btseddkfG12/wKQcUcwnLHWFGoXzUikwkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/biPA0D/btseddkfG12/wKQcUcwnLHWFGoXzUikwkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/biPA0D/btseddkfG12/wKQcUcwnLHWFGoXzUikwkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbiPA0D%2FbtseddkfG12%2FwKQcUcwnLHWFGoXzUikwkK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;725&quot; height=&quot;387&quot; data-origin-width=&quot;725&quot; data-origin-height=&quot;387&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5.재해복구 관련 세션&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;-자연재해, 기술이슈, 휴먼에러, 해킹 등 다양한 사유로 재해 복구가 필요한 상황이 발생.&lt;/div&gt;
&lt;div&gt;-RPO recovery point objective, RTO recovery time objective와 같은 관련 용어&lt;/div&gt;
&lt;div&gt;-AWS backup, pilot light, warm standby, multi-site active와 같은 활용 가능한 기능들이 있으며, backup은 수시간의 비용이 소요되나 비용이 저렴한 장점이 있고, multi-site active의 경우 실시간에 가까운 복구이고 무중단, 데이터 손실도 없지만 당연히 비용이 비싸다는 단점이 있었다. 당연하게도 사용목적에 맞는 재해 복구 시스템을 구축하는게 맞을 듯 하다. 앱이 잘게 잘게 구분되어 있으면 각 목적 별로 구분하여 재해 복구 시스템을 구축하기에 좋을 듯 하다. 데이터 손실에 따른, 서비스 중단에 따른 비용을 따져보고 적용이 필요!&lt;/div&gt;
&lt;div&gt;-백업의 경우 정적의존성, 동적의존성을 분리 후 백업이 필요하다. AMI 정보, region 정보, DB snapshot 등 별도 관리가 필요한 부분이 있을 듯 하다.&lt;/div&gt;
&lt;div&gt;-마지막으로 세션 연사님께서는 재해복구는 최초 구축 후 끝인게 아니라 계속해서 상황에 따라 검증하고 보완이 필요한 부분이라고 하셨다.&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;6.SOCAR IOT &amp;amp; 압도적인 쿠팡 데이터 사이즈&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;-나도 몇번 써본 쏘카, 실시간 데이터 기반으로 예약시간, 장소 및 실시간 수요 반영하여 가격 적용 그리고 선별적 쿠폰 발행(아.. 그래서 나에게 쏘카 쿠폰이 그렇게 안왔던 거구나..)&lt;/div&gt;
&lt;div&gt;-세차 주기 최적화, 운전자 숙련도 식별한 가격 차등 책정, 약 2만대 자체 차량 운영&lt;/div&gt;
&lt;div&gt;-자체 종합 차량 관제 시스템 OKSTRA 운영 중, 주유량, 엔진오일, 공기압 등 다 관리&lt;/div&gt;
&lt;div&gt;-Fleet management system 차량 데이터 기반으로 차량 관리 및 운영을 효율화하는 차량 관제 플랫폼. 유지보수, 알림, 유류비, 사고, 동선, 자동화, 배차, 실시간 위치, 알림, 주행데이터, 심지어 실시간 블랙 박스까지..&lt;/div&gt;
&lt;div&gt;-실시간 저장 필요 데이터와 히스토리용 데이터를 구분하여 목적에 맞는 저장소에 저장 중이었다. 실시간 데이터는 elastic cache 사용, 히스토리용 데이터는 dynamoDB 활용&lt;/div&gt;
&lt;div&gt;-IOT에서 실시간으로 들어오는 데이터를 특정 시간 단위로 벌크화하여 전송하고, 접수한 데이터를 초당 데이터로 풀어서 elastic cache에 저장&lt;/div&gt;
&lt;div&gt;-우버와 그랩은 어떻게 하고 있을까.....??&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;-쿠팡의 데이터 관련 세션이 있었다. 소개하는 바에 따르면 cron job이 하루 120k, 쿼리가 하루 500k, 분당 7.1m의 로그가 쌓인다고 한다. 규모에 일단 압도를 당했다.&lt;/div&gt;
&lt;div&gt;-AWS EMR을 활용한다고 하고, 모니터링은 슬랙, 그라파나, 프로메테우스, 스케쥴러는 airflow, processing engine은 하이브, 스파크, 쿼리엔진은 presto, 저장소는 s3&amp;hellip;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;7.토스증권&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;-토스증권이 어떻게 단기간 내에 사용자 친화적인 해외주식 거래 서비스를 만들었는지 할 수 있었다. 일명 Blitz Scaling을 통해 개발해옴. Speed, user acceptance, maker and culture, enough resources를 강조.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;-multi-cast로 한국거래소에서 받아온 증권 시세 정보가 각 증권사에 전달되고 각 증권사 별로 그 정보를 가공해서 처리한다고 함. 시세 정보는 web socket, 종목 정보는 restAPI, DB는 redis, 실시간 정보는 kafka 통해서 web-socket.. (과거에는 DB에 넣고 restAPI로 땡겼는데 너무 속도 느림..)&lt;/div&gt;
&lt;div&gt;-직원 이탈률은 정확히 알 수 없지만, 정말 엄청나게 갈아가며 서비스를 뽑아 내는 것 같다. 물론 그것을 가능하게 해주는 적절한 직원 보상과 서비스 성장에 따른 구성원의 성취감이 있을 듯 하다. 내가 만든 서비스가 하루만에 100만 사용자가 증가한다면, 줄야근을 해도 뿌듯할듯 하다. 다만 1년 365일은 불가.. 하지 않을까..&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666; text-align: justify;&quot;&gt;*블리츠스케일링(Blitzscaling)은 불확실한 상황에서 위험을 감수하더라도 엄청난 속도로 회사를 키워 압도적인 경쟁우위를 선점하는 기업의 고도성장 전략을 말한다. 기습 공격을 의미하는 &amp;lsquo;블리츠크리그(Blitzkrieg)&amp;rsquo;와 규모 확장을 의미하는 &amp;lsquo;스케일업(scale up)&amp;rsquo;의 합성어로, 링크드인 설립자 리드 호프먼이 스탠퍼드대 스타트업 특강을 계기로 미국 전역에 화제가 되면서 널리 알려지게 된 공격적 비즈니스 개념이다. 이미 아마존, 구글, 에어비앤비 등에 의해 검증된 전략으로, 경쟁자를 빠른 속도로 제압함으로써 시장의 우수한 인적&amp;middot;물적 자원을 흡수하고 브랜드 인지도를 각인하며, 결국 시장을 독점하는 것이 전략의 골자다&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;8.그 외 용어&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;-보안 관련 가장 기본은 AWS shield advanced, aws firewall, aws WAF는 좀 상급 개념으로 확인.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-멀티모달: 시각, 청각을 비롯한 여러 인터페이스를 통해서 정보를 주고 받는 것을 말하는 개념&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-데이터 관련 각 담당자의 역할&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;-데이터 생산자: 오너십, 품질, 메타데이터 관리 / redshift, s3&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;-데이터 관리자: &amp;nbsp;데이터 정리, 플랫폼 구축 운영, 권한 통제, / data zone&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;-데이터&lt;/span&gt; &lt;span&gt;소비자:&amp;nbsp;&lt;/span&gt;&lt;span&gt;비즈니스&lt;/span&gt; &lt;span&gt;우선순위&lt;/span&gt; &lt;span&gt;결정&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;새로운&lt;/span&gt; &lt;span&gt;인사이트&lt;/span&gt; &lt;span&gt;개발&lt;/span&gt;&lt;span&gt;.. // redShift&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;9.&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;부족한 점&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;-네트워킹 관련 지식 부족...&lt;/span&gt;&lt;span&gt;어떻게 각 서비스를 고립 시키는지..&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;-대용량 데이터 처리...&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;-elastic cache&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;-AMP, AMG&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;-보안 처리&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*지금까지 부족한점을 알아보지 않은 이유라면,, 필요 해야 더 열정적으로 알아 볼 텐데, 대규모 서비스를 운영해보지 않아 필요성이 없었던게 가장 큰 듯하다. 네트워킹, 대용량 데이터, 각종 시각 모니터링 기능, 보안 등.. 어떻게 하면 더 잘 알아 볼 수 있을지 고민 좀 해보자.&lt;/p&gt;</description>
      <author>jongviet</author>
      <guid isPermaLink="true">https://jongviet.tistory.com/170</guid>
      <comments>https://jongviet.tistory.com/170#entry170comment</comments>
      <pubDate>Sun, 7 May 2023 16:20:06 +0900</pubDate>
    </item>
    <item>
      <title>April 16, 2023 - SQS &amp;amp; Lambda 연동</title>
      <link>https://jongviet.tistory.com/169</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*4월16일&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;-현재 회사 어드민 페이지 내 특정 테이블 데이터에 대한 엑셀 다운로드 기능을 프론트 단에서 전부 처리하도록 구현 해놓고 있었다. 하지만 추후 회사 외부에 동일한 기능을 제공해야 할 필요성이 생겼고 해당 기능을 SQS &amp;amp; Lambda를 통해 구현해보기로 했다.&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.SQS 구성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-SQS는  생성은 거의 디폴트 옵션으로 진행했다. 유형은 표준/FIFO가 있는데 표준은 순서 보장이 되지 않고 중복 발송이 될 수 있고, FIFO는 글자 그대로 선입선출이고 정확히 1회만 처리한다. 따라서 당연히 후자가 조금 더 비싸다. 하지만 SQS로부터 넘어온 msgId 및 람다 내 캐싱을 통해 표준으로도 충분히 1회 작업만 진행할 수 있다고 판단했기에 표준으로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-SQS 생성 직후 ARN과 URL 값을 잘 복사해두고, 엑세스 정책 또한 producer(본 케이스는 호출하는 백엔드 서버)가 접근할 수 있도록 잘 뚫어준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-Lambda 트리거의 경우 해당 SQS를 폴링하면서 SQS 상 메시지가 접수 되었을 때 행동하는 consumers(또는 workers)를 말한다. SQS 하나에 여러개의 람다를 붙일 수도 있고, SQS 하나 당 하나의 람다만 붙일 수도 있다. 관리 &amp;amp; 비용 등 다양한 측면이 있으나 현재는 비용이 가장 중요하므로 비용 측면에서 가장 효율적인 방법을 선택하고자 했다. 회사 팀 리더분이 공유해주신 AI search(&lt;a href=&quot;https://www.phind.com/&quot;&gt;https://www.phind.com/&lt;/a&gt;)에 따르면 SQS 1 + Lambda 1이 가장 비용적으로는 효율적이라고 하여 해당 방법으로 구성하기로 했다. 물론 SQS로 던지는 msgBody 내부에 필요 값들을 넣어 SQS 하나에 람다 여러개를 붙이는 방법 또한 관리 측면에서 의미가 있을 수도 있다. 하지만 비용적인 측면에서는 SQS 내 메시지 하나가 날아 왔을 때 해당 SQS를 폴링하고 있던 복수의 람다가 모두 동작하기에 좋지 않을 수 있다고 했다.&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-origin-width=&quot;331&quot; data-origin-height=&quot;665&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/deUCLM/btsajdpo8Hx/Y5JdblTOGJprbiVagEkYCK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/deUCLM/btsajdpo8Hx/Y5JdblTOGJprbiVagEkYCK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/deUCLM/btsajdpo8Hx/Y5JdblTOGJprbiVagEkYCK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdeUCLM%2Fbtsajdpo8Hx%2FY5JdblTOGJprbiVagEkYCK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;331&quot; height=&quot;665&quot; data-origin-width=&quot;331&quot; data-origin-height=&quot;665&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;b&gt;2.람다 구성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-람다의 경우 node 18.x, 타임아웃 설정, 권한(DynamoDB access, S3 access, Cloudwatch) 설정이 중요 했고, 람다 레이어를 활용한 라이브러리 관리 또한 중요했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-최종적으로는 Serverless를 활용하여 팀원들끼리 람다 코드 및 라이브러리를 공유할 수 있게 갔지만, AWS 콘솔을 활용하여 버전 별로 라이브러리 레이어를 관리하고, deploy 시간을 최소화하여 콘솔 내에서 직접 테스트 해보는 방법도 나쁘지 않은 것 같다. 이는 팀이 어느 방향을 지향하느냐에 따라 더 유리한 방법으로 쓰면 될 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-console.log를 통해 찍어놓은 모든 활동은 해당 람다의 CloudWatch 내 잘 저장 되므로 적절하게 활용하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3.람다 캐싱 방법&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-SQS에서 중복으로 동일한 메시지를 람다로 던질 수도 있고, 클라이언트 측에서 여러번 요청을 할 수도 있기에, 람다가 같은 일을 여러번 하지 않도록 하는 것이 중요하다.&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;-구글링을 통해 확인하여 적용한 캐싱 방법은 하기와 같다. handler 함수 외부 변수들은 계속해서 떠있기 때문에 해당 변수를 활용하여 캐싱하면 된다.&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;538&quot; data-origin-height=&quot;538&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ep6xjc/btsagqCUR7E/9v6S468VqCn9KE0h9ZcriK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ep6xjc/btsagqCUR7E/9v6S468VqCn9KE0h9ZcriK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ep6xjc/btsagqCUR7E/9v6S468VqCn9KE0h9ZcriK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fep6xjc%2FbtsagqCUR7E%2F9v6S468VqCn9KE0h9ZcriK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;538&quot; height=&quot;538&quot; data-origin-width=&quot;538&quot; data-origin-height=&quot;538&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;b&gt;4.흐름&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-웹 또는 앱 내 특정 버튼을 통해 다운로드 요청 -&amp;gt; 백엔드 API 도달 이후, 요청 값에 대한 기본 정보를 재구성하여 msgBody값으로 SQS에 전달 -&amp;gt;&amp;nbsp; SQS를 폴링하고 있던 람다가 동작 -&amp;gt; 중복 요청 여부 점검, 캐싱 점검, DB 접근 후 데이터 구성 및 S3 업로드.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-추가적으로 S3 업로드 작업이 끝나면 msgBody 내 클라이언트 이메일과 같은 정보를 기반으로 해당 메일에 S3 URL을 보내준다던지 아니면 직접 해당 파일을 전송해준다던지 하면 될 것 같다. 실제 사용하는 서비스에서도 다운로드 요청을 이러한 식으로 처리하고 추후 파일이 구성되면 메일로 발송될 테니 확인하라고 한 경우가 있었다. 5분 넘게 메일이 도달하지 않아.. 뭐지? 라고 생각하긴 했지만 급하지 않은 건에 대해서는 그러한식으로 요청을 던져 놓는 것도 좋을 것 같다.&lt;/p&gt;</description>
      <author>jongviet</author>
      <guid isPermaLink="true">https://jongviet.tistory.com/169</guid>
      <comments>https://jongviet.tistory.com/169#entry169comment</comments>
      <pubDate>Sun, 16 Apr 2023 11:49:44 +0900</pubDate>
    </item>
    <item>
      <title>Feb 26, 2023 - promise.all &amp;amp; for await of</title>
      <link>https://jongviet.tistory.com/168</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;-이상한 고집이 있어서 항상 반복문을 통해 DB를 get, put, update, delete 할 때 항상 for await of를 썼었다. 언제부터인지는 모르겠지만 개발 첫 회사에서 통계 관련 데이터를 몽고DB에 update를 치다가, 업데이트 직후 후처리를 순차적으로 해야 할 일이 있어서 그랬던 것 같다. 이번에 특정 기능을 고도화하다가 확실하게 깨달았는데 for await of 대비 promise.all이 단순 get 기준 5배 정도 빨랐다.&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.for await of&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-순차적으로 반드시 처리되어야 하고 res를 받아서 후처리를하거나 응답값에 포함되어야 해야 할 때 사용!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2.promise.all&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-순차적으로 처리될 필요가 없는 경우 사용하기 아주 적절. 특히 get의 경우 전부다 받은 다음 추가적으로 정렬 후 리턴 해줄 수 있기 때문에 속도면에서 아주 우수할 듯 함.&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;const putData = data.map((item) =&amp;gt; { return DB.put().... }&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;await promise.all(putData);&lt;/p&gt;</description>
      <category>javascript &amp;amp; typescript</category>
      <author>jongviet</author>
      <guid isPermaLink="true">https://jongviet.tistory.com/168</guid>
      <comments>https://jongviet.tistory.com/168#entry168comment</comments>
      <pubDate>Sun, 26 Feb 2023 21:01:31 +0900</pubDate>
    </item>
    <item>
      <title>Oct 10, 2022 - Kubernetes 개념</title>
      <link>https://jongviet.tistory.com/167</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;새롭게 몸담은 회사에서 Kubernetes(이하, k8s)를 사용하게 되었다. 그전까지는 nginx, pm2 cluster로 구성된 방식으로 각각의 ec2 instance에 배포하고 ssh로 접근해서 하나하나 관리를 하면서 백엔드를 관리했었는데, docker와 함께 듣기만 했던 k8s를 사용해보게되었다. 개념 잡기에는 여러 문서들도 도움이 되었지만, 하기 유튜브 링크가 가장 많은 도움이 되었던 것 같다. 도식화된 자료와 함께 아주 쉽게 설명해주신다!&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;a href=&quot;https://www.youtube.com/watch?v=Ia8IfowgU7s&amp;amp;list=PLIUCBpK1dpsNf1m-2kiosmfn2nXfljQgb&quot;&gt;https://www.youtube.com/watch?v=Ia8IfowgU7s&amp;amp;list=PLIUCBpK1dpsNf1m-2kiosmfn2nXfljQgb&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=Ia8IfowgU7s&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/eecoHc/hyP6z4zFio/9bf4EjO3jGcfnxaS2TZ9iK/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=1062_496_1202_648&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/Ia8IfowgU7s&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;#등장배경&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-서버 상태 관리는 아무리 문서화 해도 전달이 잘 안됨.. 다양한언어, 프레임워크 등.. 그래서 서버 하나에 VM 여러개를 돌리는 방법이 등장하였으나, 특정한 클라우드 환경에 대한 의존성이 생겨 다양한 환경으로 옮겨 사용하기가 어려워짐! 그래서 등장한게 도커컨테이너! 도커 컨테이너는 배포와 롤백이 간단하고, 언어와 프레임워크에 관계 없이 어플리케이션을 동일한 방식으로 개발, 테스팅, 운영할 수 있게 해줌!&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;develop -&amp;gt; build(image생성) -&amp;gt; ship(저장소 내 배포) -&amp;gt; run&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;-그러나 각각의 도커에 ssh로 접근해서 docker stop app &amp;amp;&amp;amp; docker run 무한 반복하면서 관리하는 방식은 굉장히 귀찮았음... 컨테이너별 버전관리... 롤아웃, 문제 생길 시 롤백... IP 변경 될 때 마다 nginx에 변경된 아이피 반영.... 너무 복잡해짐.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-그에 대한 니즈로 등장한게 클러스터 단위 노드 오케스트레이션! 각 컨테이너끼리의 통신, 상태관리, 롤아웃&amp;amp;롤백, 버저닝, 서비스등록, 각 컨테이너 및 노드 변경에 따른 프록시 서버 설정 변경 및 프로세스 재시작 등 수동으로 조작해야하고 관리해야할 다양한 업무영역을 직접 해주게 됨!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;그러한 일을 해주는 대표적인 것이 k8s!&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;#k8s 아키텍쳐&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-마스터와 노드로 나뉘어져 있으며, 마스터 내에는 스케쥴러, 각종 컨트롤러, API 서버, etcd 등이 있고, 노드 내에는 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;&lt;b&gt;마스터의 구성 요소&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;*스케쥴러: 서버 별 상태 체크, 네트워크 상태 체크, pod 생성 점검, 노드 할당 등등.. 다 해줌!! - replication, endpoint(LB), namespace, custom, ML(machine learning), CI/CD&lt;/div&gt;
&lt;div&gt;*etcd: 마스터에서 상태와 데이터를 저장함, 분산시스템으로 구성하여 안정성을 높임.&lt;/div&gt;
&lt;div&gt;*API서버: etcd와 유일하게 통신하는 모듈, restAPI 형태, 권한 체크, 내부 모듈과 통신, 상태를 바꾸거나 조회 등&amp;hellip;&lt;/div&gt;
&lt;div&gt;*컨트롤러: 끊임없이 상태를 체크하고 원하는 상태를 유지, 복잡성을 낮추기위해 하나의 프로세스로 실행, 무한 루프!! 상태체크.&lt;/div&gt;
&lt;div&gt;-&amp;gt;if(current state !== desired state) take action&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;노드의 구성 요소&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*proxy(iptables, ipvs) 및 kubelet&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*kubelet은 API 서버와 각각의 pod을 바라보고 움직임! pod에 대한 상태 체크, 실행, 중지 등을 담당!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*proxy는 내/외부 통신 설정, 네티워크 프록시 및 부하분산 역할을 함!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*그 외 CNI, DNS, visualization 등이 있음!&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;#k8s 오브젝트&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-팟이 가장 작은 배포 단위! 팟이 컨테이너를 감싸고 있는 형태이며 그 안에 로그, 캐시 등이 포함 됨! 각 팟은 고유한 IP를 할당 받음!&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-replicaSet은 여러개의 팟을 관리함! 새로운 Pod은 template을 기반으로 생성되며 신규 pod을 생성 또는 제거하여 설정된 replicaSet수를 맞춤! v1 3개에서 v2로 버전업 진행 시, 하나씩 점진적으로 변경됨!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-데몬셋은&amp;nbsp;모든&amp;nbsp;노드에&amp;nbsp;하나씩만&amp;nbsp;떠있길&amp;nbsp;원하는&amp;nbsp;경우&amp;nbsp;사용,&amp;nbsp;예를들어&amp;nbsp;로그수집이나&amp;nbsp;모니터링&lt;br /&gt;-스테이트풀셋은&amp;nbsp;순서대로&amp;nbsp;팟을&amp;nbsp;실행하고&amp;nbsp;싶거나&amp;nbsp;같은&amp;nbsp;볼륨을&amp;nbsp;재활용하고&amp;nbsp;싶을&amp;nbsp;때&amp;nbsp;사용&lt;br /&gt;-잡은&amp;nbsp;한번&amp;nbsp;실행하고&amp;nbsp;죽는&amp;nbsp;팟&lt;br /&gt;-각&amp;nbsp;팟의&amp;nbsp;아이피는&amp;nbsp;죽고&amp;nbsp;살&amp;nbsp;때&amp;nbsp;계속&amp;nbsp;변경되기에,&amp;nbsp;중간에&amp;nbsp;서비스(cluster&amp;nbsp;IP)로&amp;nbsp;보내서&amp;nbsp;LB가&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;-각 노드 별로 앞단에 서비스 LB를 두고, nodePort를 가짐! nodePort를 거쳐 clusterIP에 도달하여 필요한 동작을 수행함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-ingress란 도메인 또는 경로 별로 라우팅 해주는 역할을 함. nginx라고 생각하면됨! 즉 클라이언트 단에서 특정 도메인으로 접근하여 각 도메인에서 LB를 통해 각 nodePort에 배분 되고, clusterIP에 맞추어 각 팟에 도달하는 구조.&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;abcd.com -&amp;gt; service A&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;fghd.com/help -&amp;gt; service B&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;fghd.com/info -&amp;gt; service C&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;외&amp;nbsp;다양한&amp;nbsp;기본&amp;nbsp;오브젝트가&amp;nbsp;있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;*&amp;nbsp;Volume:&amp;nbsp;storage(EBS,&amp;nbsp;NFS)&lt;br /&gt;*&amp;nbsp;Namespace:&amp;nbsp;논리적인&amp;nbsp;리소스&amp;nbsp;구분&lt;br /&gt;*&amp;nbsp;configMap/secret:&amp;nbsp;설정&lt;br /&gt;*&amp;nbsp;serviceAccount:&amp;nbsp;권한계정&lt;br /&gt;*&amp;nbsp;Role/ClusterRole:&amp;nbsp;권한설정(get,&amp;nbsp;list,&amp;nbsp;watch,&amp;nbsp;create&amp;hellip;.)&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;#쿠버네티스 API 호출&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-원하는&amp;nbsp;상태를&amp;nbsp;다양한&amp;nbsp;오브젝트(pod,&amp;nbsp;service,&amp;nbsp;ingress)로&amp;nbsp;정의(spec)하고&amp;nbsp;API서버에&amp;nbsp;Yaml&amp;nbsp;형식으로&amp;nbsp;전달!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-새로운 요청이 API 서버를 통해 접수 되면, 컨트롤러, 스케쥴러 가 캐치하여 node 내 kubelet과 함께 통신한 후, 신규 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;&lt;b&gt;yaml -&amp;gt; JSON&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;-yaml의 경우&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;object는&amp;nbsp;'&amp;nbsp;:&amp;nbsp;'&amp;nbsp;으로&amp;nbsp;구분,&amp;nbsp;array는&amp;nbsp;'&amp;nbsp;-&amp;nbsp;'&amp;nbsp;하이픈으로&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;apiVersion: v2&amp;nbsp;&lt;b&gt; // &quot;apiVersion&quot; : &quot;v2&quot;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kind: Pod&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;metadata:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;name: new-pod-app1&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;labels:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; app: app1&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;spec:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;containers:&amp;nbsp; &lt;b&gt;// &quot;container&quot; : [ { &quot;name&quot; : &quot;new-container&quot;, &quot;image&quot; : &quot;base1&quot;, &quot;ports&quot; : [ { &quot;containerPort&quot; : 8080 } ] } ]&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;- name: new-contanier&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; image: base1&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; ports:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; - containerPort: 8080&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>kubernetes</category>
      <author>jongviet</author>
      <guid isPermaLink="true">https://jongviet.tistory.com/167</guid>
      <comments>https://jongviet.tistory.com/167#entry167comment</comments>
      <pubDate>Mon, 10 Oct 2022 16:43:09 +0900</pubDate>
    </item>
    <item>
      <title>Sep 27, 2022 - DynamoDB</title>
      <link>https://jongviet.tistory.com/166</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;#dynamoDB&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-10월부터 이직해 다닐 회사에서 dynamoDB를 사용한다고 한다. MongoDB와 RDS 경험은 있어 적응이 쉬울 것 같기는 한데 문서를 찾아보면 찾아 볼 수록 둘과는 많이 다른 형태의 DB 구조 인것 처럼 보인다....&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-RDS는 최대한 중복을 제거하여 효율적으로 스토리지를 사용하게 하고, NOSQL은 데이터가 일부 중복되도 괜찮으니 스토리지를 일부 희생하더라도 빠른 성능을 목적으로 하고 있다. 그렇다면 Dynamo DB는...?&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;-key의 경우 partition Key(=primary key)만을 가지는 형태와 partition key + sort key를 함께 가지는 형태가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-데이터를 삽입, 삭제, 수정할 시에는 partition key를 기준으로 item 하나씩 write, delete, update가 가능하다. 즉 하나의 row(item)만 한번에 처리가 가능하여 batch request가 안되는 단점이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-가장 중요한 read 시에는 partition key + sort key 조합하여 read가 가능한 형태이다. 추가적으로 GSI(global secondary index)를 적용하여 sort key를 partition key로 두고, partition key를 GSI의 sort key로 놓는 형태로 read가 가능하다. &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;-모델링의 경우, RDS와 마찬가지로 1:1, 1:N 관계형태로 표현하고, 어떤 형태로 데이터 넣고, 어떤 형태로 데이터 읽을 것인지 정리한 후 key 디자인을 진행하는 형태가 추천된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-DynamoDB에는 join이라는 개념이 없어 오히려 비정규화를 지향한다고 보면 된다. 찾아본 바에 따르면 하나의 테이블에 필요한 모든 것을 담는게 오히려 쿼리 성능을 극대화 해준다고 한다. &lt;b&gt;MongoDB와는 또 다른 형태인 것으로 보이는데.. 이 또한 직접 테스트를 하고 쿼리를 던져보면서 깨달아야 할 것 같다.&lt;/b&gt;&lt;br /&gt;-sort key를 통해 선택, 범위 연산인 &amp;gt;, &amp;gt;=, &amp;lt;, &amp;lt;=, begin_withs, between 연산이 가능하다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-read의 종류는 2가지가 있는데, Eventual Consistent Read는 응답 속도는 빠르지만 최근 완료된 쓰기 작업 결과가 반영되지 않아 최종적인 데이터를 가져오지 않는다고 하고, Strong Consistent Read는 응답 속도는 느리지만 최근 완료된 쓰기 작업 결과가 반영되기 때문에 실시간 데이터에 민감한 비즈니스에는 사용이 어렵다고 한다.&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;-2018~19년에 주로 쓰인 게시글들을 보면 ORM이 없어서 매우 불편하고 usage를 쉽게 구글링하기 어려워 힘들다는 글들이 지배적이었다. 그러나 오늘 찾아보니 &lt;span style=&quot;color: #1c1e21;&quot;&gt;Dynamoose라고, Mongoose를 카피한 수준의 라이브러리가 있어 한번 사용해볼만 할 것 같다는 생각이 들었다. (Typescript도 지원!)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;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;-주말동안 직접 nestjs에 연동해서 스키마 작성부터 update, delete, insert 그리고 read까지 실습해봐야겠다.&lt;/p&gt;</description>
      <category>기타</category>
      <author>jongviet</author>
      <guid isPermaLink="true">https://jongviet.tistory.com/166</guid>
      <comments>https://jongviet.tistory.com/166#entry166comment</comments>
      <pubDate>Tue, 27 Sep 2022 21:35:49 +0900</pubDate>
    </item>
  </channel>
</rss>