<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>https://blog.hyojun.me</title>
    <link>https://devinjeon.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Thu, 2 Jul 2026 08:26:42 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>Devin Jeon</managingEditor>
    <image>
      <title>https://blog.hyojun.me</title>
      <url>https://tistory1.daumcdn.net/tistory/2786248/attach/b43c4aee7eae4147b13ef6bba7444c18</url>
      <link>https://devinjeon.tistory.com</link>
    </image>
    <item>
      <title>[Go-Go! Duck Roulette - 달려라! 오리 룰렛] 무작위 추첨 게임 개발</title>
      <link>https://devinjeon.tistory.com/13</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://hyojun.me/gogoduck/&quot;&gt;https://hyojun.me/gogoduck/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1768917977256&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;Go-Go! Duck Roulette - 달려라! 오리 룰렛&quot; data-og-description=&quot;오리들이 펼치는 무작위 순위 추첨 게임! 커피 내기, 이벤트 당첨자 선정, 발표 순서 정하기 등에 활용해 보세요!&quot; data-og-host=&quot;hyojun.me&quot; data-og-source-url=&quot;https://hyojun.me/gogoduck/&quot; data-og-url=&quot;https://hyojun.me/gogoduck&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bq7QUu/dJMb81GQ5LO/h33C0aGkC157YXefO1IwH1/img.png?width=920&amp;amp;height=460&amp;amp;face=0_0_920_460,https://scrap.kakaocdn.net/dn/biOaI2/dJMb82MwYpE/awbMcjPmdRDr1kEkkGb3JK/img.png?width=920&amp;amp;height=460&amp;amp;face=0_0_920_460,https://scrap.kakaocdn.net/dn/bIWcIn/dJMb9jgq7RF/6SfkJEENBd54dkIgnJDve0/img.png?width=264&amp;amp;height=264&amp;amp;face=0_0_264_264&quot;&gt;&lt;a href=&quot;https://hyojun.me/gogoduck/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://hyojun.me/gogoduck/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bq7QUu/dJMb81GQ5LO/h33C0aGkC157YXefO1IwH1/img.png?width=920&amp;amp;height=460&amp;amp;face=0_0_920_460,https://scrap.kakaocdn.net/dn/biOaI2/dJMb82MwYpE/awbMcjPmdRDr1kEkkGb3JK/img.png?width=920&amp;amp;height=460&amp;amp;face=0_0_920_460,https://scrap.kakaocdn.net/dn/bIWcIn/dJMb9jgq7RF/6SfkJEENBd54dkIgnJDve0/img.png?width=264&amp;amp;height=264&amp;amp;face=0_0_264_264');&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;Go-Go! Duck Roulette - 달려라! 오리 룰렛&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;오리들이 펼치는 무작위 순위 추첨 게임! 커피 내기, 이벤트 당첨자 선정, 발표 순서 정하기 등에 활용해 보세요!&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;hyojun.me&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;figure class=&quot;unsupported component-kakaotv&quot; contenteditable=&quot;false&quot; style=&quot;background:#000;margin:16px 0;min-height:72px;padding:10px 16px;display:flex;align-items:center;justify-content:center;text-align:center;box-sizing:border-box;width:100%;max-width:100%;&quot;&gt;
                &lt;p contenteditable=&quot;false&quot; style=&quot;margin:0;color:#8a8a8a;font-size:13px;line-height:1.6;user-select:none;pointer-events:none;&quot;&gt;동영상 서비스가 종료되어 해당 콘텐츠를 재생할 수 없습니다.&lt;/p&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;TL;DR&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;1등, 꼴등, 또는 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;a style=&quot;color: #0070d1;&quot; href=&quot;https://lazygyu.github.io/roulette/&quot;&gt;마블 룰렛(a.k.a 핀볼 룰렛)&lt;/a&gt;이라는 lazygyu 님께서 사내프로젝트로 개발한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;매우 훌륭한&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;웹 기반 룰렛 게임 가끔 사용해왔는데&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&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 data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;1. (마블룰렛 처럼) 완성도가 있으면서도&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;2. 가볍게 모두 같이 모여 즐길수있는 (~= 보는 맛이 있는)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;3. 웹으로 쉽게 사용가능한 (앱 설치없이, 모바일/PC 모두 가능)&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;span style=&quot;color: #333333; text-align: start;&quot;&gt;&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 data-ke-size=&quot;size16&quot;&gt;뭐 의미가 있는 사이드 프로젝트라기보다는... 그냥 취미생활 차원에서 한번 개발해보자 정도로 시작했고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요즘 딱 마침&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://antigravity.google/&quot;&gt;Google Antigravity&lt;/a&gt;라는 AI 코딩 도구가 새로 출시된 김에&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;요걸 사용해서 손코딩없이(손코딩 비율 10%이하) 작업을 해보자라는 마인드로 시작했다.&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;컨셉은 &quot;귀여움&quot;, &quot;병맛&quot; 정도...&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;&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;&quot;카메라 무빙&quot;을 마찬가지로 강조하고 싶었다. (슬로우 모션은 아직 넣지 못했지만 언젠가...^^;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;---&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Google Antigravity 1줄 사용평&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작업 계획(Planning mode)을 사람이 리뷰하는 flow를 매우 자연스럽게 IDE (vscode 기반) 에 녹인 점이 훌륭했음.&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;gogoduckroulette.png&quot; data-origin-width=&quot;1580&quot; data-origin-height=&quot;1540&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/chF1Fe/dJMcac2URp7/Zp8luBpJTjmLx0ZYnb1ZYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/chF1Fe/dJMcac2URp7/Zp8luBpJTjmLx0ZYnb1ZYK/img.png&quot; data-alt=&quot;게임 시작 메인 페이지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/chF1Fe/dJMcac2URp7/Zp8luBpJTjmLx0ZYnb1ZYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FchF1Fe%2FdJMcac2URp7%2FZp8luBpJTjmLx0ZYnb1ZYK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1580&quot; height=&quot;1540&quot; data-filename=&quot;gogoduckroulette.png&quot; data-origin-width=&quot;1580&quot; data-origin-height=&quot;1540&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;게임 시작 메인 페이지&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>gogoduck</category>
      <category>룰렛</category>
      <category>룰렛게임</category>
      <category>무작위추첨</category>
      <category>오리룰렛</category>
      <author>Devin Jeon</author>
      <guid isPermaLink="true">https://devinjeon.tistory.com/13</guid>
      <comments>https://devinjeon.tistory.com/13#entry13comment</comments>
      <pubDate>Wed, 21 Jan 2026 08:21:20 +0900</pubDate>
    </item>
    <item>
      <title>[공유] Kubernetes Scheduler Deep dive: (1) 스케줄러 동작 원리와 Scheduling Framework 이해</title>
      <link>https://devinjeon.tistory.com/11</link>
      <description>&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;슬라이드 자료는 아래 링크에서 확인하실 수 있습니다&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blog.deepdivers.dev/kubernetes-scheduler/1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://blog.deepdivers.dev/kubernetes-scheduler/1&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1654184141468&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;(1) 스케줄러 동작 원리와 Scheduling Framework 이해 - DeepDivers&quot; data-og-description=&quot;Kubernetes 스케줄러는 워크로드의 요구조건과 가용한 자원 상태에 따라 Pod를 최적의 Node에 배치하는 핵심적인 역할을 합니다. 또한 스케줄러는 다양하고 복잡한 요구조건에 유연하게 대응할 수 &quot; data-og-host=&quot;blog.deepdivers.dev&quot; data-og-source-url=&quot;https://blog.deepdivers.dev/kubernetes-scheduler/1&quot; data-og-url=&quot;https://blog.deepdivers.dev/kubernetes-scheduler/1&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://blog.deepdivers.dev/kubernetes-scheduler/1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://blog.deepdivers.dev/kubernetes-scheduler/1&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;(1) 스케줄러 동작 원리와 Scheduling Framework 이해 - DeepDivers&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Kubernetes 스케줄러는 워크로드의 요구조건과 가용한 자원 상태에 따라 Pod를 최적의 Node에 배치하는 핵심적인 역할을 합니다. 또한 스케줄러는 다양하고 복잡한 요구조건에 유연하게 대응할 수&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.deepdivers.dev&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;Kubernetes 스케줄러는 워크로드의 요구조건과 가용한 자원 상태에 따라 Pod를 최적의 Node에 배치하는 핵심적인 역할을 합니다. 또한 스케줄러는 다양하고 복잡한 요구조건에 유연하게 대응할 수 있도록, 확장 기능을 구현하기 위한 Scheduling Framework를 제공하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;이&amp;nbsp;슬라이드에서는&amp;nbsp;스케줄러의&amp;nbsp;역할과&amp;nbsp;동작&amp;nbsp;원리를&amp;nbsp;깊게&amp;nbsp;이해하며,&amp;nbsp;스케줄러의&amp;nbsp;기능들을&amp;nbsp;구현하는&amp;nbsp;여러가지&amp;nbsp;플러그인&amp;nbsp;코드와&amp;nbsp;함께&amp;nbsp;Scheduling&amp;nbsp;Framework를&amp;nbsp;살펴봅니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;br /&gt;목차&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Kubernetes&amp;nbsp;Scheduler의&amp;nbsp;역할&lt;/li&gt;
&lt;li&gt;Kubernetes&amp;nbsp;Scheduler의&amp;nbsp;동작&amp;nbsp;원리&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스케줄링의&amp;nbsp;3단계&amp;nbsp;과정&amp;nbsp;-&amp;nbsp;Filter,&amp;nbsp;Score,&amp;nbsp;Bind&lt;/li&gt;
&lt;li&gt;Scheduling&amp;nbsp;context&amp;nbsp;(Scheduling&amp;nbsp;cycle,&amp;nbsp;Bind&amp;nbsp;cycle)&lt;/li&gt;
&lt;li&gt;Optimistic&amp;nbsp;Binding&lt;/li&gt;
&lt;li&gt;스케줄러&amp;nbsp;전체&amp;nbsp;동작&amp;nbsp;흐름&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;확장&amp;nbsp;가능한&amp;nbsp;Scheduler&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여러&amp;nbsp;가지&amp;nbsp;Scheduler&amp;nbsp;확장&amp;nbsp;방식(Scheduler&amp;nbsp;Extender,&amp;nbsp;Scheduling&amp;nbsp;Framework)&lt;/li&gt;
&lt;li&gt;Scheduling&amp;nbsp;Framework&amp;nbsp;이해&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Plugin&amp;nbsp;코드와&amp;nbsp;함께&amp;nbsp;살펴보는&amp;nbsp;Extension&amp;nbsp;Points&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&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://deepdivers.gitbook.io)&quot;&gt;https://deepdivers.gitbook.io)&lt;/a&gt;를 운영하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;※&amp;nbsp;현재는&amp;nbsp;Kubernetes를&amp;nbsp;주요&amp;nbsp;주제로&amp;nbsp;다루고&amp;nbsp;있으나,&amp;nbsp;앞으로&amp;nbsp;다양한&amp;nbsp;주제로&amp;nbsp;확장해나갈&amp;nbsp;예정입니다.&lt;/p&gt;</description>
      <category>Tech</category>
      <category>container</category>
      <category>K8S</category>
      <category>k8s-scheduler</category>
      <category>kube-scheduler</category>
      <category>Kubernetes</category>
      <category>Scheduler</category>
      <category>스케줄러</category>
      <category>스케줄링</category>
      <category>컨테이너</category>
      <category>쿠버네티스</category>
      <author>Devin Jeon</author>
      <guid isPermaLink="true">https://devinjeon.tistory.com/11</guid>
      <comments>https://devinjeon.tistory.com/11#entry11comment</comments>
      <pubDate>Mon, 30 May 2022 23:36:32 +0900</pubDate>
    </item>
    <item>
      <title>개발자가 되려는 동생을 어떻게 도와줄 수 있을까</title>
      <link>https://devinjeon.tistory.com/10</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;개발자가 되기 위해 &quot;부트캠프&quot; 과정을 시작한 동생&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;비전공자인 동생이 온라인으로 진행되는 부트캠프 프론트엔드 &lt;span style=&quot;color: #000000;&quot;&gt;개발자&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;과정을 시작하게 되었다.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;내가 풀타임으로 가르칠 여건도 안 되고 자신도 없다. &amp;rarr; 여러 좋은 유/무료 교육 과정이 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;나는 옆에서 조금 도와주는 멘토 역할을 할 뿐&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;일단 내가 개발자로 있으니, 동생을 도와주어야겠다는 생각이 들었고, 매주 모르는 것을 질문하는 Q&amp;amp;A 세션을 진행했다.&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;알아서 부트캠프 강의 듣고 커리큘럼에 잘 따라가는 것과 별개로, 모르는 것들을 질문할 수 있는 시간으로 두었다. (부트캠프 과정에서 별도의 멘토링이 존재하지 않았음)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;하지만 몇 번 Q&amp;amp;A 세션을 진행할수록 &lt;b&gt;개인적으로 채워주고 싶은 부분들이 보이기 시작했고, 이제는 멘토링 할 때 나름의 기준이 생겼다.&lt;/b&gt; (물론 나는 전문 교육자가 아니고, 교육 경험이 부족하기 때문에, 내가 세운 나름의 교육 철학이 미래에는 시행착오가 될 수 있다. 더 좋은 방법이 있다면 언제든 환영...)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;동생은 부트 캠프를 시작한지 얼마 안 되었을 때, 이미 밤새 코딩에 몰두하며 아침 해가 뜨는 경험까지 할 정도로 흥미가 어느 정도 붙은 상태.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;즉, 동생이 동기부여가 되게끔 내가 따로 노력할 필요가 없었다. (다행히도...)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Q&amp;amp;A 세션: 주 2회 / 회당 2시간 정도 진행 중&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;(처음에는 회당 1시간이었다. 하지만 잘 따라오는 게 눈에 보이다 보니 가르치는 재미가 있어서 어느샌가 2시간이 되어버렸다. 초반이라 생각보다 시간을 많이 들인다고 생각 중, 점차 줄여 갈 예정.)&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;강의 내용만 따라가다보면 발생하는 문제&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;스스로 문제를 해결하는 능력 부재&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;주어진 지식만 습득하다 보니, 정작 필요한 지식을 스스로 터득하는 방법 부재&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;필요한 지식이 무엇인지 파악하는 능력(내가 모르는 게 무엇인지 알아야...)도 부족함.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;필요한 지식이 무엇인지 알았다면, 그때는 스스로 터득하는 방법이 필요&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;제한된 시간 내에 강의 내용에서 모든 것을 챙길 수 없음 &amp;rarr; 강의 내용에&lt;b&gt;'만'&lt;/b&gt; 의존하면 안 됨&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;때로는 너무 복잡한 개념을 한 번에 설명하는 것은 더 어렵게 느껴질 수 있기 때문에 강의에서는 충분히 넘어갈 수 있다고 생각함&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;대신 스스로 &quot;왜?&quot;를 생각하도록 만들 필요가 있음 (궁금증을 가지는 것부터 시작)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;보충이 필요한 부분은 스스로 탐구해 볼 수 있도록 더 심화 주제를 던져주기도 했음&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;Q&amp;amp;A 세션을 진행할 때 내가 코칭 하는 방식&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;1. 문제를 잘 해결하기 위해서는 본인이 겪는 문제를 잘 설명하도록 유도&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;생각을 날것으로 표현하도록 유도&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&amp;ldquo;네가 지금 생각하고 있는 것을 그대로 말을 해봐, 무엇이 문제인지 몰라서 질문하기가 애매하다면 그 사실도 말로 그냥 표현해도 돼&amp;rdquo;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;잘 풀리지 않는 알고리즘 문제에 대해 질문한다면, 코칭 과정에서 내가 직접 코드를 읽지 않고, 동생 본인이 코드 의도를 나에게 설명하도록 함.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;2. 항상 본인의 터득한 지식을 설명할 수 있는 단계까지 유도&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;설명하는 것의 필요성/중요성 강조&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;네가 배운 것을 설명해 보라고 하는 것은 내가 &amp;ldquo;검사하는 게 아니라&amp;rdquo;, 피드백을 주기 위함인 것을 강조 (심리적 거부감 방지)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;정확한 이해를 유도&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;남에게 설명하려면 더 정확히 알아야 함&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;나에게 설명하면서 본인이 잘못된 걸 깨닫고 스스로 정정할 때는, 고무 오리 meme을 보여주면서 &amp;ldquo;네가 지금 이런 케이스다 ㅋㅋ&amp;rdquo; 하면서 재미를 유도 (남들도 나와 똑같은 경험을 한다를 인식)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;모르는 부분을 직접적으로 노출할 수 있음&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;무엇을 모르는지 정확히 파악하고 심화 주제를 던져줄 수 있는 포인트&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;모르는건 부끄러운 게 아님, 모르는 걸 숨기는 것이 더 부끄러운 일.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;개발은 혼자 하는 것이 아니라 협업이기 때문에, 코드를 짜는 것보다 내가 하고자 하는 것, 하고 있는 것, 왜 해야 하는지, 내가 잘 아는 것들을 남에게 잘 설명하고 설득하는 것이 더욱 중요하다는 것을 재차 강조&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;면접 대비&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;면접에 나올만한 질문을 할 땐, 실제로 면접 질문에 자주 나오는 것임을 강조&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;추가로, 내 면접 경험에서 받았던 질문과 내 면접 회고를 같이 이야기해 줄 기회&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;이렇게 시도해 봄&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;모르는 것을 질문했을 때, 암묵적인 지식으로 생각하는 부분을 설명해 보라고 함.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;e.g. 메모리 사용량 초과는 왜 발생하는가? &amp;rarr; 메모리 초과에 대해 설명하기 전에 &quot;메모리&amp;rdquo;는 어떻게 관리되는지 설명해보라고 하거나, 메모리 할당이 어떻게 이루어지는지 설명해 보라고 함.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;어느 수준으로 이해하고 있는지, 어디서부터 보충이 필요할지, 어디서부터 잘못된 이해를 가지고 있는지 알 수 있음. (심화 주제를 던져줄 수 있는 포인트가 됨.)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;Q&amp;amp;A 세션 시간이 좀 남는 경우 강의 커리큘럼에서 무엇을 배웠는지(아주 간단하게만) 브리핑하고, 중요해 보이는 것들은 설명해 보라고 함(e.g. 매우 중요한 CS 개념, 면접에서 나올만한 것들, 등)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;100점짜리 답변을 기대하면 안 됨&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;코치하는 입장에서 심화 주제를 던질 수 있는 포인트를 발견하고, 심화 주제를 탐색하도록 기회를 부여하는 것이 중요&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;답변에서 잘 이해하고 있는 부분, 애매하거나 더 정확한 이해가 필요한 부분이 드러나는 것이 중요&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;좀 더 조리 있게 설명하려면 어떻게 해야 하는지 피드백 해줄 필요가 있음&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;오해를 일으킬 만한 키워드 정정해 줄 필요가 있음&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;Javascript를 Java로 이야기한다든지... (둘은 다른 것임을 모름)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;3. 스스로 무엇을 모르는 것인지 깨닫고, 스스로 필요한 지식을 터득하도록 함&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;무엇을 모르는 것인지 알더라도, 당장 문서를 보면 어렵게 느껴질 수 있음 &amp;rarr; 왜 어렵게 느끼는지? 왜 어려운지?를 스스로 찾게 함.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;초심자들은 기초지식이 없기 때문에, 왜 이해할 수 없는지 파악하기조차 힘듦. 문서를 봤을 때 설명에서 무엇이 어려운지(보통은 특정 키워드, 사전 지식에 대한 부재)를 스스로 정리하고 함께 알아보도록 유도.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;알아야 할 사전 지식이 많다고 느껴질 때 많은 초심자들이 어려움을 겪고 좌절을 느낌&lt;br /&gt;예) A를 알 기위해서는 B도 알아야 하고 B를 이해하려면 C를 알아야 하고...&lt;br /&gt;예) B의 범위가 너무 광대하고 깊어서, 어떤 수준까지 이해해야 하는지 감이 없음&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&amp;ldquo;A를 먼저 한번 직접 조사해 보고 나한테 설명해 봐.&amp;rdquo;라고 하면 때로는 막연할 수 있음 &amp;rarr; &amp;ldquo;설명하기 어렵다면 무엇 때문에 어려운지 한번 생각해 봐&amp;rdquo;를 덧붙인다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;때로는 속도가 느리더라도 단계적인 접근이 필요&lt;/span&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;어떤 개념을 이해하는 데 필요한 사전 지식은, 결국 광범위한 지식 이해에 도움 되는 경우가 많음. &amp;rarr; A를 아는 것보다 B, C를 아는것이 중요할 때가 많음&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;B, C부터 차근차근 알아가도록 하면서, 자연스럽게 A라는 개념이 왜 나왔고 왜 필요한지 깨달을 수 있도록 유도&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;스스로 지식을 터득하는 과정&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;지식을 어떻게 터득하는지를 보여주는 것도 필요&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;코칭 하는 사람이 직접 말로 생각하는 과정을 잘 표현해 줄 필요가 있음&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;나는 지금 이걸 모르는데 검색해도 잘 모르겠네?&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;내가 뭘 모르는 거지? 아 A를 이해하려면 B를 알아야겠구나.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;B를 알아보는데 잘 모르겠다. 좀 더 쉽게 설명된 문서가 없을까?&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;아 이런 식으로 검색하니 좀 더 잘 찾아지네.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이 설명이 더 직관적으로 이해되는구나.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;B를 깊게 이해하는 것은 불필요해 보이는데, 이 정도 수준 개념만 알고 A를 다시 볼까.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;등...&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;어떻게 검색하는지 (검색 팁 전수 필요)&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;일반인들은 구글 검색이 생각 외로 익숙하지 않을 수 있음.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;영어로 작성된 문서가 친숙하게 느껴지도록...&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;영어로 검색했을 때 더 방대하고 정확한 정보가 나올 때 많음&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;한글 문서는 최신 정보를 반영하지 못할 때가 있음&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;오역으로 인한 잘못된 정보가 존재할 때도 있음&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;처음부터 한글 문서를 주로 보기 시작하면 이후에 영어 문서 볼 때 거부감이 들 수 있음.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;나도 그랬음. 지금도 영향을 받고 있어서 영어로 읽도록 의식적으로 노력하는 중.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;4. 왜 그럴까?, 왜 필요할까?를 먼저 생각하도록 유도함&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;당연하게끔 되는 것은 없음&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&amp;ldquo;해야 된다&amp;rdquo; &amp;rarr; &quot;왜?&amp;rdquo; 궁금증이 나오도록 자연스럽게 이어져야 함.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;암묵적인 지식으로 당연하게끔 생각하는 부분들 중에 이해가 필요한 부분을 짚어서 왜? 인지 질문할 필요가 있음&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;왜 이해해야 하는지 설명&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이걸 이해하면 어떤 것들을 더 이해할 수 있는지 설명&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;5. 공감을 많이 해줘야 함&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;나도 겪었던 문제&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;너와 똑같은/비슷한 삽질로 나도 밤을 새웠었다(...)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;나도 똑같은 질문을 했다!&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;나도 못 했던 것들&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이거 내가 실제로 받았던 면접 질문인데 대답 못해서 떨어졌었다(...)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;나도 너의 설명을 들으면서 많이 배웠다.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;실제로 Javascript GC가 어떻게 동작하는지 나도 몰랐음. 동생한테 배움. 이때 칭찬 많이 해줌.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;네가 진짜 잘하고 있다 강조해야 함&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;진짜 중요. 칭찬은 고래를 춤추게 한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;절대 같은 것을 여러 번 질문하거나, 계속 이해를 못 한다고 짜증 내면 안 됨&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;왜 이해를 못 하고 있는 것인지 파악할 필요가 있음&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;만약 부족했다면 더 강조하거나, 스스로 다시 조사하도록 유도할 필요가 있음.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;6. 한 번에 이런 생각 흐름이 정착되기 힘듦&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;지속적으로 질문 유도, 심화 주제를 던져주면서, 스스로 본인의 생각의 흐름에 &amp;ldquo;왜?&amp;rdquo;라는 질문을 계속 넣도록 유도하고 있음.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;성향에 따라 다르겠지만, 꽤 오랜시간의 반복 밖에 답이 없어보임(검증되지 않음)&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;다른 답이 있으면 알려주세요...&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;위에서 강조한 코칭 지점들이 동생의 생각 흐름에 잘 정착된다면, 부트캠프의 강의 내용이 부족한 부분이 있더라도 시간의 지남에 따라 결국 자연스럽게 해결될 것이라고 &lt;b&gt;기대중&lt;/b&gt;이다. (=발전할 수 있는 기틀 마련)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;아직까지는 꽤 좋은 성과들이 보이지만 확신하긴 이르다.&lt;/span&gt;&lt;/p&gt;</description>
      <category> </category>
      <category>개발자</category>
      <category>부트캠프</category>
      <author>Devin Jeon</author>
      <guid isPermaLink="true">https://devinjeon.tistory.com/10</guid>
      <comments>https://devinjeon.tistory.com/10#entry10comment</comments>
      <pubDate>Wed, 11 May 2022 07:48:49 +0900</pubDate>
    </item>
    <item>
      <title>Kubernetes 네트워크 이해하기 (2) : 서비스 개념과 동작 원리</title>
      <link>https://devinjeon.tistory.com/9</link>
      <description>&lt;p&gt;&lt;script async class=&quot;speakerdeck-embed&quot; data-id=&quot;a6ce2249e582483695e69c7c8ea53850&quot; data-ratio=&quot;1.77777777777778&quot; src=&quot;//speakerdeck.com/assets/embed.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;
&lt;p&gt;Short link -&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://hyojun.me/~k8s-network-2&quot;&gt;https://hyojun.me/~k8s-network-2&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;# 다른 슬라이드들&lt;/p&gt;
&lt;p&gt;* Container부터 다시 살펴보는 Kubernetes Pod 동작 원리&lt;br /&gt;&lt;a href=&quot;https://hyojun.me/~k8s-pod-internal&quot;&gt;https://hyojun.me/~k8s-pod-internal&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;* Kubernetes 네트워크 이해하기 (1) : 컨테이너 네트워크부터 CNI까지&lt;br /&gt;&lt;a href=&quot;https://hyojun.me/~k8s-network-1&quot;&gt;https://hyojun.me/~k8s-network-1&lt;/a&gt;&lt;/p&gt;</description>
      <category>Tech</category>
      <category>externalip</category>
      <category>iptables</category>
      <category>ipvs</category>
      <category>K8S</category>
      <category>kubeproxy</category>
      <category>Kubernetes</category>
      <category>nodeport</category>
      <category>service</category>
      <category>sessionaffinity</category>
      <category>userspace</category>
      <author>Devin Jeon</author>
      <guid isPermaLink="true">https://devinjeon.tistory.com/9</guid>
      <comments>https://devinjeon.tistory.com/9#entry9comment</comments>
      <pubDate>Thu, 22 Apr 2021 17:20:57 +0900</pubDate>
    </item>
    <item>
      <title>Kubernetes 네트워크 이해하기 (1) : 컨테이너 네트워크부터 CNI까지</title>
      <link>https://devinjeon.tistory.com/8</link>
      <description>&lt;p&gt;&lt;script async class=&quot;speakerdeck-embed&quot; data-id=&quot;2653ccb7284e44aabbc3ddd01d0fd440&quot; data-ratio=&quot;1.77777777777778&quot; src=&quot;//speakerdeck.com/assets/embed.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;
&lt;p&gt;Short link -&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://hyojun.me/~k8s-network-1&quot;&gt;https://hyojun.me/~k8s-network-1&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;# 다른 슬라이드들&lt;/p&gt;
&lt;p&gt;* Container부터 다시 살펴보는 Kubernetes Pod 동작 원리&lt;br /&gt;&lt;a href=&quot;https://hyojun.me/~k8s-pod-internal&quot;&gt;https://hyojun.me/~k8s-pod-internal&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;* Kubernetes 네트워크 이해하기 (2) : 서비스 개념과 동작 원리&lt;br /&gt;&lt;a href=&quot;https://hyojun.me/~k8s-network-2&quot;&gt;https://hyojun.me/~k8s-network-2&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Tech</category>
      <category>CNI</category>
      <category>container network</category>
      <category>Flannel</category>
      <category>K8S</category>
      <category>Kubernetes</category>
      <category>Network</category>
      <category>overlay</category>
      <category>pod network</category>
      <category>VxLAN</category>
      <author>Devin Jeon</author>
      <guid isPermaLink="true">https://devinjeon.tistory.com/8</guid>
      <comments>https://devinjeon.tistory.com/8#entry8comment</comments>
      <pubDate>Thu, 22 Apr 2021 17:18:03 +0900</pubDate>
    </item>
    <item>
      <title>Kubernetes Pod internals with the fundamentals of Containers</title>
      <link>https://devinjeon.tistory.com/7</link>
      <description>&lt;p&gt;&lt;a href=&quot;https://hyojun.me/~k8s-pod-internal-en&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://hyojun.me/~k8s-pod-internal-en&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;script async class=&quot;speakerdeck-embed&quot; data-id=&quot;cd02a5cc3a9a44b7aeea17524d663087&quot; data-ratio=&quot;1.77777777777778&quot; src=&quot;//speakerdeck.com/assets/embed.js&quot;&gt;&lt;/script&gt;</description>
      <category>Tech</category>
      <category>container</category>
      <category>Kubernetes</category>
      <category>Pod</category>
      <author>Devin Jeon</author>
      <guid isPermaLink="true">https://devinjeon.tistory.com/7</guid>
      <comments>https://devinjeon.tistory.com/7#entry7comment</comments>
      <pubDate>Fri, 2 Apr 2021 01:07:34 +0900</pubDate>
    </item>
    <item>
      <title>Container부터 다시 살펴보는 Kubernetes Pod 동작 원리</title>
      <link>https://devinjeon.tistory.com/6</link>
      <description>&lt;p&gt;&lt;script async class=&quot;speakerdeck-embed&quot; data-id=&quot;6a1116d79a8f4d46bf3307bee3af1806&quot; data-ratio=&quot;1.77777777777778&quot; src=&quot;//speakerdeck.com/assets/embed.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;
&lt;p&gt;Short link -&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://hyojun.me/~k8s-pod-internal&quot;&gt;https://hyojun.me/~k8s-pod-internal&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;# 다른 슬라이드들&lt;/p&gt;
&lt;p&gt;* Kubernetes 네트워크 이해하기 (1) : 컨테이너 네트워크부터 CNI까지&lt;br /&gt;&lt;a href=&quot;https://hyojun.me/~k8s-network-1&quot;&gt;https://hyojun.me/~k8s-network-1&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;* Kubernetes 네트워크 이해하기 (2) : 서비스 개념과 동작 원리&lt;br /&gt;&lt;a href=&quot;https://hyojun.me/~k8s-network-2&quot;&gt;https://hyojun.me/~k8s-network-2&lt;/a&gt;&lt;/p&gt;</description>
      <category>Tech</category>
      <author>Devin Jeon</author>
      <guid isPermaLink="true">https://devinjeon.tistory.com/6</guid>
      <comments>https://devinjeon.tistory.com/6#entry6comment</comments>
      <pubDate>Wed, 17 Mar 2021 21:34:01 +0900</pubDate>
    </item>
    <item>
      <title>Kubernetes의 Docker container runtime 지원 중단에 대하여</title>
      <link>https://devinjeon.tistory.com/5</link>
      <description>&lt;h1&gt;Kubernetes의 Docker container runtime 지원 중단에 대하여&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;기존에 Container, Kubernetes에 대한 기반 지식이 거의 없는 상태에서 위 내용을 처음부터 잘 이해하기엔 약간의 어려움이 있어서 개인적으로 정리해보았습니다. (얕게 한번 훑어보는 느낌으로)&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;a href=&quot;https://kubernetes.io/blog/2020/12/02/dont-panic-kubernetes-and-docker/&quot;&gt;https://kubernetes.io/blog/2020/12/02/dont-panic-kubernetes-and-docker/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Kubernetes는 Docker를 더 이상 Container runtime으로 사용하지 않는 것으로 결정했습니다. 1.20.0 버전부터 경고가 표시되며 2021년 하반기 정도로 계획된 1.23 릴리즈부터 완전히 중단될 예정입니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 지원 중단 이후 기존에 Docker로 빌드한 이미지들은 사용할 수 없는 걸까요?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아닙니다. 우리가 Docker를 사용해서 만들었던 컨테이너 이미지들(&lt;code&gt;$ docker build ...&lt;/code&gt;)은 Kubernetes에서 다른 컨테이너 런타임을 사용하더라도 그대로 사용할 수 있습니다. 그 이유는 &lt;b&gt;Docker의 이미지는 실제로 &lt;a href=&quot;https://github.com/opencontainers/image-spec&quot;&gt;OCI 이미지 스펙&lt;/a&gt;을 기반으로 하고 있기 때문&lt;/b&gt;입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;OCI(Open Container Initiative) 란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OCI란, 컨테이너에 대한 표준을 만들고 이를 통일하기 위한 조직이자 프로젝트인데요. 여러 다양한 컨테이너 런타임(containerd, CRI-O)들이 통일된 규격을 사용하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨테이너 이미지의 경우 &lt;a href=&quot;https://github.com/opencontainers/image-spec&quot;&gt;https://github.com/opencontainers/image-spec&lt;/a&gt;에 지정된 규격을 사용하고 있기 때문에, Docker에서 빌드 한 이미지 또한 다른 OCI 표준을 따르는 다른 컨테이너 런타임(&lt;code&gt;containerd&lt;/code&gt;, &lt;code&gt;cri-o&lt;/code&gt;)을 사용하더라도 그대로 사용할 수 있는 것이죠.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 왜 Kubernetes는 Container Runtime으로 널리 잘 사용되던 Docker를 지원 중단하는 것일까요?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Docker는 하나의 &quot;플랫폼&quot;으로서 containerd에서 제공하지 않는 Network, 빌드 등 여러가지 기능들을 쉽게 사용할 수 있도록 좀더 사용자(user) 친화적인 UX를 제공하고 있는데요.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;1.png&quot; data-origin-width=&quot;906&quot; data-origin-height=&quot;470&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7mC1c/btqT0tov0n1/B8BrDYUaxiY9KlSgbkkzyk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7mC1c/btqT0tov0n1/B8BrDYUaxiY9KlSgbkkzyk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7mC1c/btqT0tov0n1/B8BrDYUaxiY9KlSgbkkzyk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7mC1c%2FbtqT0tov0n1%2FB8BrDYUaxiY9KlSgbkkzyk%2Fimg.png&quot; data-filename=&quot;1.png&quot; data-origin-width=&quot;906&quot; data-origin-height=&quot;470&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;Kubernetes의 Docker 지원 중단을 쉽게 이해하기 위해 잠시 Docker의 container runtime 구조에 대하여 살펴볼 필요가 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;2.png&quot; data-origin-width=&quot;1130&quot; data-origin-height=&quot;636&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7GuPL/btqT6HeXtWo/yXQ9uUFKMDywHZJdkKOV11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7GuPL/btqT6HeXtWo/yXQ9uUFKMDywHZJdkKOV11/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7GuPL/btqT6HeXtWo/yXQ9uUFKMDywHZJdkKOV11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7GuPL%2FbtqT6HeXtWo%2FyXQ9uUFKMDywHZJdkKOV11%2Fimg.png&quot; data-filename=&quot;2.png&quot; data-origin-width=&quot;1130&quot; data-origin-height=&quot;636&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;runC?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Docker는 많은 기반 시스템들(plumbing)들로 구성되는데, 그중에서도 컨테이너 환경을 구성하는 시스템들(e.g. &quot;cgroup&quot;, &quot;namespace&quot; 등)을 통합하고 추상화하여 runC라는 범용 경량 컨테이너 런타임을 공개했습니다. 이 &lt;code&gt;runC&lt;/code&gt;는 Docker에 대한 종속성이 없도록 모듈화되었고, OCI runtime-spec을 따르기 때문에 쉽게 다른 컨테이너 기반 시스템에서 사용할 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;containerd?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;containerd는 고수준 컨테이너 런타임(High-level Container Runtime)으로서, 컨테이너를 실행하기 위한 여러 OS의 syscall들을 추상화하여, 컨테이너를 사용하는 시스템이 커널에 직접 접근하지 않고도 runC와 같은 저수준 컨테이너 런타임을 관리할 수 있습니다. 그 밖에도 컨테이너 이미지를 실행/관리하고 컨테이너들의 수명주기 관리, 오버레이 파일시스템과 같은 Graphdriver가 작동하는 방식을 정의하는 등 여러 가지 역할을 하고 있습니다.&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 Engine은 이미지를 관리하고, 컨테이너를 실행하고 동작시키는 데 있어서 &lt;code&gt;containerd&lt;/code&gt; 데몬과 통신하여 &lt;code&gt;runC&lt;/code&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;containerd는 단순히 Docker에서만 사용되도록 만들어진 것이 아닌, Kubernetes 그리고 다양한 OS를 기반으로 한 컨테이너 플랫폼에서 사용될 수 있도록 설계되었습니다. 그 예로, Kubernetes와 잘 통합될 수 있도록 CRI(Container Runtime Interface)를 구현하고 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;CRI(Container Runtime Interface)란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Kubernetes에서는 &lt;code&gt;Docker&lt;/code&gt;를 컨테이너 런타임으로 사용하기 위해 &lt;a href=&quot;https://github.com/kubernetes/kubernetes/tree/v1.20.2/pkg/kubelet/dockershim&quot;&gt;dockershim&lt;/a&gt;과 같은 도구를 kubelet에 구현하여 Docker engine의 인터페이스 변경에 맞게 수정하여 사용해왔습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만, 이러한 통합 방식은 kubelet에 대한 깊은 이해가 필요할 뿐만 아니라, 컨테이너 런타임의 유지 보수를 각각 관리해 주어야 하는 유지 보수의 어려움이 존재합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 Kubernetes에서는 이러한 어려움을 해결하기 위해 컨테이너 런타임들과 kubelet이 쉽게 통합될 수 있도록 정의 것이 CRI(Container Runtime Interface)이고, &lt;code&gt;containerd&lt;/code&gt;, &lt;code&gt;cri-o&lt;/code&gt;와 같은 여러 가지 컨테이너 런타임들은 이러한 인터페이스를 충실히 구현하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kubelet은 그렇게 구현된 인터페이스를 통해 컨테이너 런타임들과 통신하여 컨테이너를 생성, 종료하고 관리하는 동작들을 할 수 있는 것이죠.&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;현재 Kubernetes에서 지원하는 컨테이너 런타임은 다음 문서에서 볼 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://kubernetes.io/docs/setup/production-environment/container-runtimes/&quot;&gt;https://kubernetes.io/docs/setup/production-environment/container-runtimes/&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. (정리) 굳이 Docker를 사용할 필요가 없는 Kubernetes&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;Docker는 Kubernetes 1.20.0부터 컨테이너 런타임으로서 지원 중단 &quot;경고&quot;를 표시하며, 1.23.0(2021년 하반기 예정)부터 완전히 지원 중단될 예정입니다. &lt;a href=&quot;https://kubernetes.io/blog/2020/12/02/dockershim-faq/#when-will-dockershim-be-removed&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;참고&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;OCI(Open Container Initiative)는 컨테이너에 관련된 표준을 만드는 조직, 프로젝트입니다.&lt;/li&gt;
&lt;li&gt;Docker의 이미지는 OCI에서 정의한 이미지 표준을 따르므로, OCI 표준을 준수하는 컨테이너 플랫폼에서는 그대로 사용할 수 있습니다.&lt;/li&gt;
&lt;li&gt;Docker는 컨테이너를 통해 애플리케이션을 쉽게 배포, 빌드 할 수 있도록 돕기 위한 &quot;플랫폼&quot;입니다.&lt;/li&gt;
&lt;li&gt;Docker engine은 내부적으로 runC, containerd를 사용하고, 이를 다시 추상화하여 인터페이스를 제공합니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;runC는 격리된 환경인 컨테이너를 구성하는 데 필요한 cgroup, namespace과 같은 시스템들을 통합하여 모듈화한 저수준 컨테이너 런타임입니다.&lt;/li&gt;
&lt;li&gt;containerd는 컨테이너의 수명주기를 관리하고, 이미지를 실행/관리, syscall 추상화, graphdriver의 동작 방식을 정의하는 등 저수준 컨테이너 런타임을 관리할 수 있는 추상화된 인터페이스를 제공합니다.&lt;/li&gt;
&lt;li&gt;runC, containerd는 OCI의 스펙을 따르며 따라서 Docker에 대한 종속성 없이 독립적으로 사용될 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;기존에는 Kubernetes에서 &lt;code&gt;dockershim&lt;/code&gt;과 같은 도구를 kubelet에 내장하여, Docker engine의 인터페이스 변화에 맞게 유지 보수해 왔습니다.
&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Kubernetes에서는 컨테이너 런타임들과의 유연한 통합과 유지 보수의 효율성을 위해 CRI(Container Runtime Interface)를 정의했습니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;containerd&lt;/code&gt;, &lt;code&gt;cri-o&lt;/code&gt;와 같은 컨테이너 런타임들은 이러한 인터페이스를 구현하고 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Docker는 이미 CRI를 제공하는 containerd를 기반으로 하고 있습니다. 그리고 Kubernetes에서는 이미 &lt;code&gt;containerd&lt;/code&gt;를 컨테이너 런타임으로 사용할 수 있도록 제공하고 있으며, 기존에 Docker를 컨테이너 런타임으로 사용하더라도 &lt;code&gt;containerd&lt;/code&gt;를 컨테이너 런타임으로 사용하는 데 있어서 문제가 없습니다. 때문에 Docker를 지속적으로 지원하는 것은 비효율적이고 불필요하다고 판단한 것입니다.&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를 사용하는 것과 containerd를 사용하는 것은 같은 containerd를 사용하는 것이나 다름없지만 pod을 실행하는 데 있어서 latency, CPU usage, Memory usage의 성능 차이도 있다고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://kubernetes.io/blog/2018/05/24/kubernetes-containerd-integration-goes-ga/#performance&quot;&gt;https://kubernetes.io/blog/2018/05/24/kubernetes-containerd-integration-goes-ga/#performance&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;3.png&quot; data-origin-width=&quot;564&quot; data-origin-height=&quot;462&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o5W2K/btqT03iTUK9/29LCNlq2uscpSahNFRKck1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o5W2K/btqT03iTUK9/29LCNlq2uscpSahNFRKck1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o5W2K/btqT03iTUK9/29LCNlq2uscpSahNFRKck1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo5W2K%2FbtqT03iTUK9%2F29LCNlq2uscpSahNFRKck1%2Fimg.png&quot; data-filename=&quot;3.png&quot; data-origin-width=&quot;564&quot; data-origin-height=&quot;462&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Q541a/btqT8HMlh5W/FboRmwYGQaVfF7DMbUghB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Q541a/btqT8HMlh5W/FboRmwYGQaVfF7DMbUghB1/img.png&quot; data-filename=&quot;4.png&quot; data-origin-width=&quot;470&quot; data-origin-height=&quot;468&quot; width=&quot;318&quot; height=&quot;NaN&quot; style=&quot;width: 42.7692%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Q541a/btqT8HMlh5W/FboRmwYGQaVfF7DMbUghB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQ541a%2FbtqT8HMlh5W%2FFboRmwYGQaVfF7DMbUghB1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;470&quot; height=&quot;468&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cWL4w2/btqT6HlLmc8/KlNVMzbvMbeQdS6hKHxKn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cWL4w2/btqT6HlLmc8/KlNVMzbvMbeQdS6hKHxKn1/img.png&quot; data-filename=&quot;5.png&quot; data-origin-width=&quot;732&quot; data-origin-height=&quot;556&quot; style=&quot;width: 56.068%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cWL4w2/btqT6HlLmc8/KlNVMzbvMbeQdS6hKHxKn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcWL4w2%2FbtqT6HlLmc8%2FKlNVMzbvMbeQdS6hKHxKn1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;732&quot; height=&quot;556&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 참고한 글(같이 읽으면 좋은 글)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://kubernetes.io/blog/2020/12/02/dont-panic-kubernetes-and-docker/&quot;&gt;https://kubernetes.io/blog/2020/12/02/dont-panic-kubernetes-and-docker/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://kubernetes.io/ko/docs/setup/production-environment/container-runtimes/&quot;&gt;https://kubernetes.io/ko/docs/setup/production-environment/container-runtimes/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://kubernetes.io/blog/2016/12/container-runtime-interface-cri-in-kubernetes/&quot;&gt;https://kubernetes.io/blog/2016/12/container-runtime-interface-cri-in-kubernetes/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/kubernetes/kubernetes/blob/242a97307b34076d5d8f5bbeb154fa4d97c9ef1d/docs/devel/container-runtime-interface.md&quot;&gt;https://github.com/kubernetes/kubernetes/blob/242a97307b34076d5d8f5bbeb154fa4d97c9ef1d/docs/devel/container-runtime-interface.md&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://kubernetes.io/blog/2018/05/24/kubernetes-containerd-integration-goes-ga/&quot;&gt;https://kubernetes.io/blog/2018/05/24/kubernetes-containerd-integration-goes-ga/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.docker.com/blog/runc/&quot;&gt;https://www.docker.com/blog/runc/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.docker.com/blog/what-is-containerd-runtime/&quot;&gt;https://www.docker.com/blog/what-is-containerd-runtime/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.opennaru.com/kubernetes/containerd/&quot;&gt;http://www.opennaru.com/kubernetes/containerd/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://caylent.com/what-is-containerd&quot;&gt;https://caylent.com/what-is-containerd&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Tech</category>
      <category>container runtime</category>
      <category>containerd</category>
      <category>cri</category>
      <category>deprecated</category>
      <category>docker</category>
      <category>K8S</category>
      <category>Kubernetes</category>
      <category>OCI</category>
      <category>runC</category>
      <author>Devin Jeon</author>
      <guid isPermaLink="true">https://devinjeon.tistory.com/5</guid>
      <comments>https://devinjeon.tistory.com/5#entry5comment</comments>
      <pubDate>Tue, 19 Jan 2021 20:16:00 +0900</pubDate>
    </item>
    <item>
      <title>Zombie process reaping 에 대하여, Container에서 고려할 부분들</title>
      <link>https://devinjeon.tistory.com/4</link>
      <description>&lt;p&gt;Container의 PID namespace 격리에 대해서 학습하고 이를 정리하다 보니, Zombie process부터 init system 등 여러 가지를 다시 짚어보는 좋은 계기가 되었습니다.&lt;/p&gt;
&lt;p&gt;이미 알고 계시는 내용이 많겠지만, 그래도 공유해봅니다. (좀 깁니다...)&lt;/p&gt;
&lt;h2&gt;목차&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Zombie process&lt;/li&gt;
&lt;li&gt;고의적으로 OrphanProcess 를 만들어봅시다.&lt;/li&gt;
&lt;li&gt;고아 프로세스를 거두어준init process(pid=1)&lt;/li&gt;
&lt;li&gt;initprocess?&lt;/li&gt;
&lt;li&gt;여기까지 이야기한 내용을 정리해봅시다.&lt;/li&gt;
&lt;li&gt;Container에서의 pid=1에 대하여
&lt;ul&gt;
&lt;li&gt;그럼 Container에서 Zombie process reaping 은 어떻게 해야할까요?&lt;/li&gt;
&lt;li&gt;Container 용 경량화된 init system의 등장&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Kubernetes의 PID namespacesharing&lt;/li&gt;
&lt;li&gt;최종정리&lt;/li&gt;
&lt;li&gt;참고한 글(함께 읽어보면 좋은 글)&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;1. Zombie process&lt;/h2&gt;
&lt;p&gt;Zombie process에 대해서 한번 짚고 넘어가도록 하지요.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Zombie process는 실제로는 종료된 프로세스이지만, Process Table에 여전히 남아있는 프로세스입니다.&lt;/li&gt;
&lt;li&gt;Zombie process는 Defunct process라고도 부릅니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이렇게 Process Table에 남게 되는 정보는 컴퓨팅 리소스(CPU, Disk, Memory)를 사용하진 않지만, 최대 프로세스 개수 제한(&lt;code style=&quot;letter-spacing: 0px;&quot;&gt;$ sysctl kernel.pid_max&lt;/code&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;)과 같은 일부 시스템 리소스를 차지하게 됩니다. 그 예로, Process table이 꽉 차게 되면 더 이상 프로세스를 실행할 수 없는 상황이 발생할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그렇다면 종료된 프로세스는 Process Table로부터 언제 제거될까요?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;일반적으로 부모 프로세스가 자식 프로세스를 실행하고, 자식 프로세스가 종료되어 부모 프로세스로부터 &lt;code&gt;wait&lt;/code&gt; system call(e.g. &lt;a href=&quot;https://linux.die.net/man/2/waitpid&quot;&gt;waitpid&lt;/a&gt;)이 호출되면 Process table로부터 제거됩니다.&lt;/li&gt;
&lt;li&gt;자식 프로세스의 실행이 종료된 이후에 부모 프로세스가 종료되면, 부모 프로세스와 함께 Process Table로부터 제거됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;하지만 반대로,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;부모 프로세스가 자식 프로세스보다 먼저 종료되는 경우&lt;/li&gt;
&lt;li&gt;부모 프로세스가 자식 프로세스의 종료 처리 역할을 제대로 하지 못하는 경우&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;좀비 프로세스가 발생할 수 있습니다. 여기서, 부모 프로세스가 먼저 종료되어 기존의 부모 프로세스를 잃어버린 자식 프로세스들은 &lt;code&gt;Orphan Process&lt;/code&gt;(고아 프로세스)가 됩니다.&lt;/p&gt;
&lt;h2&gt;2. 고의적으로 Orphan Process 를 만들어봅시다.&lt;/h2&gt;
&lt;p&gt;Bash에서 간단한 스크립트를 하나 만듭니다.&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;background-color: #efefef; font-family: Menlo, Consolas, Monaco, monospace; letter-spacing: 0px;&quot;&gt;make-orphans.sh&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;html xml&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;  #!/usr/bin/env bash

  for ((i = 0; i &amp;lt; 3; i ++)); do
      # Make zombies by executing subshells(child processes) on background
      (echo &quot;I'm a child&quot;; sleep 10; echo &quot;Child process terminated&quot;) &amp;amp;
  done

  # Exit without `wait` command
  # to make child processes to be zombie-processes
  echo &quot;* Parent process terminated&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Bash에서는 명령어를 괄호로 감싸주면 subshell(Child processes)로 실행됩니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;실행할 명령어 뒤에 &lt;code&gt;&amp;amp;&lt;/code&gt;를 붙여주면 background로 실행됩니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;여기서 Background에서 실행된 자식 프로세스들이 고아 프로세스가 되지 않도록 하기 위해서는 &lt;code&gt;wait&lt;/code&gt; 명령어 추가가 필요합니다. 하지만 고의로 생략합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;vhdl&quot;&gt;&lt;code&gt;$ bash make-orphans.sh
* Parent process terminated
I'm a child
I'm a child
I'm a child
Child process terminated
Child process terminated
Child process terminated&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;부모 프로세스가 종료되고 약 10초 이후 자식 프로세스들이 종료되는 것을 확인할 수 있습니다. stdout 이 출력되는 시간은 약간씩 달라질 수 있으나, 어쨌든 부모 프로세스가 자식 프로세스보다 더 빨리 종료되도록 했으니, 자식 프로세스들은 앞서 말했던 &quot;고아 프로세스&quot;가 되어야겠죠?&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그럼 이번엔 부모 프로세스가 종료된 직후 바로 &lt;code&gt;ps&lt;/code&gt; 커맨드를 활용해서 실행 중인 자식 프로세스들을 확인해봅시다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;bash make-orphans.sh; ps -ef | grep bash&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;1.png&quot; data-origin-width=&quot;1144&quot; data-origin-height=&quot;506&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/q0PFt/btqTtqGeMrb/IfRiEsyGh2kIzrfZitV4Yk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/q0PFt/btqTtqGeMrb/IfRiEsyGh2kIzrfZitV4Yk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/q0PFt/btqTtqGeMrb/IfRiEsyGh2kIzrfZitV4Yk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fq0PFt%2FbtqTtqGeMrb%2FIfRiEsyGh2kIzrfZitV4Yk%2Fimg.png&quot; data-filename=&quot;1.png&quot; data-origin-width=&quot;1144&quot; data-origin-height=&quot;506&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;이상하네요.&lt;/p&gt;
&lt;p&gt;고아 프로세스가 될 것으로 예상했던 자식 프로세스들의 PPID(부모 프로세스 아이디)가 &lt;code&gt;1&lt;/code&gt;인 것을 확인하실 수 있습니다. pid=1인 init process(여기선 &lt;code&gt;systemd&lt;/code&gt;)가 자식 프로세스들의 부모로 재할당 되었습니다.&lt;/p&gt;
&lt;h2&gt;3. 고아 프로세스를 거두어준 init process(pid=1)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;일반적으로 &lt;b&gt;Linux kernel에서는 부모 프로세스가 먼저 종료된 고아 프로세스(Orphan process)의 부모를 pid=1, 즉 init 프로세스로 재할당 해줍니다.&lt;/b&gt; (&lt;b&gt;리눅스 배포판별로 조금씩 다를 수 있다고 합니다만 일반적으로 그렇습니다.)&lt;/b&gt;
&lt;ul&gt;
&lt;li&gt;이러한 원리로, SysV Unix 체계에서는 daemon을 실행할 때 프로세스를 forking 하고 부모 프로세스를 종료하여 고아 프로세스로 만들고 init process가 부모 프로세스로 재할당되도록 하여 프로세스를 데몬화(Deamonize)합니다. (실제로는 세션으로부터 완전히 독립시키기 위해 Double forking 을 수행합니다)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;여기서 다시 자식 프로세스들이 종료된 이후에 다시 &lt;code&gt;ps&lt;/code&gt; 커맨드를 이용하여 확인해보면, 좀비 프로세스가 되었어야 할 녀석들이 좀비 상태로 남지 않고 사라진 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;2.png&quot; data-origin-width=&quot;1150&quot; data-origin-height=&quot;310&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dblCM3/btqTDJRGLAY/9Ab76ZA1jUkYhvBYTihCrk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dblCM3/btqTDJRGLAY/9Ab76ZA1jUkYhvBYTihCrk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dblCM3/btqTDJRGLAY/9Ab76ZA1jUkYhvBYTihCrk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdblCM3%2FbtqTDJRGLAY%2F9Ab76ZA1jUkYhvBYTihCrk%2Fimg.png&quot; data-filename=&quot;2.png&quot; data-origin-width=&quot;1150&quot; data-origin-height=&quot;310&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;왜 일까요?&lt;/p&gt;
&lt;h2&gt;4. &lt;code&gt;init&lt;/code&gt; process?&lt;/h2&gt;
&lt;p&gt;Unix 기반 OS에서 &lt;code&gt;init&lt;/code&gt; 프로세스는 &quot;부팅 시 최초로 실행되는 프로세스(pid=1)&quot;로 많이 알려져 있습니다. pid=1로 실행되면서 모든 프로세스의 최종 부모 프로세스 역할을 합니다.&lt;/p&gt;
&lt;p&gt;또한 익히 알고 계시는 &lt;code&gt;systemd&lt;/code&gt;, &lt;code&gt;upstart&lt;/code&gt;, 그리고 전통적으로는 &lt;code&gt;SysV init&lt;/code&gt;과 같은 init system 들이 &lt;code&gt;init&lt;/code&gt; 프로세스로서 사용되고 있습니다. (&lt;code&gt;systemd&lt;/code&gt;는 여러 가지 역할을 하지만, 각 init system에 대한 특징과 히스토리들은 여기서 다루지 않겠습니다.)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;3.png&quot; data-origin-width=&quot;1198&quot; data-origin-height=&quot;318&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLoAb0/btqTF4nqMDY/AXGQwcpij5AZnhf8kwOSSk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLoAb0/btqTF4nqMDY/AXGQwcpij5AZnhf8kwOSSk/img.png&quot; data-alt=&quot;Ubuntu 16.04에서 확인해보면&amp;amp;amp;nbsp; /sbin/init &amp;amp;amp;nbsp;이&amp;amp;amp;nbsp; systemd 의 symlink인 것을 볼 수 있습니다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLoAb0/btqTF4nqMDY/AXGQwcpij5AZnhf8kwOSSk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLoAb0%2FbtqTF4nqMDY%2FAXGQwcpij5AZnhf8kwOSSk%2Fimg.png&quot; data-filename=&quot;3.png&quot; data-origin-width=&quot;1198&quot; data-origin-height=&quot;318&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Ubuntu 16.04에서 확인해보면&amp;nbsp; /sbin/init &amp;nbsp;이&amp;nbsp; systemd 의 symlink인 것을 볼 수 있습니다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;잠시 딴 길로 새면, 이처럼 여러 init system이 등장하면서 우리가 쉽게 발견할 수 있는 차이는 daemon을 관리할 때 사용되는 명령어인데요.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SysV init, upstart - &lt;code&gt;/etc/init.d/[daemon] [start|stop|...]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;systemd - &lt;code&gt;systemctl [start|stop|...] [daemon]&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;물론 &lt;code&gt;service&lt;/code&gt;라는 커맨드를 사용해보신 적도 많으실 겁니다. (e.g. &lt;code&gt;service [daemon] [start|stop|...]&lt;/code&gt;)&lt;/p&gt;
&lt;p&gt;리눅스 배포판, 버전마다 모두 다르겠지만, 이전에는 SysV init의 wrapper 로서 역할을 하다가 현재는 systemd, sysV init, upstart을 아우르는 &lt;b&gt;wrapper&lt;/b&gt;로서 역할을 하고 있습니다. (예시 참고: &lt;a href=&quot;http://manpages.ubuntu.com/manpages/bionic/man8/service.8.html&quot;&gt;http://manpages.ubuntu.com/manpages/bionic/man8/service.8.html&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;다시 돌아와서, &lt;b&gt;init process의 또 한 가지 중요한 역할은 부모 프로세스를 잃어버린 고아 프로세스를 거두어 좀비 프로세스가 되지 않도록 정리해 주는 역할을 하는 것이죠&lt;/b&gt;. 이러한 역할을 &lt;code&gt;Reaping&lt;/code&gt;이라고도 합니다. 위의 예제에서 고아 프로세스가 종료된 이후 좀비 프로세스가 되지 않은 것도 init process의 &lt;code&gt;Reaping&lt;/code&gt;에 의한 것이라고 볼 수 있습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;추가적으로, init process 대신 userspace에서 서비스 관리를 수행하는 sub-reaper의 개념도 존재합니다만 여기선 다루지 않겠습니다. (대신 &lt;a href=&quot;https://unix.stackexchange.com/questions/250153/what-is-a-subreaper-process&quot;&gt;참고링크&lt;/a&gt;)&lt;/p&gt;
&lt;h2&gt;5. 여기까지 이야기한 내용을 정리해봅시다.&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Zombie process는 실제로는 종료된 프로세스이지만, Process Table에 여전히 남아있는 프로세스입니다.&lt;/li&gt;
&lt;li&gt;Orphan process는 부모 프로세스가 먼저 종료되어 고아가 된 프로세스입니다.&lt;/li&gt;
&lt;li&gt;Orphan process가 발생하면, 커널에 의해 부모 프로세스가 init process(pid=1)으로 할당됩니다.
&lt;ul&gt;
&lt;li&gt;Init process는 Orphan process를 거두어들이는 역할을 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;이러한 고아 프로세스들의 실행이 종료되고 Process Table에서 제거되려면 부모 프로세스에서 &lt;code&gt;wait&lt;/code&gt; system call을 호출해 주어야 하는데요. 이걸 해주지 않으면 zombie process로 남습니다.
&lt;ul&gt;
&lt;li&gt;그래서 &lt;code&gt;init&lt;/code&gt; 프로세스에서는 주기적으로 &lt;code&gt;wait&lt;/code&gt; 콜을 호출하여 좀비 프로세스를 정리해 주는 역할을 합니다. 이러한 동작을 일반적으로 &lt;code&gt;Reaping&lt;/code&gt;이라고 부릅니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이처럼 Unix 시스템에서 pid=1은 매우 중요한 의미를 지니고 있다고 볼 수 있습니다.&lt;/p&gt;
&lt;p&gt;여기까지 왔으면 대충 감을 잡으셨겠지만.. 그래도 하고자 하던 이야기는 계속해야겠지요?&lt;/p&gt;
&lt;h2&gt;6. Container에서의 pid=1에 대하여&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/architecture/containerized-lifecycle/design-develop-containerized-apps/common-container-design-principles&quot;&gt;Container는 기본적으로 단일 프로세스만을 실행하도록 만드는 것이 권장됩니다.&lt;/a&gt; 여러 가지 이유가 있겠지만 그중 하나로, Container에서 격리된 PID namespace에서 최초로 실행된 pid=1의 프로세스와 함께 컨테이너의 수명이 결정되기 때문이죠.&lt;/p&gt;
&lt;p&gt;만약 Container 내부에서 여러 개의 다른 역할을 하는 process 들이 실행되면, Container의 상태와 실행 중인 application들의 상태가 일치하지 않으므로, Container가 실행 중이더라도 내부의 모든 application들이 정상적으로 실행되고 있는 상태인지 보장할 수 없게 됩니다.&lt;/p&gt;
&lt;p&gt;결국 최초로 실행된 Process 실행/종료와 Container 자체의 실행/종료가 같은 의미를 가지는데요.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;어쨌든 이처럼 Container는 단일 프로세스를 실행하는 방식으로 설계되었고, Container 내부에서 실행되는 첫 번째 프로세스의 pid는 &lt;code&gt;1&lt;/code&gt; 이 됩니다.&lt;/p&gt;
&lt;p&gt;하지만 이전에 알아본 대로&amp;nbsp;&lt;b&gt;pid=1로 실행되는 프로세스는 이러한 Reaping 역할을 잘 수행할 수 있거나, 또는 애플리케이션에서 고아 프로세스가 발생하지 않도록 보장해야 합니다.&lt;/b&gt; 그렇지 않으면 의도치 않은 상황에서 좀비 프로세스가 발생하고 정리되지 않아 누적될 수 있겠죠.&lt;/p&gt;
&lt;p&gt;즉, Container에서 좀비 프로세스가 발생하지 않도록 보장하거나, reaping이 가능하도록 설계가 필요합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;그럼 Container에서 Zombie process reaping 은 어떻게 해야할까요?&lt;/h3&gt;
&lt;p&gt;몇 가지 방법을 생각해 볼 수 있습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;bash&lt;/code&gt;를 pid=1로 실행, Application process를 bash(pid=1)의 자식 프로세스로 실행&lt;/li&gt;
&lt;li&gt;Application에 Reaping 역할을 구현&lt;/li&gt;
&lt;li&gt;Container에서 &lt;code&gt;systemd&lt;/code&gt; 와 같은 기존의 init process 실행&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;첫 번째 방법에 대하여, &lt;code&gt;bash&lt;/code&gt;는 Orphan process를 처리할 수 있는 reaper로 가장 익히 알려진 프로그램입니다. 하지만 우리는 여기서 &lt;code&gt;docker stop&lt;/code&gt; 명령어를 생각해 볼 필요가 있습니다.&lt;/p&gt;
&lt;p&gt;Docker는 &lt;code&gt;docker stop&lt;/code&gt; 을 실행하는 경우 SIGTERM을 container의 처음 실행된 프로세스로 전송합니다. 하지만 &lt;code&gt;bash&lt;/code&gt;는 SIGTERM을 자식 프로세스로 전달하지 않기 때문에 graceful shut down 이 불가능해집니다.&lt;/p&gt;
&lt;p&gt;결국 pid=1은 자식 프로세스들에게 SIGTERM을 적절하게 전파해 주고 자식 프로세스들이 완전히 종료될 때까지 기다려 줄 수 있어야 합니다. 하지만 bash는 안타깝게도 SIGTERM signal을 자식 프로세스에 전파하지도 않고, 종료되길 기다려주지도 않습니다. bash의 자식 프로세스들은 결국 bash가 종료되면서 &lt;code&gt;SIGKILL&lt;/code&gt; signal에 의해 강제 종료 됩니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;두 번째 방법도 역시 Reaping 역할뿐만 아니라, 위와 같은 경우처럼 Signal handling을 잘 해줘야겠지요.&lt;/p&gt;
&lt;p&gt;세 번째 방법은 일반적인 경우 권장되진 않습니다. 이러한 init system의 일부 기능을 활용하기 위해, 기존의 init system(&lt;code&gt;SysV init&lt;/code&gt;, &lt;code&gt;systemd&lt;/code&gt;, &lt;code&gt;upstart&lt;/code&gt;, etc.)을 Container에서 실행하는 것은 닭 잡는 데 소 잡는 칼을 쓰는 격이죠.&lt;/p&gt;
&lt;h3&gt;Container 용 경량화된 init system의 등장&lt;/h3&gt;
&lt;p&gt;이런 히스토리에서, Container에서도 필요한 이런 기존의 init system의 중요한 역할들을 할 수 있는 경량화된 init system들이 등장하기 시작했습니다.&lt;/p&gt;
&lt;p&gt;그 예로, &lt;a href=&quot;https://github.com/Yelp/dumb-init&quot;&gt;Yelp/dumb-init&lt;/a&gt;, &lt;a href=&quot;https://github.com/krallin/tini&quot;&gt;krallin/tini&lt;/a&gt;, &lt;a href=&quot;https://github.com/phusion/baseimage-docker&quot;&gt;phusion/baseimage-docker&lt;/a&gt; 같은 것들이 있습니다. 여기서 &lt;code&gt;tini&lt;/code&gt; 의 경우 Docker 1.13.0 부터는 &lt;code&gt;--init&lt;/code&gt; option으로 사용될 수 있도록 추가되었습니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.docker.com/engine/release-notes/prior-releases/#runtime-1&quot;&gt;https://docs.docker.com/engine/release-notes/prior-releases/#runtime-1&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/moby/moby/pull/26061&quot;&gt;https://github.com/moby/moby/pull/26061&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;7. Kubernetes의 PID namespace sharing&lt;/h2&gt;
&lt;p&gt;Google에서는 Kubernetes에서 Zombie process reaping을 위해 &lt;a href=&quot;https://kubernetes.io/docs/tasks/configure-pod-container/share-process-namespace/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;PID namespace sharing&lt;/a&gt;(&lt;code&gt;--docker-disable-shared-pid=false&lt;/code&gt;)을 &lt;a href=&quot;https://cloud.google.com/solutions/best-practices-for-building-containers#solution_2_enable_process_namespace_sharing_in_kubernetes&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;제안&lt;/a&gt;합니다.&lt;/p&gt;
&lt;p&gt;PID namespace sharing을 하게 되면, 같은 Pod의 컨테이너들은 하나의 PID namespace를 공유하게 되고, 기존에 Kubernetes에서 Network namespace를 유지하던 &lt;code&gt;pause&lt;/code&gt; 컨테이너의 프로세스가 pid=1로서 Reaping을 담당하게 됩니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;위 옵션은, Kubernetes 1.7에서 기본적으로 해당 옵션이 활성화되어 있지만, 1.8 버전부터는 다시 비활성화되었기 때문에 직접 활성화해야 합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;혹시 궁금하신 분들을 위해... 왜 옵션의 기본값 rollback이 되었는지에 대한 배경은 아래 링크에서 확인하실 수 있습니다. (요약해보면... 이러한 옵션의 기본적인 활성화는 Container에서 &lt;code&gt;systemd&lt;/code&gt; 와 같은 init system에 의존하는 일부 애플리케이션들과 충돌을 일으키고, 여러 가지 측면에서 좀 더 고려될 필요가 있다는 판단하에 일단 1.8에서 다시 되돌린 것으로 보입니다.)&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/kubernetes/kubernetes/issues/48937&quot;&gt;https://github.com/kubernetes/kubernetes/issues/48937&lt;/a&gt; (대략 &lt;a href=&quot;https://github.com/kubernetes/kubernetes/issues/48937#issuecomment-323509979&quot;&gt;여기&lt;/a&gt;쯤부터 보시면 될 것 같습니다.)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;다시 돌아와서, &lt;span data-token-index=&quot;1&quot; data-reactroot=&quot;&quot;&gt;pause&lt;/span&gt; process의 코드의 &lt;span data-token-index=&quot;3&quot; data-reactroot=&quot;&quot;&gt;sigreap&lt;/span&gt; function을 한번 살펴보면 &lt;span data-token-index=&quot;5&quot; data-reactroot=&quot;&quot;&gt;waitpid&lt;/span&gt; syscall을 통해 Reaping을 수행하도록 구현된 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/kubernetes/kubernetes/blob/68108c70e29a74bb455ab63adeb5725a37e94e4f/build/pause/linux/pause.c#L37-L40&quot;&gt;https://github.com/kubernetes/kubernetes/blob/68108c70e29a74bb455ab63adeb5725a37e94e4f/build/pause/linux/pause.c#L37-L40&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;4.png&quot; data-origin-width=&quot;1310&quot; data-origin-height=&quot;1286&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HFv0a/btqTF3hKmH6/e7ygfiRgJBkhcCj8WGrs11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HFv0a/btqTF3hKmH6/e7ygfiRgJBkhcCj8WGrs11/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HFv0a/btqTF3hKmH6/e7ygfiRgJBkhcCj8WGrs11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHFv0a%2FbtqTF3hKmH6%2Fe7ygfiRgJBkhcCj8WGrs11%2Fimg.png&quot; data-filename=&quot;4.png&quot; data-origin-width=&quot;1310&quot; data-origin-height=&quot;1286&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;부록)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;위 코드를 보면 &lt;code&gt;pause&lt;/code&gt; process는 SIGTERM을 받으면, pid=1이지만 같은 PID namespace에 있는 자식 프로세스들에게 SIGTERM 전달을 해주지 않습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이유는 Pod의 Lifecycle에 있습니다.&lt;/p&gt;
&lt;p&gt;Kubernetes는 Container보다 pod이라는 추상화된 상태로 실행 단위를 정의하기 때문에, Pod 내부의 Container 종료도 역시 Pod 단위로 이루어지는데요.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-termination&quot;&gt;https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-termination&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;그러니까 pod termination의 동작을 살펴보면,&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;각 노드마다 실행되는 &lt;code&gt;kubelet&lt;/code&gt;이 먼저 해당 &lt;code&gt;pod&lt;/code&gt;에 있는 각각의 container에 먼저 SIGTERM을 보냅니다. (Graceful Shutdown 시도)&lt;/li&gt;
&lt;li&gt;이때 미리 정의해두었던 &lt;code&gt;terminationGracePeriodSeconds&lt;/code&gt; 유예시간(기본 30초) 이후에도 컨테이너가 종료되지 않으면 &lt;code&gt;SIGKILL&lt;/code&gt;로 강제 종료&lt;/li&gt;
&lt;li&gt;마지막에 hidden container인 &lt;code&gt;pause&lt;/code&gt; 컨테이너를 종료하게 됩니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;kubelet&lt;/code&gt;이 pod에 존재하는 컨테이너들에 각각 SIGTERM을 먼저 보내서 모두 종료하고 마지막으로 &lt;code&gt;pause&lt;/code&gt; 와 같은 hidden container를 종료하기 때문에, pause 컨테이너가 SIGTERM을 전파해 줄 필요가 없는 것이죠.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;또, 위 k8s 문서에서는 &lt;code&gt;send a TERM signal to process 1 inside each container&lt;/code&gt;라고 서술하고 있는데, PID namespace가 공유된 경우엔 같은 Pod에서 pid=1은 항상 &lt;code&gt;pause&lt;/code&gt; process 일 텐데 pod lifecycle이 어떻게 동작할지 궁금하네요.&lt;/p&gt;
&lt;p&gt;확인해보니 실제로는 docker client가 각각의 Container에 stop 명령어를 보내는 것과 똑같이 동작합니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/kubernetes/kubernetes/blob/60cb99909fd62d5edc37de61ab9a39b217052ec8/pkg/kubelet/dockershim/docker_container.go#L305-L312&quot;&gt;https://github.com/kubernetes/kubernetes/blob/60cb99909fd62d5edc37de61ab9a39b217052ec8/pkg/kubelet/dockershim/docker_container.go#L305-L312&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그리고 docker client는 stop 핸들러가 동작하면 각각 Container의 &lt;b&gt;&quot;main process&quot;&lt;/b&gt;에 SIGTERM을 보내고, 유예시간 이후에 SIGKILL로 강제 종료를 하게 됩니다. 실제로 &lt;code&gt;docker stop&lt;/code&gt; 명령어도 다음과 같이 설명하고 있네요.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;The main process inside the container will receive &lt;code&gt;SIGTERM&lt;/code&gt;, and after a grace period, &lt;code&gt;SIGKILL&lt;/code&gt;.&lt;br /&gt;For example uses of this command, refer to the &lt;a href=&quot;https://docs.docker.com/engine/reference/commandline/stop/#examples&quot;&gt;examples section&lt;/a&gt; below.&lt;br /&gt;&lt;a href=&quot;https://docs.docker.com/engine/reference/commandline/stop/&quot;&gt;https://docs.docker.com/engine/reference/commandline/stop/&lt;/a&gt;&lt;/blockquote&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Docker를 Container runtime에서 PID namespace sharing 을 사용하는 겅우에도 pid namespace를 공유하더라도 각 컨테이너의 종료는 pod lifecycle에 따라 잘 동작하겠지요.&lt;/p&gt;
&lt;h2&gt;8. 최종정리&lt;/h2&gt;
&lt;p&gt;중간 정리(&lt;code&gt;5. 여기까지 이야기한 내용을 정리해봅시다.&lt;/code&gt;)까지는 Zombie process, Orphan process, init system, Zombie process reaping에 대해 자세히 설명하였습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그리고 Container에서의 Zombie process reaping에 대한 내용을 다뤘는데요. 정리해보면...&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Container에서는 최초로 실행되는 프로세스가 pid=1이 됨
&lt;ul&gt;
&lt;li&gt;Container 내부에서 Zombie process가 발생하지 않을 것이란 보장이 필요&lt;/li&gt;
&lt;li&gt;그렇지 않으면, Zombie process reaping 문제가 발생할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Container에서의 Zombie process reaping 방법
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;bash를 entrypoint로
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;다만, SIGTERM을 자식 프로세스에 전달해 주지 않기 때문에, Graceful shutdown이 불가능(모든 자식 프로세스들은 강제 종료됨)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Application에 직접 reaping 을 구현&lt;/li&gt;
&lt;li&gt;기존 init system 사용(&lt;code&gt;SysV init&lt;/code&gt;, &lt;code&gt;systemd&lt;/code&gt;, &lt;code&gt;upstart&lt;/code&gt; ...)
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;단순 Zombie process reaping을 위해 전체 시스템 초기화 용도의 init system들을 가져다 쓰는 것은 권장되지 않음.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;이런 문제들로 인해 Container 용도의 경량화된 init system들이 등장
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;a style=&quot;letter-spacing: 0px;&quot; href=&quot;https://github.com/Yelp/dumb-init&quot; data-token-index=&quot;0&quot; data-reactroot=&quot;&quot;&gt;Yelp/dumb-init&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;letter-spacing: 0px;&quot; href=&quot;https://github.com/krallin/tini&quot; data-token-index=&quot;2&quot; data-reactroot=&quot;&quot;&gt;krallin/tini&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;letter-spacing: 0px;&quot; href=&quot;https://github.com/phusion/baseimage-docker&quot; data-token-index=&quot;4&quot; data-reactroot=&quot;&quot;&gt;phusion/baseimage-docker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tini&lt;/code&gt;의 경우 Docker 1.13.0 부터 &lt;code&gt;--init&lt;/code&gt; option으로 사용될 수 있도록 추가됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Kubernetes 에서의 PID namespace sharing
&lt;ul&gt;
&lt;li&gt;Google에서는 Kubernetes에서 Zombie process reaping을 위해 &lt;a href=&quot;https://cloud.google.com/solutions/best-practices-for-building-containers#solution_2_enable_process_namespace_sharing_in_kubernetes&quot;&gt;PID namespace sharing&lt;/a&gt;(&lt;code&gt;--docker-disable-shared-pid=false&lt;/code&gt;)을 제안&lt;/li&gt;
&lt;li&gt;k8s 1.7에선 기본적으로 활성화, 하지만 1.8에선 다시 비활성화됨&lt;/li&gt;
&lt;li&gt;k8s pod의 hidden container인 &lt;code&gt;pause&lt;/code&gt; 컨테이너의 프로세스가 pid=1로서 reaping을 담당&lt;/li&gt;
&lt;li&gt;(부록) &lt;code&gt;kubelet&lt;/code&gt;이 pod 종료 시 미리 정의된 pod lifecycle 대로 내부의 각 container들을 먼저 종료한 뒤 마지막으로 &lt;code&gt;pause&lt;/code&gt; 컨테이너를 종료하기 때문에, &lt;code&gt;pause&lt;/code&gt; 컨테이너는 SIGTERM 전파를 해줄 필요가 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;9. 참고한 글(함께 읽어보면 좋은 글)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://cloud.google.com/solutions/best-practices-for-building-containers&quot;&gt;https://cloud.google.com/solutions/best-practices-for-building-containers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.phusion.nl/2015/01/20/docker-and-the-pid-1-zombie-reaping-problem/&quot;&gt;https://blog.phusion.nl/2015/01/20/docker-and-the-pid-1-zombie-reaping-problem/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.joinc.co.kr/w/Site/system_programing/process/Zombie&quot;&gt;https://www.joinc.co.kr/w/Site/system_programing/process/Zombie&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.ianlewis.org/en/almighty-pause-container&quot;&gt;https://www.ianlewis.org/en/almighty-pause-container&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/config/containers/multi-service_container/&quot;&gt;https://docs.docker.com/config/containers/multi-service_container/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;다소 장황하게 설명한 것 같은데, 끝까지 읽어주신 분들께 감사드립니다. ( _ _)&lt;/b&gt;&lt;/p&gt;</description>
      <category>Tech</category>
      <category>container</category>
      <category>docker</category>
      <category>INIT</category>
      <category>K8S</category>
      <category>Kubernetes</category>
      <category>PAUSE</category>
      <category>pid namespace</category>
      <category>Reaping</category>
      <category>waitpid</category>
      <category>zombie process</category>
      <author>Devin Jeon</author>
      <guid isPermaLink="true">https://devinjeon.tistory.com/4</guid>
      <comments>https://devinjeon.tistory.com/4#entry4comment</comments>
      <pubDate>Thu, 14 Jan 2021 22:33:09 +0900</pubDate>
    </item>
  </channel>
</rss>