<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>ParanBlog.</title>
    <link>https://pscr.tistory.com/</link>
    <description>파랗게 파랗게 물들었네.</description>
    <language>ko</language>
    <pubDate>Tue, 2 Jun 2026 10:15:54 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>파란화면</managingEditor>
    <image>
      <title>ParanBlog.</title>
      <url>https://t1.daumcdn.net/cfile/tistory/25659E47582ED5AF2D</url>
      <link>https://pscr.tistory.com</link>
    </image>
    <item>
      <title>일본 특색 인터넷과 PPPoE, IPoE, v6플러스 ~IPv6을 쓰면 인터넷이 빨라짐~</title>
      <link>https://pscr.tistory.com/115</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h2 data-ke-size=&quot;size26&quot;&gt;후렛츠망과 일본 특색 PPPoE&lt;/h2&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;현 세대 NTT의 백본망은 &lt;b&gt;NGN&lt;/b&gt;(Next Generation Network)이라고 합니다. Full IPv6 기반의 네트워크이고, 이것을 이용해 플레츠(FLET'S, フレッツ 후렛츠)라는 광인터넷 서비스를 제공하기 때문에 흔히 &lt;b&gt;후렛츠망&lt;/b&gt;이라고도 부릅니다.&lt;br&gt;하지만 NGN은 그 자체로는 인터넷에 연결되어 있지 않은 폐쇄망입니다. NTT법에 따라 NTT동/서는 인터넷 연결서비스를 직접 제공하면 안 되고, 후렛츠망과 다크 파이버(사용되지 않고 있는 예비 광케이블 용량)를 타 통신사에 개방할 것이 의무화되어 있기 때문입니다. 계열사인 도코모나 NTT커뮤니케이션즈가 인터넷 연결서비스를 제공하고, NTT데이터는 세계구급 규모의 IX를 운영하고 있는 걸 보면 솔직히 눈 가리고 아웅이 아닌가 싶긴 한데요. 아무튼 이 때문에 일본에서는 &lt;b&gt;ISP&lt;/b&gt;=&lt;b&gt;프로바이더&lt;/b&gt;(プロバイダー)랑 &lt;b&gt;회선제공자&lt;/b&gt;가 별개의 개체로서 존재한다는 것입니다.&lt;br&gt;과거에는 IPv6 폐쇄망인 NGN을 거쳐 ISP에 연결하기 위해 보통 &lt;b&gt;PPPoE 터널&lt;/b&gt;을 사용했습니다. PPPoE나 그 모태가 되는 PPP 등은 과거 전세계에서 사용되었던 것이니 우리에게도 비교적 친숙한 개념이라고 할 수 있겠지요.&lt;br&gt;그리고, NGN의 끝단에 위치한 ISP의 PPPoE 서버이자, 인터넷을 향한 게이트웨이 역할을 하는 서버를 &lt;b&gt;망종단장치&lt;/b&gt;(網終端装置 Network Termination Equipment; NTE)라고 합니다.&lt;br&gt;※ 일본에서는 광랜 사용자 가정 내에 설치되는 ONU(Optical Network Unit)를 광회선 종단장치(光回線終端装置)나 가입자 망종단장치(加入者網終端装置)라고 부르기도 하는데, 당연히 이거랑은 전혀 다른 물건입니다.&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1108&quot; data-origin-height=&quot;522&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/szp9j/btsOCgF8NUx/WfgCAfjKBeJuMRE0EwNaw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/szp9j/btsOCgF8NUx/WfgCAfjKBeJuMRE0EwNaw0/img.png&quot; data-alt=&quot;자료: 총무성&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/szp9j/btsOCgF8NUx/WfgCAfjKBeJuMRE0EwNaw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fszp9j%2FbtsOCgF8NUx%2FWfgCAfjKBeJuMRE0EwNaw0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1108&quot; height=&quot;522&quot; data-origin-width=&quot;1108&quot; data-origin-height=&quot;522&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;자료: 총무성&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br&gt;&lt;br&gt;하지만 보통 ISP의 망종단장비는 빈약해서 사람이 몰리는 시간대만 되면 느려지는 현상이 발생했습니다. 일본에서 경험적으로 'IPv6을 쓰면 인터넷이 빨라진다'는 괴소문이 널리 퍼져 있는 데에는 이러한 이유가 있습니다 - 그 괴소문이 사실이기 때문입니다.&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h2 data-ke-size=&quot;size26&quot;&gt;일본 특색 IPv6과 VNE&lt;/h2&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br&gt;IPoE의 원래 뜻은 IP over Ethernet- 그러니까 &quot;이더넷 위에서 IP쓰기&quot;입니다. 너무나 당연한 얘기를 하는 게 아닌가 생각하실 수도 있지만, 이건 후렛츠망 하에서 이용되었던 IPv4/PPPoE와 대조를 위해 만들어진 표현이라고 생각하시면 됩니다.&lt;br&gt;여기서 &lt;b&gt;VNE&lt;/b&gt;라는 새로운 개념이 등장합니다. VNE는 Virtual Network Enabler의 약자로, ISP를 대신하여 NGN망의 끝단에서 IPv6 인터넷으로 향하는 게이트웨이를 운영하는 업체를 가리킵니다. 어원적으로는, 원래 이동통신업계에서 MVNO 사업자에게 OSS(Operation Support System)과 BSS(Business Support System) 등의 서비스와 솔루션을 제공하는 업체를 가리키는 단어인 &quot;MVNE(Mobile Virtual Network Enabler)&quot;에서 맨 앞의 &quot;Mobile&quot; 부분만 떼어 낸 것입니다.&lt;br&gt;MVNO 사업자가 실제 망을 가지고 있지 않고 MNO의 설비와 MVNE의 시스템을 빌려 쓰는 것처럼, IPoE 환경에서 ISP는 NTT의 설비와 VNE의 게이트웨이를 빌려 쓰는 것뿐이며 실제&amp;nbsp;인터넷&amp;nbsp;연결&amp;nbsp;서비스를&amp;nbsp;제공하지&amp;nbsp;않습니다.&lt;br&gt;일본에서 IPoE 환경을 이용해 인터넷에 연결하면 global IPv6 주소가 할당됩니다. 이것은 NGN 내부에서 사용되는 private IPv6주소와는 다른 public IPv6 주소로, VNE사에서 보유하고 있는 IPv6 주소 풀 중에서 하나가 부여됩니다.&lt;br&gt;IPv6/IPoE환경에서 IPv6호스트로 패킷을 전송하는 경우, IPv4/PPPoE에서와는 달리 패킷은 별도의 캡슐화를 거치지 않고, 그대로 NGN망으로 홀러갑니다. NGN의 라우터는 패킷의 sender address를 보고, 해당 주소가 어느 VNE사의 것인지를 확인하여 VNE사가 보유한 NGN-인터넷 게이트웨이로 패킷을 라우팅합니다(policy based routing).&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1914&quot; data-origin-height=&quot;862&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cX4v25/btsOBCDaHUH/ulIJ4AqQ0uAZnbwSGWd7lk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cX4v25/btsOBCDaHUH/ulIJ4AqQ0uAZnbwSGWd7lk/img.png&quot; data-alt=&quot;&amp;amp;lt;徹底解説 v6プラス&amp;amp;gt;에서 인용&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cX4v25/btsOBCDaHUH/ulIJ4AqQ0uAZnbwSGWd7lk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcX4v25%2FbtsOBCDaHUH%2FulIJ4AqQ0uAZnbwSGWd7lk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1914&quot; height=&quot;862&quot; data-origin-width=&quot;1914&quot; data-origin-height=&quot;862&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;&amp;lt;徹底解説 v6プラス&amp;gt;에서 인용&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IPv6/IPoE 환경에서는 IPv4/PPPoE와는 달리 encapsulation-decapsulation 연산으로 인한 오버헤드가 없고, 낡은 망종단장비 대신 대용량의 VNE 게이트웨이로 바로 가기 때문에 더 빠른 속도를 실현할 수 있는 것입니다.&lt;br&gt;지금까지&amp;nbsp;설명한&amp;nbsp;내용을&amp;nbsp;보면&amp;nbsp;아시겠지만&amp;nbsp;일본식&amp;nbsp;IPoE의&amp;nbsp;경우&amp;nbsp;정확히는&amp;nbsp;IPv6oE라고&amp;nbsp;하는&amp;nbsp;게&amp;nbsp;맞을&amp;nbsp;것입니다.&amp;nbsp;사용자&amp;nbsp;컴퓨터에서&amp;nbsp;NGN을&amp;nbsp;거쳐&amp;nbsp;VNE에&amp;nbsp;도착하기까지&amp;nbsp;전&amp;nbsp;구간이&amp;nbsp;IPv6이니까요.&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h2 data-ke-size=&quot;size26&quot;&gt;IPoE에서 IPv4 사용하기: 일본 특색 MAP-E&lt;/h2&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 IPv4 통신은 어떻게 하느냐? 두가지 방식이 있습니다.&lt;/p&gt;&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;&lt;li&gt;IPv4는 PPPoE로 IPv6은 IPoE로 통신한다&lt;/li&gt;&lt;li&gt;IPoE만 사용하고, IPv4패킷을 보낼 일이 있으면 IPv6위로 캡슐화해서 보낸다&lt;/li&gt;&lt;/ol&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;이 중 2번 방법을 위해 가장 보편적으로 사용되는 방식이 MAP-E이고,&amp;nbsp; MAP-E를 이용한 IPv4서비스에 대해 일본 최대 규모의 VNE사인 JPIX(구 JPNE)에서 붙인 서비스명이 v6플러스(v6プラス)입니다.&lt;br&gt;MAP-E에서는 global IPv6주소와 사전할당된 몇 가지 값에 따라 특정 IPv6주소의 사용자가 사용할 수 있는 global IPv4주소와 포트범위가 정해지게 됩니다. 고객 측에 설치된 CPE는 MAP Rule에 따라 사용자에게 할당된 IPv4 집피와 포트번호를 계산하여 가지고 있습니다. 이 때 MAP rule은 DHCPv6-PD나 Router Advertisement에 의해 가정의 CPE에 배포됩니다.&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1422&quot; data-origin-height=&quot;1504&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yAm7S/btsOBZLDQ70/eaFYE8f8zSgmgQk7SGR551/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yAm7S/btsOBZLDQ70/eaFYE8f8zSgmgQk7SGR551/img.png&quot; data-alt=&quot;&amp;amp;lt;徹底解説 v6プラス&amp;amp;gt;에서 인용&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yAm7S/btsOBZLDQ70/eaFYE8f8zSgmgQk7SGR551/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyAm7S%2FbtsOBZLDQ70%2FeaFYE8f8zSgmgQk7SGR551%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1422&quot; height=&quot;1504&quot; data-origin-width=&quot;1422&quot; data-origin-height=&quot;1504&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;&amp;lt;徹底解説 v6プラス&amp;gt;에서 인용&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IPv4 네트워크와 통신을 할 때, 고객 측 CPE는 IPv4패킷을 IPv6 위에서 캡슐화하여 NGN으로 던지게 됩니다. NGN을 넘어 VNE측 게이트웨이에 도착하면 게이트웨이는 캡슐에 담긴 IPv4패킷의 source 주소와 허용된 포트 범위가 허용된 값과 일치하는지 확인하고, 일치한다면 그대로 외부 인터넷으로 던지는 것입니다.&lt;br&gt;이러한 구조를 통해 ISP...가 아니라 VNE의 입장에서는, 일반적인 CGNAT을 사용했을 때와는 달리 NAT을 위한 상태관리를 해 줄 필요가 없다는 장점이 있습니다. 하지만 엔드유저 입장에서는 대충 랜덤 포트 범위를 포트포워딩으로 열 수 있는 CGNAT64처럼 동작한다고 생각하면 되겠습니다.&lt;br&gt;&lt;br&gt;MAP-E는&amp;nbsp;IETF에&amp;nbsp;의해&amp;nbsp;RFC&amp;nbsp;7597로&amp;nbsp;표준화되어&amp;nbsp;있습니다만&amp;nbsp;실제&amp;nbsp;NTT에서&amp;nbsp;사용하는&amp;nbsp;MAP-E는&amp;nbsp;일본&amp;nbsp;특색&amp;nbsp;MAP-E...가&amp;nbsp;아니라&amp;nbsp;표준&amp;nbsp;확정&amp;nbsp;이전의&amp;nbsp;draft-ietf-softwire-map입니다.&amp;nbsp;(draft버전이&amp;nbsp;00인지&amp;nbsp;03인지는&amp;nbsp;확실하게&amp;nbsp;컨펌된&amp;nbsp;바가&amp;nbsp;없습니다)&lt;/p&gt;</description>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/115</guid>
      <comments>https://pscr.tistory.com/115#entry115comment</comments>
      <pubDate>Sat, 14 Jun 2025 22:19:02 +0900</pubDate>
    </item>
    <item>
      <title>고도인재 관련 규정 뭉치</title>
      <link>https://pscr.tistory.com/113</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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;원문은 세로쓰기입니다. 가로쓰기로 변환할 경우 &quot;상단 란&quot;은 맨 왼쪽 칸, &quot;하단 란&quot;은 가로쓰기로 변환할 경우 맨 오른쪽 칸을 말합니다.&lt;/li&gt;
&lt;li&gt;&quot;일본어를 전공하여 외국의 대학을 졸업하거나, 일상적인 장면에서 사용되는 일본어에 더해, 논리적으로 다소 복잡한 일본어를 포함한 폭넓은 장면에서 사용되는 일본어를 이해할 수 있는 능력을 가지고 있음을 시험에 의해 증명받았을 것.&quot;은 JLPT N1, BJT 480점 이상을 말합니다.&lt;/li&gt;
&lt;li&gt;&quot;일상적인 장면에서 사용되는 일본어를 이해할 수 있을 뿐만 아니라, 논리적으로 다소 복잡한 일본어를 포함한 폭넓은 장면에서 사용되는 일본어를 어느 정도 이해할 수 있는 능력을 가지고 있음을 시험에 의해 증명받았을 것&quot;은 JLPT N2, BJT 400점 이상을 말합니다.&lt;/li&gt;
&lt;li&gt;일본의 법령이므로, &quot;우리나라&quot;(원문은 本邦 또는 我が国)라는 표현은 일본을 말합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;출입국관리 및 난민인정법(昭和 26년 정령 제319호) (발췌)&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;별표 제 1&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;(생략)&lt;/li&gt;
&lt;li&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;width: 71px;&quot;&gt;재류 자격&lt;/th&gt;
&lt;th style=&quot;width: 783px;&quot;&gt;우리나라 내에서 할 수 있는 활동&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 71px;&quot;&gt;고도전문직&lt;/td&gt;
&lt;td style=&quot;width: 783px;&quot;&gt;1. 고도의 전문적인 능력을 가진 인재로서 법무성령으로 정하는 기준에 적합한 자가 행하는 다음 イ부터 ハ까지의 어느 하나에 해당하는 활동으로서, 우리나라의 학술연구 또는 경제의 발전에 기여할 것으로 예상되는 것&lt;br /&gt;&lt;br /&gt;イ 법무대신이 지정하는 우리나라 내 공・사(公私)의 기관과의 계약에 기초하여 연구, 연구의 지도 혹은 교육을 하는 활동 또는 해당 활동과 함께 해당 활동과 관련된 사업을 스스로 경영하거나 해당 기관 이외의 우리나라 내 공・사의 기관과의 계약에 기초하여 연구, 연구의 지도 혹은 교육을 하는 활동&lt;br /&gt;&lt;br /&gt;ロ 법무대신이 지정하는 우리나라 내 공・사의 기관과의 계약에 기초하여 자연과학 혹은 인문과학 분야에 속하는 지식 혹은 기술을 요하는 업무에 종사하는 활동 또는 해당 활동과 함께 해당 활동과 관련된 사업을 스스로 경영하는 활동&lt;br /&gt;&lt;br /&gt;ハ 법무대신이 지정하는 우리나라 내 공・사의 기관에서 무역 기타 사업의 경영을 하거나 해당 사업의 관리에 종사하는 활동 또는 해당 활동과 함께 해당 활동과 관련된 사업을 스스로 경영하는 활동&lt;br /&gt;&lt;br /&gt;2. 전호에 열거된 활동을 행한 자로서, 그 체류가 우리나라의 이익에 이바지하는 것으로서 법무성령으로 정하는 기준에 적합한 자가 행하는 다음에 열거하는 활동&lt;br /&gt;&lt;br /&gt;イ 우리나라 내 공・사의 기관과의 계약에 기초하여 연구, 연구의 지도 또는 교육을 하는 활동&lt;br /&gt;&lt;br /&gt;ロ 우리나라 내 공・사의 기관과의 계약에 기초하여 자연과학 또는 인문과학 분야에 속하는 지식 또는 기술을 요하는 업무에 종사하는 활동&lt;br /&gt;&lt;br /&gt;ハ 우리나라 내 공・사의 기관에서 무역 기타 사업의 경영을 하거나 해당 사업의 관리에 종사하는 활동&lt;br /&gt;&lt;br /&gt;ニ イ부터 ハ까지의 어느 하나의 활동과 함께 행하는 일의 표의 교수 항목부터 보도 항목까지의 하단에 열거된 활동 또는 이 표의 법률&amp;middot;회계업무 항목, 의료 항목, 교육 항목, 기술&amp;middot;인문지식&amp;middot;국제업무 항목, 흥행 항목 혹은 기능 항목의 하단에 열거된 활동(イ부터 ハ까지의 어느 하나에 해당하는 활동을 제외함)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;출입국관리 및 난민인정법 별표 제1의 2의 표의 고도전문직 항목의 하단 란 기준을 정하는 성령(平成 26년 법무성령 제37호)&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://laws.e-gov.go.jp/law/426M60000010037&quot;&gt;令和 6년 6월 10일 시행&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;제1조&lt;/b&gt;. 출입국관리 및 난민인정법(이하 &quot;법&quot;이라 한다) 별표 제1의 2의 표의 고도전문직 항목의 하단 란 제1호의 기준은, 동호에 열거된 활동을 하는 외국인이 법 제3장 제1절 또는 제2절의 규정에 의한 상륙허가 증인 또는 허가(재류자격의 결정을 수반하는 것에 한한다), 법 제4장 제2절의 규정에 의한 허가, 법 제50조 제1항 또는 제61조의 5의 제1항의 규정에 의한 허가(이하 &quot;제1호 허가 등&quot;이라 한다)를 받는 시점에서 특별고도인재(특히 고도의 전문적인 능력을 갖는 인재로서 별도의 법무성령으로 정하는 기준에 적합한 자를 말한다. 이하 같다)일 것, 또는 다음 각 호의 어느 하나에 해당하는 것으로 한다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;법 별표 제1의 2의 표의 고도전문직 항목의 하단 란 제1호 イ에 열거된 활동을 하는 외국인으로서, 다음 표의 상단 란에 열거된 항목에 관한 동표의 중간 란에 열거된 기준(연수입 항목에 있어서는, 해당 시점에서의 해당 외국인의 연령이 30세 미만일 때는 동항의 イ부터 ト까지, 30세 이상 35세 미만일 때는 동항의 イ부터 ヘ까지, 35세 이상 40세 미만일 때는 동항의 イ부터 ホ까지, 40세 이상일 때는 동항의 イ부터 ハ까지에 열거된 기준)에 따라, 동표의 하단 란에 열거된 점수를 합계한 것이 70점 이상일 것.&lt;/li&gt;
&lt;/ol&gt;
&lt;table style=&quot;width: 853px;&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style4&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;width: 56px;&quot;&gt;항목&lt;/th&gt;
&lt;th style=&quot;width: 770px;&quot;&gt;기준&lt;/th&gt;
&lt;th style=&quot;width: 27px;&quot;&gt;점수&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 56px;&quot; rowspan=&quot;4&quot;&gt;학력&lt;/td&gt;
&lt;td style=&quot;width: 770px;&quot;&gt;イ 박사 학위를 가지고 있을 것.&lt;/td&gt;
&lt;td style=&quot;width: 27px;&quot;&gt;30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 770px;&quot;&gt;ロ 석사 학위 또는 전문직 학위(학위규칙(昭和 28년 문부성령 제9호) 제5조의 2에 규정된 전문직 학위를 말하며, 외국에서 수여된 이에 상당하는 학위를 포함한다. 이하 같다)를 가지고 있을 것(イ에 해당하는 경우를 제외한다).&lt;/td&gt;
&lt;td style=&quot;width: 27px;&quot;&gt;20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 770px;&quot;&gt;ハ 대학을 졸업하거나 이와 동등 이상의 교육을 받았을 것(イ 또는 ロ에 해당하는 경우를 제외한다).&lt;/td&gt;
&lt;td style=&quot;width: 27px;&quot;&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 770px;&quot;&gt;ニ 복수의 분야에서 박사 또는 석사 학위 또는 전문직 학위를 가지고 있을 것.&lt;/td&gt;
&lt;td style=&quot;width: 27px;&quot;&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 56px;&quot; rowspan=&quot;3&quot;&gt;직력&lt;/td&gt;
&lt;td style=&quot;width: 770px;&quot;&gt;イ 종사하는 연구, 연구의 지도 또는 교육에 대해 7년 이상의 실무 경험이 있을 것.&lt;/td&gt;
&lt;td style=&quot;width: 27px;&quot;&gt;15&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 770px;&quot;&gt;ロ 종사하는 연구, 연구의 지도 또는 교육에 대해 5년 이상 7년 미만의 실무 경험이 있을 것.&lt;/td&gt;
&lt;td style=&quot;width: 27px;&quot;&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 770px;&quot;&gt;ハ 종사하는 연구, 연구의 지도 또는 교육에 대해 3년 이상 5년 미만의 실무 경험이 있을 것.&lt;/td&gt;
&lt;td style=&quot;width: 27px;&quot;&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 56px;&quot; rowspan=&quot;7&quot;&gt;연수입&lt;/td&gt;
&lt;td style=&quot;width: 770px;&quot;&gt;イ 계약기관(계약의 상대방인 우리나라 공・사 기관을 말한다. 이하 같다) 및 외국소속기관(외국의 공・사 기관의 직원이 해당 기관에서 전근하여 계약기관에 받아들여지는 경우의 해당 외국의 공・사 기관을 말한다. 이하 이 호, 다음 호 및 다음 조 제1항 제1호 ロ에서 같다)에서 받는 보수의 연액 합계가 1,000만 엔 이상일 것.&lt;/td&gt;
&lt;td style=&quot;width: 27px;&quot;&gt;40&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 770px;&quot;&gt;ロ 계약기관 및 외국소속기관에서 받는 보수의 연액 합계가 900만 엔 이상 1,000만 엔 미만일 것.&lt;/td&gt;
&lt;td style=&quot;width: 27px;&quot;&gt;35&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 770px;&quot;&gt;ハ 계약기관 및 외국소속기관에서 받는 보수의 연액 합계가 800만 엔 이상 900만 엔 미만일 것.&lt;/td&gt;
&lt;td style=&quot;width: 27px;&quot;&gt;30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 770px;&quot;&gt;ニ 계약기관 및 외국소속기관에서 받는 보수의 연액 합계가 700만 엔 이상 800만 엔 미만일 것.&lt;/td&gt;
&lt;td style=&quot;width: 27px;&quot;&gt;25&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 770px;&quot;&gt;ホ 계약기관 및 외국소속기관에서 받는 보수의 연액 합계가 600만 엔 이상 700만 엔 미만일 것.&lt;/td&gt;
&lt;td style=&quot;width: 27px;&quot;&gt;20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 770px;&quot;&gt;ヘ 계약기관 및 외국소속기관에서 받는 보수의 연액 합계가 500만 엔 이상 600만 엔 미만일 것.&lt;/td&gt;
&lt;td style=&quot;width: 27px;&quot;&gt;15&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 770px;&quot;&gt;ト 계약기관 및 외국소속기관에서 받는 보수의 연액 합계가 400만 엔 이상 500만 엔 미만일 것.&lt;/td&gt;
&lt;td style=&quot;width: 27px;&quot;&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 56px;&quot; rowspan=&quot;3&quot;&gt;연령&lt;/td&gt;
&lt;td style=&quot;width: 770px;&quot;&gt;イ 연령이 30세 미만일 것.&lt;/td&gt;
&lt;td style=&quot;width: 27px;&quot;&gt;15&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 770px;&quot;&gt;ロ 연령이 30세 이상 35세 미만일 것.&lt;/td&gt;
&lt;td style=&quot;width: 27px;&quot;&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 770px;&quot;&gt;ハ 연령이 35세 이상 40세 미만일 것.&lt;/td&gt;
&lt;td style=&quot;width: 27px;&quot;&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 56px;&quot; rowspan=&quot;6&quot;&gt;연구실적&lt;/td&gt;
&lt;td style=&quot;width: 770px;&quot;&gt;イ 다음의 (1)부터 (4)까지 중 2개 이상에 해당할 것.&lt;/td&gt;
&lt;td style=&quot;width: 27px;&quot; rowspan=&quot;5&quot;&gt;25&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 770px;&quot;&gt;(1) 발명자로서 특허를 받은 발명이 1건 이상 있을 것.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 770px;&quot;&gt;(2) 외국 정부로부터 보조금, 경쟁적 자금 기타 금전의 급부를 받은 연구에 3회 이상 종사한 적이 있을 것.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 770px;&quot;&gt;(3) 우리나라 국가 기관에서 이용되고 있는 학술논문 데이터베이스(학술상의 논문에 관한 정보의 집합물로서, 그 정보를 전자계산기를 이용하여 검색할 수 있도록 체계적으로 구성한 것을 말한다. 이하 같다)에 등록되어 있는 학술잡지에 게재된 논문(해당 외국인이 책임을 지고 논문에 관한 문의에 대응 가능한 저자(이하 &quot;책임저자&quot;라 한다)인 것에 한한다)이 3편 이상 있을 것.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 770px;&quot;&gt;(4) (1)부터 (3)까지에 해당하지 않는 연구실적으로 해당 외국인이 신청한 것으로서, 이들과 동등한 연구실적으로서, 관계 행정기관의 장의 의견을 들은 후 법무대신이 인정하는 것이 있을 것.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 770px;&quot;&gt;ロ イ의 (1)부터 (4)까지 중 어느 하나에 해당할 것(イ에 해당하는 경우를 제외한다).&lt;/td&gt;
&lt;td style=&quot;width: 27px;&quot;&gt;20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 56px;&quot; rowspan=&quot;11&quot;&gt;특별가산&lt;/td&gt;
&lt;td style=&quot;width: 770px;&quot;&gt;イ 계약기관이 중소기업자(중소기업기본법(昭和 38년 법률 제154호) 제2조 제1항에 규정된 중소기업자를 말한다. 이하 같다)이며, 또한 이노베이션 창출(과학기술&amp;middot;이노베이션 창출의 활성화에 관한 법률(平成 20년 법률 제63호) 제2조 제5항에 규정된 이노베이션 창출을 말한다. 이하 같다)의 촉진에 이바지하는 것으로서 법무대신이 고시로 정하는 법률의 규정에 기초한 인정 등을 받고 있거나 보조금의 교부 기타 지원 조치로서 이노베이션 창출의 촉진에 이바지하는 것으로서 법무대신이 고시로 정하는 것을 받고 있을 것.&lt;/td&gt;
&lt;td style=&quot;width: 27px;&quot;&gt;20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 770px;&quot;&gt;ロ 계약기관이 이노베이션 창출의 촉진에 이바지하는 것으로서 법무대신이 고시로 정하는 법률의 규정에 기초한 인정 등을 받고 있거나 보조금의 교부 기타 지원 조치로서 이노베이션 창출의 촉진에 이바지하는 것으로서 법무대신이 고시로 정하는 것을 받고 있을 것(イ에 해당하는 경우를 제외한다).&lt;/td&gt;
&lt;td style=&quot;width: 27px;&quot;&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 770px;&quot;&gt;ハ 법 제7조의 2 제1항, 제20조 제2항, 제21조 제2항, 제22조의 2 제2항(법 제22조의 3에서 준용하는 경우를 포함한다) 또는 제50조제2항의 규정에 의한 신청, 법 제11조 제3항에 따른 재결 또는 법 제61조의 2의 5 제1항의 규정에 의한 허가의 날(이하 &quot;신청 등의 날&quot;이라 한다)이 속하는 사업연도의 전 사업연도(신청 등의 날이 전 사업연도 경과 후 2개월 이내인 경우는, 전전 사업연도. 이하 같다)에 있어서 계약기관(중소기업자에 한한다)에 관한 시험연구비 등 비율(1사업연도에 있어서의 시험연구비 및 개발비(법인세법 시행령(昭和 40년 정령 제97호) 제14조 제1항 제3호에 규정된 개발비 및 새로운 사업의 개시를 위해 특별히 지출하는 비용을 말한다)의 합계액의 수입금액(총수입금액에서 고정자산 또는 법인세법(昭和 40년 법률 제34호) 제2조 제21호에 규정된 유가증권의 양도에 의한 수입금액을 공제한 금액을 말한다)에 대한 비율을 말한다. 이하 같다)이 3퍼센트를 초과할 것.&lt;/td&gt;
&lt;td style=&quot;width: 27px;&quot;&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 770px;&quot;&gt;ニ 종사하는 업무에 관련된 외국의 자격, 표창 기타 고도의 전문지식, 능력 또는 경험을 가지고 있음을 증명하는 것으로서, 이노베이션 창출의 촉진에 이바지하는 것으로서 관계 행정기관의 장의 의견을 들은 후 법무대신이 인정하는 것(이 표의 연구실적 항목에 해당하는 것을 제외한다)이 있을 것.&lt;/td&gt;
&lt;td style=&quot;width: 27px;&quot;&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 770px;&quot;&gt;ホ 우리나라의 대학을 졸업하거나 대학원 과정을 수료하여 학위를 수여받았을 것.&lt;/td&gt;
&lt;td style=&quot;width: 27px;&quot;&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 770px;&quot;&gt;ヘ 일본어를 전공하여 외국의 대학을 졸업하거나, 일상적인 장면에서 사용되는 일본어에 더해, 논리적으로 다소 복잡한 일본어를 포함한 폭넓은 장면에서 사용되는 일본어를 이해할 수 있는 능력을 가지고 있음을 시험에 의해 증명받았을 것.&lt;/td&gt;
&lt;td style=&quot;width: 27px;&quot;&gt;15&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 770px;&quot;&gt;ト 일상적인 장면에서 사용되는 일본어를 이해할 수 있을 뿐만 아니라, 논리적으로 다소 복잡한 일본어를 포함한 폭넓은 장면에서 사용되는 일본어를 어느 정도 이해할 수 있는 능력을 가지고 있음을 시험에 의해 증명받았을 것(ホ 또는 ヘ에 해당하는 경우를 제외한다).&lt;/td&gt;
&lt;td style=&quot;width: 27px;&quot;&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 770px;&quot;&gt;チ 장래에 성장발전이 기대되는 분야의 첨단적인 사업으로서 관계 행정기관의 장의 의견을 들은 후 법무대신이 인정하는 사업을 담당하는 것일 것.&lt;/td&gt;
&lt;td style=&quot;width: 27px;&quot;&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 770px;&quot;&gt;リ 관계 행정기관의 장의 의견을 들은 후 법무대신이 고시로 정하는 대학을 졸업하거나, 그 대학의 대학원 과정을 수료하여 학위를 수여받았을 것.&lt;/td&gt;
&lt;td style=&quot;width: 27px;&quot;&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 770px;&quot;&gt;ヌ 국가 또는 국가로부터 위탁을 받은 기관이 실시하는 연수로서, 법무대신이 고시로 정하는 것을 수료했을 것(우리나라의 대학 또는 대학원의 수업을 이용하여 행해지는 연수에 있어서는, ホ에 해당하는 경우를 제외한다).&lt;/td&gt;
&lt;td style=&quot;width: 27px;&quot;&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 770px;&quot;&gt;ル 계약기관이 산업의 국제경쟁력의 강화 및 국제적인 경제활동의 거점의 형성을 도모하기 위해 지방공공단체로부터 필요한 경비에 관한 보조금의 교부, 기타 이것에 준하는 방법에 의한 지원으로서 당해 지방공공단체에 있어서 고도인재외국인을 받아들이는 것을 촉진하는 것이라고 법무대신이 인정하는 것을 받고 있을 것.&lt;/td&gt;
&lt;td style=&quot;width: 27px;&quot;&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; start=&quot;2&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;법 별표 제1의 2의 표의 고도전문직 항목의 하단 란 제1호 ロ에 열거된 활동을 하는 외국인으로서, 다음 표의 상단 란에 열거된 항목에 관한 동표의 중간 란에 열거된 기준(연수입 항목에 있어서는, 해당 시점에서의 해당 외국인의 연령이 30세 미만일 때는 동항의 イ부터 ト까지, 30세 이상 35세 미만일 때는 동항의 イ부터 ヘ까지, 35세 이상 40세 미만일 때는 동항의 イ부터 ホ까지, 40세 이상일 때는 동항의 イ부터 ハ까지에 열거된 기준)에 따라, 동표의 하단 란에 열거된 점수를 합계한 것이 70점 이상이며, 또한 계약기관 및 외국소속기관에서 받는 보수의 연액 합계가 300만 엔 이상일 것.&lt;/li&gt;
&lt;/ol&gt;
&lt;table style=&quot;width: 852px;&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style4&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;width: 45px;&quot;&gt;항목&lt;/th&gt;
&lt;th style=&quot;width: 778px;&quot;&gt;기준&lt;/th&gt;
&lt;th style=&quot;width: 29px;&quot;&gt;점수&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 45px;&quot; rowspan=&quot;5&quot;&gt;학력&lt;/td&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;イ 박사 학위를 가지고 있을 것.&lt;/td&gt;
&lt;td style=&quot;width: 29px;&quot;&gt;30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;ロ 경영관리에 관한 전문직 학위를 가지고 있을 것(イ에 해당하는 경우를 제외한다).&lt;/td&gt;
&lt;td style=&quot;width: 29px;&quot;&gt;25&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;ハ 석사 학위 또는 전문직 학위를 가지고 있을 것(イ 또는 ロ에 해당하는 경우를 제외한다).&lt;/td&gt;
&lt;td style=&quot;width: 29px;&quot;&gt;20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;ニ 대학을 졸업하거나 이와 동등 이상의 교육을 받았을 것(イ부터 ハ까지에 해당하는 경우를 제외한다).&lt;/td&gt;
&lt;td style=&quot;width: 29px;&quot;&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;ホ 복수의 분야에서 박사 또는 석사 학위 또는 전문직 학위를 가지고 있을 것.&lt;/td&gt;
&lt;td style=&quot;width: 29px;&quot;&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 45px;&quot; rowspan=&quot;4&quot;&gt;직력&lt;/td&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;イ 종사하는 업무에 대해 10년 이상의 실무 경험이 있을 것.&lt;/td&gt;
&lt;td style=&quot;width: 29px;&quot;&gt;20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;ロ 종사하는 업무에 대해 7년 이상 10년 미만의 실무 경험이 있을 것.&lt;/td&gt;
&lt;td style=&quot;width: 29px;&quot;&gt;15&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;ハ 종사하는 업무에 대해 5년 이상 7년 미만의 실무 경험이 있을 것.&lt;/td&gt;
&lt;td style=&quot;width: 29px;&quot;&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;ニ 종사하는 업무에 대해 3년 이상 5년 미만의 실무 경험이 있을 것.&lt;/td&gt;
&lt;td style=&quot;width: 29px;&quot;&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 45px;&quot; rowspan=&quot;7&quot;&gt;연수입&lt;/td&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;イ 계약기관 및 외국소속기관에서 받는 보수의 연액 합계가 1,000만 엔 이상일 것.&lt;/td&gt;
&lt;td style=&quot;width: 29px;&quot;&gt;40&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;ロ 계약기관 및 외국소속기관에서 받는 보수의 연액 합계가 900만 엔 이상 1,000만 엔 미만일 것.&lt;/td&gt;
&lt;td style=&quot;width: 29px;&quot;&gt;35&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;ハ 계약기관 및 외국소속기관에서 받는 보수의 연액 합계가 800만 엔 이상 900만 엔 미만일 것.&lt;/td&gt;
&lt;td style=&quot;width: 29px;&quot;&gt;30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;ニ 계약기관 및 외국소속기관에서 받는 보수의 연액 합계가 700만 엔 이상 800만 엔 미만일 것.&lt;/td&gt;
&lt;td style=&quot;width: 29px;&quot;&gt;25&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;ホ 계약기관 및 외국소속기관에서 받는 보수의 연액 합계가 600만 엔 이상 700만 엔 미만일 것.&lt;/td&gt;
&lt;td style=&quot;width: 29px;&quot;&gt;20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;ヘ 계약기관 및 외국소속기관에서 받는 보수의 연액 합계가 500만 엔 이상 600만 엔 미만일 것.&lt;/td&gt;
&lt;td style=&quot;width: 29px;&quot;&gt;15&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;ト 계약기관 및 외국소속기관에서 받는 보수의 연액 합계가 400만 엔 이상 500만 엔 미만일 것.&lt;/td&gt;
&lt;td style=&quot;width: 29px;&quot;&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 45px;&quot; rowspan=&quot;3&quot;&gt;연령&lt;/td&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;イ 연령이 30세 미만일 것.&lt;/td&gt;
&lt;td style=&quot;width: 29px;&quot;&gt;15&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;ロ 연령이 30세 이상 35세 미만일 것.&lt;/td&gt;
&lt;td style=&quot;width: 29px;&quot;&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;ハ 연령이 35세 이상 40세 미만일 것.&lt;/td&gt;
&lt;td style=&quot;width: 29px;&quot;&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 45px;&quot; rowspan=&quot;5&quot;&gt;연구실적&lt;/td&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;다음의 イ부터 ニ까지 중 1개 이상에 해당할 것.&lt;/td&gt;
&lt;td style=&quot;width: 29px;&quot; rowspan=&quot;5&quot;&gt;15&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;イ 발명자로서 특허를 받은 발명이 1건 이상 있을 것.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;ロ 외국 정부로부터 보조금, 경쟁적 자금 기타 금전의 급부를 받은 연구에 3회 이상 종사한 적이 있을 것.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;ハ 우리나라 국가 기관에서 이용되고 있는 학술논문 데이터베이스에 등록되어 있는 학술잡지에 게재된 논문(해당 외국인이 책임저자인 것에 한한다)이 3편 이상 있을 것.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;ニ イ부터 ハ까지에 해당하지 않는 연구실적으로 해당 외국인이 신청한 것으로서, 이들과 동등한 연구실적으로서, 관계 행정기관의 장의 의견을 들은 후 법무대신이 인정하는 것이 있을 것.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 45px;&quot; rowspan=&quot;9&quot;&gt;자격&lt;/td&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;イ 다음의 (1)부터 (3)까지 중 1개 이상에 해당할 것.&lt;/td&gt;
&lt;td style=&quot;width: 29px;&quot; rowspan=&quot;4&quot;&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;(1) 종사하는 업무에 관련된 2개 이상의 우리나라 국가자격(자격 중, 법령에 있어서 해당 자격을 가지지 않은 자는 해당 자격에 관한 업무 또는 행위를 하거나, 해당 자격에 관한 명칭을 사용할 수 없다고 되어 있는 것을 말한다. 이하 같다)을 가지고 있을 것.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;(2) 출입국관리 및 난민인정법 제7조 제1항 제2호의 기준을 정하는 성령(平成 2년 법무성령 제16호. 이하 &quot;기준성령&quot;이라 한다)의 기술&amp;middot;인문지식&amp;middot;국제업무 항목의 하단 란 제1호 단서의 규정에 기초하여 법무대신이 고시로 정하는 정보처리기술에 관한 시험 중, 2개 이상에 합격했을 것.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;(3) 기준성령의 기술&amp;middot;인문지식&amp;middot;국제업무 항목의 하단 란 제1호 단서의 규정에 기초하여 법무대신이 고시로 정하는 정보처리기술에 관한 자격 중, 2개 이상을 가지고 있을 것.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;ロ 다음의 (1)부터 (3)까지 중 2개 이상에 해당할 것(イ에 해당하는 경우를 제외한다).&lt;/td&gt;
&lt;td style=&quot;width: 29px;&quot; rowspan=&quot;4&quot;&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;(1) 종사하는 업무에 관련된 우리나라의 국가자격을 가지고 있을 것.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;(2) 기준성령의 기술&amp;middot;인문지식&amp;middot;국제업무 항목의 하단 란 제1호 단서의 규정에 기초하여 법무대신이 고시로 정하는 정보처리기술에 관한 시험에 합격했을 것.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;(3) 기준성령의 기술&amp;middot;인문지식&amp;middot;국제업무 항목의 하단 란 제1호 단서의 규정에 기초하여 법무대신이 고시로 정하는 정보처리기술에 관한 자격을 가지고 있을 것.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;ハ ロ의 (1)부터 (3)까지 중 어느 하나에 해당할 것(イ 또는 ロ에 해당하는 경우를 제외한다).&lt;/td&gt;
&lt;td style=&quot;width: 29px;&quot;&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 45px;&quot;&gt;특별가산&lt;/td&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;イ 계약기관이 중소기업자이며, 또한 이노베이션 창출의 촉진에 이바지하는 것으로서 법무대신이 고시로 정하는 법률의 규정에 기초한 인정 등을 받고 있거나 보조금의 교부 기타 지원 조치로서 이노베이션 창출의 촉진에 이바지하는 것으로서 법무대신이 고시로 정하는 것을 받고 있을 것.&lt;/td&gt;
&lt;td style=&quot;width: 29px;&quot;&gt;20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 45px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;ロ 계약기관이 이노베이션 창출의 촉진에 이바지하는 것으로서 법무대신이 고시로 정하는 법률의 규정에 기초한 인정 등을 받고 있거나 보조금의 교부 기타 지원 조치로서 이노베이션 창출의 촉진에 이바지하는 것으로서 법무대신이 고시로 정하는 것을 받고 있을 것(イ에 해당하는 경우를 제외한다).&lt;/td&gt;
&lt;td style=&quot;width: 29px;&quot;&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 45px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;ハ 신청 등의 날이 속하는 사업연도의 전 사업연도에 있어서 계약기관(중소기업자에 한한다)에 관한 시험연구비 등 비율이 3퍼센트를 초과할 것.&lt;/td&gt;
&lt;td style=&quot;width: 29px;&quot;&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 45px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;ニ 종사하는 업무에 관련된 외국의 자격, 표창 기타 고도의 전문지식, 능력 또는 경험을 가지고 있음을 증명하는 것으로서, 이노베이션 창출의 촉진에 이바지하는 것으로서 관계 행정기관의 장의 의견을 들은 후 법무대신이 인정하는 것(이 표의 연구실적 및 자격 항목에 해당하는 것을 제외한다)이 있을 것.&lt;/td&gt;
&lt;td style=&quot;width: 29px;&quot;&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 45px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;ホ 우리나라의 대학을 졸업하거나 대학원 과정을 수료하여 학위를 수여받았을 것.&lt;/td&gt;
&lt;td style=&quot;width: 29px;&quot;&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 45px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;ヘ 일본어를 전공하여 외국의 대학을 졸업하거나, 일상적인 장면에서 사용되는 일본어에 더해, 논리적으로 다소 복잡한 일본어를 포함한 폭넓은 장면에서 사용되는 일본어를 이해할 수 있는 능력을 가지고 있음을 시험에 의해 증명받았을 것.&lt;/td&gt;
&lt;td style=&quot;width: 29px;&quot;&gt;15&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 45px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;ト 일상적인 장면에서 사용되는 일본어를 이해할 수 있을 뿐만 아니라, 논리적으로 다소 복잡한 일본어를 포함한 폭넓은 장면에서 사용되는 일본어를 어느 정도 이해할 수 있는 능력을 가지고 있음을 시험에 의해 증명받았을 것(ホ 또는 ヘ에 해당하는 경우를 제외한다).&lt;/td&gt;
&lt;td style=&quot;width: 29px;&quot;&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 45px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;チ 장래에 성장발전이 기대되는 분야의 첨단적인 사업으로서 관계 행정기관의 장의 의견을 들은 후 법무대신이 인정하는 사업을 담당하는 것일 것.&lt;/td&gt;
&lt;td style=&quot;width: 29px;&quot;&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 45px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;リ 관계 행정기관의 장의 의견을 들은 후 법무대신이 고시로 정하는 대학을 졸업하거나, 그 대학의 대학원 과정을 수료하여 학위를 수여받았을 것.&lt;/td&gt;
&lt;td style=&quot;width: 29px;&quot;&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 45px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;ヌ 국가 또는 국가로부터 위탁을 받은 기관이 실시하는 연수로서, 법무대신이 고시로 정하는 것을 수료했을 것(우리나라의 대학 또는 대학원의 수업을 이용하여 행해지는 연수에 있어서는, ホ에 해당하는 경우를 제외한다).&lt;/td&gt;
&lt;td style=&quot;width: 29px;&quot;&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 45px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;ル 금융의 기능 강화에 이바지하는 것으로서 관계 행정기관의 장의 의견을 들은 후 법무대신이 고시로 정하는 업무에 종사할 것.&lt;/td&gt;
&lt;td style=&quot;width: 29px;&quot;&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 45px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 778px;&quot;&gt;ヲ 계약기관이 산업의 국제경쟁력의 강화 및 국제적인 경제활동의 거점의 형성을 도모하기 위해 지방공공단체로부터 필요한 경비에 관한 보조금의 교부, 기타 이것에 준하는 방법에 의한 지원으로서 당해 지방공공단체에 있어서 고도인재외국인을 받아들이는 것을 촉진하는 것이라고 법무대신이 인정하는 것을 받고 있을 것.&lt;/td&gt;
&lt;td style=&quot;width: 29px;&quot;&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; start=&quot;3&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;법 별표 제1의 2의 표의 고도전문직 항목의 하단 란 제1호 ハ에 열거된 활동을 하는 외국인으로서, 다음 표의 상단 란에 열거된 항목에 관한 동표의 중간 란에 열거된 기준에 따라, 동표의 하단 란에 열거된 점수를 합계한 것이 70점 이상이며, 또한 활동기관(법 별표 제1의 2의 표의 고도전문직 항목의 하단 란 제1호 ハ에 열거된 활동을 하는 우리나라의 공・사 기관을 말한다. 이하 같다) 및 외국소속기관(외국의 공・사 기관의 직원이 해당 기관에서 전근하여 활동기관에 받아들여지는 경우의 해당 외국의 공・사 기관을 말한다. 이하 이 호 및 다음 조 제1항 제1호 ハ에서 같다)에서 받는 보수의 연액 합계가 300만 엔 이상일 것.&lt;/li&gt;
&lt;/ol&gt;
&lt;table style=&quot;width: 852px;&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style4&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;width: 55px;&quot;&gt;항목&lt;/th&gt;
&lt;th style=&quot;width: 761px;&quot;&gt;기준&lt;/th&gt;
&lt;th style=&quot;width: 36px;&quot;&gt;점수&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 55px;&quot; rowspan=&quot;4&quot;&gt;학력&lt;/td&gt;
&lt;td style=&quot;width: 761px;&quot;&gt;イ 경영관리에 관한 전문직 학위를 가지고 있을 것.&lt;/td&gt;
&lt;td style=&quot;width: 36px;&quot;&gt;25&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 761px;&quot;&gt;ロ 박사 또는 석사 학위 또는 전문직 학위를 가지고 있을 것(イ에 해당하는 경우를 제외한다).&lt;/td&gt;
&lt;td style=&quot;width: 36px;&quot;&gt;20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 761px;&quot;&gt;ハ 대학을 졸업하거나 이와 동등 이상의 교육을 받았을 것(イ 또는 ロ에 해당하는 경우를 제외한다).&lt;/td&gt;
&lt;td style=&quot;width: 36px;&quot;&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 761px;&quot;&gt;ニ 복수의 분야에서 박사 또는 석사 학위 또는 전문직 학위를 가지고 있을 것.&lt;/td&gt;
&lt;td style=&quot;width: 36px;&quot;&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 55px;&quot; rowspan=&quot;4&quot;&gt;직력&lt;/td&gt;
&lt;td style=&quot;width: 761px;&quot;&gt;イ 사업의 경영 또는 관리에 대해 10년 이상의 실무 경험이 있을 것.&lt;/td&gt;
&lt;td style=&quot;width: 36px;&quot;&gt;25&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 761px;&quot;&gt;ロ 사업의 경영 또는 관리에 대해 7년 이상 10년 미만의 실무 경험이 있을 것.&lt;/td&gt;
&lt;td style=&quot;width: 36px;&quot;&gt;20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 761px;&quot;&gt;ハ 사업의 경영 또는 관리에 대해 5년 이상 7년 미만의 실무 경험이 있을 것.&lt;/td&gt;
&lt;td style=&quot;width: 36px;&quot;&gt;15&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 761px;&quot;&gt;ニ 사업의 경영 또는 관리에 대해 3년 이상 5년 미만의 실무 경험이 있을 것.&lt;/td&gt;
&lt;td style=&quot;width: 36px;&quot;&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 55px;&quot; rowspan=&quot;5&quot;&gt;연수입&lt;/td&gt;
&lt;td style=&quot;width: 761px;&quot;&gt;イ 활동기관 및 외국소속기관에서 받는 보수의 연액 합계가 3,000만 엔 이상일 것.&lt;/td&gt;
&lt;td style=&quot;width: 36px;&quot;&gt;50&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 761px;&quot;&gt;ロ 활동기관 및 외국소속기관에서 받는 보수의 연액 합계가 2,500만 엔 이상 3,000만 엔 미만일 것.&lt;/td&gt;
&lt;td style=&quot;width: 36px;&quot;&gt;40&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 761px;&quot;&gt;ハ 활동기관 및 외국소속기관에서 받는 보수의 연액 합계가 2,000만 엔 이상 2,500만 엔 미만일 것.&lt;/td&gt;
&lt;td style=&quot;width: 36px;&quot;&gt;30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 761px;&quot;&gt;ニ 활동기관 및 외국소속기관에서 받는 보수의 연액 합계가 1,500만 엔 이상 2,000만 엔 미만일 것.&lt;/td&gt;
&lt;td style=&quot;width: 36px;&quot;&gt;20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 761px;&quot;&gt;ホ 활동기관 및 외국소속기관에서 받는 보수의 연액 합계가 1,000만 엔 이상 1,500만 엔 미만일 것.&lt;/td&gt;
&lt;td style=&quot;width: 36px;&quot;&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 55px;&quot; rowspan=&quot;2&quot;&gt;지위&lt;/td&gt;
&lt;td style=&quot;width: 761px;&quot;&gt;イ 활동기관의 대표이사, 대표집행역 또는 업무를 집행하는 사원(대표권을 가진 자에 한한다)으로서 해당 기관의 사업의 경영 또는 관리에 종사할 것.&lt;/td&gt;
&lt;td style=&quot;width: 36px;&quot;&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 761px;&quot;&gt;ロ 활동기관의 이사, 집행역 또는 업무를 집행하는 사원으로서 해당 기관의 사업의 경영 또는 관리에 종사할 것(イ에 해당하는 경우를 제외한다).&lt;/td&gt;
&lt;td style=&quot;width: 36px;&quot;&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 55px;&quot; rowspan=&quot;13&quot;&gt;특별가산&lt;/td&gt;
&lt;td style=&quot;width: 761px;&quot;&gt;イ 활동기관이 중소기업자이며, 또한 이노베이션 창출의 촉진에 이바지하는 것으로서 법무대신이 고시로 정하는 법률의 규정에 기초한 인정 등을 받고 있거나 보조금의 교부 기타 지원 조치로서 이노베이션 창출의 촉진에 이바지하는 것으로서 법무대신이 고시로 정하는 것을 받고 있을 것.&lt;/td&gt;
&lt;td style=&quot;width: 36px;&quot;&gt;20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 761px;&quot;&gt;ロ 활동기관이 이노베이션 창출의 촉진에 이바지하는 것으로서 법무대신이 고시로 정하는 법률의 규정에 기초한 인정 등을 받고 있거나 보조금의 교부 기타 지원 조치로서 이노베이션 창출의 촉진에 이바지하는 것으로서 법무대신이 고시로 정하는 것을 받고 있을 것(イ에 해당하는 경우를 제외한다).&lt;/td&gt;
&lt;td style=&quot;width: 36px;&quot;&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 761px;&quot;&gt;ハ 신청 등의 날이 속하는 사업연도의 전 사업연도에 있어서 활동기관(중소기업자에 한한다)에 관한 시험연구비 등 비율이 3퍼센트를 초과할 것.&lt;/td&gt;
&lt;td style=&quot;width: 36px;&quot;&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 761px;&quot;&gt;ニ 종사하는 업무에 관련된 외국의 자격, 표창 기타 고도의 전문지식, 능력 또는 경험을 가지고 있음을 증명하는 것으로서, 이노베이션 창출의 촉진에 이바지하는 것으로서 관계 행정기관의 장의 의견을 들은 후 법무대신이 인정하는 것이 있을 것.&lt;/td&gt;
&lt;td style=&quot;width: 36px;&quot;&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 761px;&quot;&gt;ホ 우리나라의 대학을 졸업하거나 대학원 과정을 수료하여 학위를 수여받았을 것.&lt;/td&gt;
&lt;td style=&quot;width: 36px;&quot;&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 761px;&quot;&gt;ヘ 일본어를 전공하여 외국의 대학을 졸업하거나, 일상적인 장면에서 사용되는 일본어에 더해, 논리적으로 다소 복잡한 일본어를 포함한 폭넓은 장면에서 사용되는 일본어를 이해할 수 있는 능력을 가지고 있음을 시험에 의해 증명받았을 것.&lt;/td&gt;
&lt;td style=&quot;width: 36px;&quot;&gt;15&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 761px;&quot;&gt;ト 일상적인 장면에서 사용되는 일본어를 이해할 수 있을 뿐만 아니라, 논리적으로 다소 복잡한 일본어를 포함한 폭넓은 장면에서 사용되는 일본어를 어느 정도 이해할 수 있는 능력을 가지고 있음을 시험에 의해 증명받았을 것(ホ 또는 ヘ에 해당하는 경우를 제외한다).&lt;/td&gt;
&lt;td style=&quot;width: 36px;&quot;&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 761px;&quot;&gt;チ 장래에 성장발전이 기대되는 분야의 첨단적인 사업으로서 관계 행정기관의 장의 의견을 들은 후 법무대신이 인정하는 사업을 담당하는 것일 것.&lt;/td&gt;
&lt;td style=&quot;width: 36px;&quot;&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 761px;&quot;&gt;リ 관계 행정기관의 장의 의견을 들은 후 법무대신이 고시로 정하는 대학을 졸업하거나, 그 대학의 대학원 과정을 수료하여 학위를 수여받았을 것.&lt;/td&gt;
&lt;td style=&quot;width: 36px;&quot;&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 761px;&quot;&gt;ヌ 국가 또는 국가로부터 위탁을 받은 기관이 실시하는 연수로서, 법무대신이 고시로 정하는 것을 수료했을 것(우리나라의 대학 또는 대학원의 수업을 이용하여 행해지는 연수에 있어서는, ホ에 해당하는 경우를 제외한다).&lt;/td&gt;
&lt;td style=&quot;width: 36px;&quot;&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 761px;&quot;&gt;ル 우리나라의 공・사 기관에서 무역 기타 사업의 경영을 하는 경우에 있어서는, 해당 사업에 스스로 1억 엔 이상을 투자하고 있을 것.&lt;/td&gt;
&lt;td style=&quot;width: 36px;&quot;&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 761px;&quot;&gt;ヲ 금융의 기능 강화에 이바지하는 것으로서 관계 행정기관의 장의 의견을 들은 후 법무대신이 고시로 정하는 업무에 종사할 것.&lt;/td&gt;
&lt;td style=&quot;width: 36px;&quot;&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 761px;&quot;&gt;ワ 계약기관이 산업의 국제경쟁력의 강화 및 국제적인 경제활동의 거점의 형성을 도모하기 위해 지방공공단체로부터 필요한 경비에 관한 보조금의 교부, 기타 이것에 준하는 방법에 의한 지원으로서 당해 지방공공단체에 있어서 고도인재외국인을 받아들이는 것을 촉진하는 것이라고 법무대신이 인정하는 것을 받고 있을 것.&lt;/td&gt;
&lt;td style=&quot;width: 36px;&quot;&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; start=&quot;2&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;법 제6조 제2항, 제20조 제2항, 제21조 제2항, 제22조의 2 제2항(법 제22조의 3에서 준용하는 경우를 포함한다) 또는 제50조의 제2항의 규정에 의한 신청의 시점에서 특별고도인재인 자 또는 전항전항 각 호의 어느 하나에 해당하는 자는, 해당 신청에 관한 제1호 허가 등을 받는 시점에서 각각 특별고도인재인 자 또는 해당 각 호에 해당하는 것으로 간주한다.&lt;/li&gt;
&lt;/ol&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;제2조. &lt;/b&gt;법 별표 제1의 2의 표의 고도전문직 항목의 하단 란 제2호의 기준은, 동호에 열거된 활동을 하는 외국인이, 법 제12조 제1항 또는 법 제4장 제2절의 규정에 의한 해당 허가(이하 &quot;제2호 허가&quot;라 한다)를 받는 시점에서, 다음 각 호의 모두에 해당하는 것으로 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 다음 중 어느 하나에 해당할 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;イ 고도전문직의 재류자격을 가지고 우리나라에 재류하고 있는 외국인으로서 특별고도인재일 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ロ 고도전문직의 재류자격(법 별표 제1의 2의 표의 고도전문직 항목의 하단 란 제1호 イ에 관한 것에 한한다)을 가지고 우리나라에 재류하고 있던 외국인에 있어서는, 전조 제1항 제1호의 표의 상단 란에 열거된 항목에 관한 동표의 중간 란에 열거된 기준(연수입 항목에 있어서는, 해당 시점에서의 해당 외국인의 연령이 30세 미만일 때는 동항의 イ부터 ト까지, 30세 이상 35세 미만일 때는 동항의 イ부터 ヘ까지, 35세 이상 40세 미만일 때는 동항의 イ부터 ホ까지, 40세 이상일 때는 동항의 イ부터 ハ까지에 열거된 기준)에 따라, 동표의 하단 란에 열거된 점수를 합계한 것이 70점 이상일 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ハ 고도전문직의 재류자격(법 별표 제1의 2의 표의 고도전문직 항목의 하단 란 제1호 ロ에 관한 것에 한한다)을 가지고 우리나라에 재류하고 있던 외국인에 있어서는, 전조 제1항 제2호의 표의 상단 란에 열거된 항목에 관한 동표의 중간 란에 열거된 기준(연수입 항목에 있어서는, 해당 시점에서의 해당 외국인의 연령이 30세 미만일 때는 동항의 イ부터 ト까지, 30세 이상 35세 미만일 때는 동항의 イ부터 ヘ까지, 35세 이상 40세 미만일 때는 동항의 イ부터 ホ까지, 40세 이상일 때는 동항의 イ부터 ハ까지에 열거된 기준)에 따라, 동표의 하단 란에 열거된 점수를 합계한 것이 70점 이상이며, 또한 계약기관 및 외국소속기관에서 받는 보수의 연액 합계가 300만 엔 이상일 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ニ 고도전문직의 재류자격(법 별표 제1의 2의 표의 고도전문직 항목의 하단 란 제1호 ハ에 관한 것에 한한다)을 가지고 우리나라에 재류하고 있던 외국인에 있어서는, 전조 제1항 제3호의 표의 상단 란에 열거된 항목에 관한 동표의 중간 란에 열거된 기준에 따라, 동표의 하단 란에 열거된 점수를 합계한 것이 70점 이상이며, 또한 활동기관 및 외국소속기관에서 받는 보수의 연액 합계가 300만 엔 이상일 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 고도전문직의 재류자격(법 별표 제1의 2의 표의 고도전문직 항목의 하단 란 제1호 イ부터 ハ까지에 관한 것에 한한다)을 가지고 우리나라에 3년　(특별고도인재의 경우 1년) 이상 재류하여 동호에 열거된 활동을 하고 있었을 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 소행이 선량할 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 해당 외국인의 재류가 일본국의 이익에 합치한다고 인정될 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;법 제6조 제2항, 제20조 제2항 또는 제22조의 2 제2항의 규정에 의한 신청의 시점에서 전항 각 호의 모두에 해당하는 자는, 해당 신청에 관한 제2호 허가를 받는 시점에서 동항 각 호의 모두에 해당하는 것으로 간주한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;부칙&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(시행일)&lt;br /&gt;제1조 이 성령은 平成 27년 4월 1일부터 시행한다. 다만, 부칙 제4조의 규정은 平成 27년 1월 1일부터 시행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(경과조치)&lt;br /&gt;제2조 이 성령의 시행일 전 또는 이 성령의 시행일 이후에 출입국관리 및 난민인정법의 일부를 개정하는 법률(平成 26년 법률 제74호. 이하 &quot;개정법&quot;이라 한다)에 의한 개정 전의 출입국관리 및 난민인정법(이하 &quot;구법&quot;이라 한다) 별표 제1의 5의 표의 하단 란(ニ에 관한 부분에 한한다)에 열거된 활동 중 다음 각 호에 열거된 것을 하는 자로서의 동표의 상단 란의 재류자격을 가지고 우리나라에 재류하고 있던 외국인은, 제2조 제1항 제1호의 적용에 있어서는, 각각 해당 각 호에 열거된 자로 간주한다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;개정법 부칙 제3조 제5항 제1호에 열거된 활동: 고도전문직의 재류자격(법 별표 제1의 2의 표의 고도전문직 항목의 하단 란 제1호 イ에 관한 것에 한한다)을 가지고 우리나라에 재류하고 있던 외국인&lt;/li&gt;
&lt;li&gt;개정법 부칙 제3조 제5항 제2호에 열거된 활동: 고도전문직의 재류자격(법 별표 제1의 2의 표의 고도전문직 항목의 하단 란 제1호 ロ에 관한 것에 한한다)을 가지고 우리나라에 재류하고 있던 외국인&lt;/li&gt;
&lt;li&gt;개정법 부칙 제3조 제5항 제3호에 열거된 활동: 고도전문직의 재류자격(법 별표 제1의 2의 표의 고도전문직 항목의 하단 란 제1호 ハ에 관한 것에 한한다)을 가지고 우리나라에 재류하고 있던 외국인&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제3조 이 성령의 시행일 전 또는 이 성령의 시행일 이후에 구법 별표 제1의 5의 표의 하단 란(ニ에 관한 부분에 한한다)에 열거된 활동 중 개정법 부칙 제3조 제5항 각 호에 열거된 것을 하는 자로서의 동표의 상단 란의 재류자격을 가지고 우리나라에 재류하고 있던 외국인에 대한 제2조 제1항 제2호의 적용에 있어서는, 해당 재류자격을 가지고 우리나라에 재류하여 해당 각 호에 열거된 활동을 하고 있던 기간을 산입하는 것으로 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제4조 개정법 부칙 제4조의 규정에 의한 재류자격인정증명서(법 제7조의 2에 규정된 증명서를 말한다)의 교부에 대해서는, 이 성령의 시행일 전에 있어서도, 제1조의 규정을 적용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;출입국관리 및 난민인정법 별표 제1의 2의 표의 고도전문직의 항의 하란의 기준을 정하는 성령 제1조 제1항 각호의 표의 특별가산의 항의 규정에 기초하여 법무대신이 정하는 법률의 규정 등을 정하는 건 (平成 26년 법무성 고시 제578호)&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근 개정 平成 6년 9월 30일 법무성 고시 제302호&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;제1조.&lt;/b&gt; 출입국관리 및 난민인정법 별표 제1의 2의 표의 고도전문직의 항의 하단 란의 기준을 정하는 성령(平成 26년 법무성령 제37호. 이하 &quot;고도전문직 성령&quot;이라 한다) 제1조 제1항 각호의 표의 특별가산의 항의 중간 란 イ 및 ロ의 규정에 기초하여 정하는 법률의 규정은 별표 제1에 정하는 것으로 하고, 보조금의 교부 기타 지원 조치는 별표 제2에 정하는 것으로 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;제2조.&lt;/b&gt; 고도전문직 성령 제1조 제1항 각호의 표의 특별가산의 항의 중간 란 リ의 규정에 기초하여 정하는 대학은 다음 각 호의 어느 하나에 해당하는 대학으로 한다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;다음에 열거하는 지표(모두 가장 최근의 것에 한한다) 중 2개 이상에서 상위 300위까지에 올라 있는 외국의 대학 또는 해당 지표의 어느 하나에 올라 있는 본국의 대학
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;イ. 쿼커렐리 시몬즈사(영국)가 공표하는 세계 대학 랭킹(QS 월드 유니버시티 랭킹스)&lt;/li&gt;
&lt;li&gt;ロ. 타임즈사(영국)가 발행하는 타임즈 하이어 에듀케이션지에서 공표되는 세계 대학 랭킹(THE 월드 유니버시티 랭킹스)&lt;/li&gt;
&lt;li&gt;ハ. 상하이 랭킹 컨설턴시(중국)가 공표하는 세계 대학 학술 랭킹(아카데믹 랭킹 오브 월드 유니버시티즈)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;문부과학성이 실시하는 슈퍼글로벌 대학 창성 지원 사업(톱형 및 글로벌화 견인형)에서 보조금의 교부를 받고 있는 대학&lt;/li&gt;
&lt;li&gt;외무성이 실시하는 이노베이티브 아시아 사업에서 파트너 교로서 지정을 받고 있는 대학&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;제3조.&lt;/b&gt; 고도전문직 성령 제1조 제1항 각호의 표의 특별가산의 항의 중간 란 ヌ의 규정에 기초하여 정하는 연수는 전조 제3호에 규정하는 이노베이티브 아시아 사업의 일환으로서 외무성으로부터 위탁을 받은 독립행정법인 국제협력기구가 본국에서 실시하는 연수로서 연수 기간이 1년 이상인 것으로 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;제4조.&lt;/b&gt; 고도전문직 성령 제1조 제1항 제2호의 표의 특별가산의 항의 중간 란 ル 및 같은 항 제3호의 표의 특별가산의 항의 중간 란 ヲ의 규정에 따라 정하는 업무는 금융상품거래법(昭和 23년 법률 제25호) 제28조 제2항에 규정하는 제2종 금융상품거래업, 같은 조 제3항에 규정하는 투자조언&amp;middot;대리업 및 같은 조 제4항에 규정하는 투자운용업에 관한 업무로 한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;별표 제1 (제1조 관계)&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;대학 등에서의 기술에 관한 연구 성과의 민간 사업자에게의 이전 촉진에 관한 법률(平成 10년 법률 제52호) 제4조 제1항 또는 제11조 제1항&lt;/li&gt;
&lt;li&gt;중소기업 등 경영강화법(平成 11년 법률 제18호) 제8조 제1항, 제9조 제1항 및 제14조 제1항&lt;/li&gt;
&lt;li&gt;중소기업의 사업승계 촉진을 위한 중소기업에서의 경영 승계의 원활화에 관한 법률 등의 일부를 개정하는 법률(平成 2년 법률 제58호)에 의한 개정 전의 중소기업 등 경영강화법(平成 11년 법률 제18호) 제16조 제1항&lt;/li&gt;
&lt;li&gt;국립대학법인법(平成 15년 법률 제112호) 제34조의 4 제1항 또는 제34조의 9 제1항&lt;/li&gt;
&lt;li&gt;중소기업의 사업승계 촉진을 위한 중소기업에서의 경영 승계의 원활화에 관한 법률 등의 일부를 개정하는 법률(平成 2년 법률 제58호)에 의한 폐지 전의 중소기업의 제조기반기술의 고도화에 관한 법률(平成 18년 법률 제33호) 제4조 제1항&lt;/li&gt;
&lt;li&gt;중소기업의 사업승계 촉진을 위한 중소기업에서의 경영 승계의 원활화에 관한 법률 등의 일부를 개정하는 법률(平成 2년 법률 제58호)에 의한 폐지 전의 중소기업에 의한 지역산업자원을 활용한 사업활동의 촉진에 관한 법률(平成 19년 법률 제39호) 제6조 제1항&lt;/li&gt;
&lt;li&gt;지역경제 견인사업의 촉진에 의한 지역의 성장발전의 기반강화에 관한 법률(平成 19년 법률 제40호) 제13조 제4항 및 제13조 제7항&lt;/li&gt;
&lt;li&gt;중소기업자와 농림어업자와의 연계에 의한 사업활동의 촉진에 관한 법률(平成 20년 법률 제38호) 제4조 제1항 및 제6조 제1항&lt;/li&gt;
&lt;li&gt;에너지 환경 적합 제품의 개발 및 제조를 행하는 사업의 촉진에 관한 법률(平成 22년 법률 제38호) 제4조 제1항&lt;/li&gt;
&lt;li&gt;지역자원을 활용한 농림어업자 등에 의한 신사업의 창출 등 및 지역의 농림수산물의 이용촉진에 관한 법률(平成 22년 법률 제67호) 제5조 제1항 및 제7조 제1항&lt;/li&gt;
&lt;li&gt;특정 다국적 기업에 의한 연구개발사업 등의 촉진에 관한 특별조치법(平成 24년 법률 제55호) 제4조 제1항 및 제6조 제1항&lt;/li&gt;
&lt;li&gt;산업경쟁력강화법(平成 25년 법률 제98호) 제21조의 3 제1항, 제21조의 22 제1항, 제23조 제1항 또는 제24조의 2 제1항&lt;/li&gt;
&lt;li&gt;기술연구조합법(昭和 36년 법률 제81호) 제13조 제1항&lt;/li&gt;
&lt;li&gt;국제탁월연구대학의 연구 및 연구성과의 활용을 위한 체제의 강화에 관한 법률(平成 4년 법률 제51호) 제4조 제1항 및 제5조 제1항&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;별표 제2 (제1조 관계)&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 내각부 관계&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;전략적 이노베이션 창조 프로그램(SIP)&lt;/li&gt;
&lt;li&gt;오키나와 과학기술대학원대학 학원에 요하는 경비&lt;/li&gt;
&lt;li&gt;의료연구개발 혁신기반 창성사업(CiCLE)&lt;/li&gt;
&lt;li&gt;연구개발과 Society 5.0과의 가교 프로그램(BRIDGE)&lt;/li&gt;
&lt;li&gt;중소기업 이노베이션 창출 추진 사업&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 총무성 관계&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;정보통신기술 연구개발 위탁비&lt;/li&gt;
&lt;li&gt;소방방재 과학기술 연구 추진 제도&lt;/li&gt;
&lt;li&gt;전략적 정보통신 연구개발 추진 사업(SCOPE)&lt;/li&gt;
&lt;li&gt;국립연구개발법인 정보통신연구기구에 요하는 경비&lt;/li&gt;
&lt;li&gt;Beyond 5G 연구개발 촉진 사업&lt;/li&gt;
&lt;li&gt;스타트업 창출형 맹아적 연구개발 지원 사업&lt;/li&gt;
&lt;li&gt;혁신적 정보통신기술(Beyond 5G(6G)) 기금 사업&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 문부과학성 관계&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;우주 수송 시스템&lt;/li&gt;
&lt;li&gt;과학연구비 조성사업(과연비)&lt;/li&gt;
&lt;li&gt;기후변화 적응 전략 이니셔티브&lt;/li&gt;
&lt;li&gt;연구성과 전개 사업&lt;/li&gt;
&lt;li&gt;기초&amp;middot;기반적인 방재과학기술의 연구개발 추진&lt;/li&gt;
&lt;li&gt;고성능 범용 계산기 고도 이용 사업&lt;/li&gt;
&lt;li&gt;국제우주스테이션 개발비 보조금&lt;/li&gt;
&lt;li&gt;국제과학기술 공동연구 추진 사업&lt;/li&gt;
&lt;li&gt;국가적&amp;middot;사회적 니즈를 고려한 전략적&amp;middot;중점적인 연구개발의 추진 등&lt;/li&gt;
&lt;li&gt;지진조사연구 추진본부 관련 사업&lt;/li&gt;
&lt;li&gt;지진방재연구 전략 프로젝트&lt;/li&gt;
&lt;li&gt;중입자선을 이용한 암 치료 연구&lt;/li&gt;
&lt;li&gt;세계 톱레벨 연구거점 프로그램(WPI)&lt;/li&gt;
&lt;li&gt;사회기술 연구개발 사업&lt;/li&gt;
&lt;li&gt;전략적 창조연구 추진 사업(신기술 시즈 창출)&lt;/li&gt;
&lt;li&gt;지구관측 시스템 연구개발비 보조금&lt;/li&gt;
&lt;li&gt;지재 활용 지원 사업&lt;/li&gt;
&lt;li&gt;저탄소사회 실현을 위한 사회 시나리오 연구&lt;/li&gt;
&lt;li&gt;특정 첨단 대형 연구시설 이용촉진 교부금&lt;/li&gt;
&lt;li&gt;라이프사이언스 데이터베이스 통합 추진 사업&lt;/li&gt;
&lt;li&gt;위성에 의한 우주 이용&lt;/li&gt;
&lt;li&gt;우주과학에 관한 학술연구&amp;middot;실험 등&lt;/li&gt;
&lt;li&gt;달&amp;middot;탐사 미션 연구&amp;middot;추진&lt;/li&gt;
&lt;li&gt;항공과학기술에 관한 연구개발&lt;/li&gt;
&lt;li&gt;의료연구개발 추진사업비 보조금&lt;/li&gt;
&lt;li&gt;북극역 연구 가속 프로젝트&lt;/li&gt;
&lt;li&gt;차세대 인공지능 기술 등 연구개발 거점 형성 사업비 보조금&lt;/li&gt;
&lt;li&gt;탁월 연구원 사업&lt;/li&gt;
&lt;li&gt;차세대 화산 연구&amp;middot;인재 육성 종합 프로젝트&lt;/li&gt;
&lt;li&gt;성장 분야를 지원하는 정보기술 인재의 육성 거점 형성 사업 보조금&lt;/li&gt;
&lt;li&gt;특정 첨단 대형 연구시설 운영비 등 보조금&lt;/li&gt;
&lt;li&gt;원자력 시스템 연구개발 사업&lt;/li&gt;
&lt;li&gt;지혜를 결집한 원자력 과학기술&amp;middot;인재 육성 추진 사업&lt;/li&gt;
&lt;li&gt;연구거점 형성 사업&lt;/li&gt;
&lt;li&gt;양국 간 교류 사업&lt;/li&gt;
&lt;li&gt;국제 공동연구 사업&lt;/li&gt;
&lt;li&gt;미래사회 창조 사업&lt;/li&gt;
&lt;li&gt;Society 5.0 실현화 연구거점 지원 사업&lt;/li&gt;
&lt;li&gt;광&amp;middot;양자 비약 플래그십 프로그램(Q-LEAP)&lt;/li&gt;
&lt;li&gt;우주상황파악&lt;/li&gt;
&lt;li&gt;지구환경의 상황파악과 변동예측을 위한 연구개발&lt;/li&gt;
&lt;li&gt;해양자원의 지속적 유효이용에 관한 연구개발&lt;/li&gt;
&lt;li&gt;해역에서 발생하는 지진 및 화산활동에 관한 연구개발&lt;/li&gt;
&lt;li&gt;수리과학적 방법에 의한 해양지구정보의 고도화 및 최적화에 관한 연구개발&lt;/li&gt;
&lt;li&gt;도전적&amp;middot;독창적인 연구개발의 추진&lt;/li&gt;
&lt;li&gt;해양조사 플랫폼에 관한 첨단적 기반기술 개발 및 운용&lt;/li&gt;
&lt;li&gt;재료의 사회실장을 향한 프로세스 사이언스 구축 사업&lt;/li&gt;
&lt;li&gt;첨단 가속기 공통 기반기술 연구개발비 보조금&lt;/li&gt;
&lt;li&gt;문샷형 연구개발 프로그램&lt;/li&gt;
&lt;li&gt;창발적 연구 지원 사업&lt;/li&gt;
&lt;li&gt;연구개발 시설 공용 등 촉진비 보조금&lt;/li&gt;
&lt;li&gt;통계 전문가 인재 육성 프로젝트&lt;/li&gt;
&lt;li&gt;재료 첨단 리서치 인프라&lt;/li&gt;
&lt;li&gt;데이터 창출&amp;middot;활용형 재료 연구개발 프로젝트&lt;/li&gt;
&lt;li&gt;해양생물 빅데이터 활용기술 고도화&lt;/li&gt;
&lt;li&gt;혁신적 파워일렉트로닉스 창출 기반기술 연구개발 사업&lt;/li&gt;
&lt;li&gt;대학의 힘을 결집한, 지역의 탈탄소화 가속을 위한 기반 연구개발&lt;/li&gt;
&lt;li&gt;전국 앙트레프레너십 양성 촉진 사업&lt;/li&gt;
&lt;li&gt;차세대 X-nics 반도체 창생 거점 형성 사업&lt;/li&gt;
&lt;li&gt;백신 개발을 위한 세계 톱레벨 연구개발 거점 형성 사업&lt;/li&gt;
&lt;li&gt;혁신적 GX 기술 창출 사업(GteX)&lt;/li&gt;
&lt;li&gt;전략적 창조연구 추진 사업(첨단적 카본뉴트럴 기술 개발)&lt;/li&gt;
&lt;li&gt;지역 중핵&amp;middot;특색 있는 연구대학 강화 촉진 사업(J-PEAKS)&lt;/li&gt;
&lt;li&gt;대학발 신산업 창출 기금 사업&lt;/li&gt;
&lt;li&gt;글로벌 스타트업 캠퍼스 구상 선행 국제 공동연구 사업&lt;/li&gt;
&lt;li&gt;첨단 국제 공동연구 추진 사업/프로그램(ASPIRE)&lt;/li&gt;
&lt;li&gt;공동이용&amp;middot;공동연구 시스템 형성 사업&lt;/li&gt;
&lt;li&gt;전략적 창조연구 추진 사업(정보통신과학&amp;middot;이노베이션 기반 창출)&lt;/li&gt;
&lt;li&gt;대학발 의료계 스타트업 지원 프로그램&lt;/li&gt;
&lt;li&gt;시민참가에 의한 해양 종합지 창출 수법 구축 프로젝트&lt;/li&gt;
&lt;li&gt;화산 조사연구 추진본부 관련 사업&lt;/li&gt;
&lt;li&gt;즉전력이 되는 화산 인재 육성 프로그램&lt;/li&gt;
&lt;li&gt;일-ASEAN 과학기술&amp;middot;이노베이션 협동 연계(NEXUS)&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 후생노동성 관계&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;독립행정법인 의약품의료기기종합기구 심사 등 계정 운영비 교부금(레귤러토리 사이언스 전략 상담 추진 사업)&lt;/li&gt;
&lt;li&gt;희소질병용 의약품 등&amp;middot;특정용도 의약품 등 개발 진흥 사업&lt;/li&gt;
&lt;li&gt;기초연구 추진 사업&lt;/li&gt;
&lt;li&gt;기반적 기술 연구 사업&lt;/li&gt;
&lt;li&gt;결핵연구소 보조금&lt;/li&gt;
&lt;li&gt;후생노동과학연구비 보조금&lt;/li&gt;
&lt;li&gt;국민의 건강 유지&amp;middot;증진 및 국민의 영양 기타 국민의 식생활에 관한 조사연구&lt;/li&gt;
&lt;li&gt;생물자원 연구 사업&lt;/li&gt;
&lt;li&gt;의료연구개발 추진사업비 보조금&lt;/li&gt;
&lt;li&gt;후생노동행정 추진 조사사업비 보조금&lt;/li&gt;
&lt;li&gt;보건위생의료 조사 등 추진 사업비 보조금&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. 농림수산성 관계&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;국익에 직결된 국제연계의 추진에 요하는 경비&lt;/li&gt;
&lt;li&gt;농림수산 분야의 첨단기술 전개 사업&lt;/li&gt;
&lt;li&gt;국립연구개발법인 국제농림수산업연구센터에 요하는 경비&lt;/li&gt;
&lt;li&gt;국립연구개발법인 농업&amp;middot;식품산업기술종합연구기구에 요하는 경비&lt;/li&gt;
&lt;li&gt;안전한 농축수산물 안정공급을 위한 포괄적 레귤러토리 사이언스 연구 추진 사업&lt;/li&gt;
&lt;li&gt;농림수산 연구의 추진(위탁 프로젝트 연구)&lt;/li&gt;
&lt;li&gt;스마트 농업 기술의 개발&amp;middot;실증&amp;middot;실장 프로젝트&lt;/li&gt;
&lt;li&gt;이노베이션 창출 강화 연구 추진 사업&lt;/li&gt;
&lt;li&gt;국립연구개발법인 산림연구&amp;middot;정비기구에 관한 경비&lt;/li&gt;
&lt;li&gt;국립연구개발법인 수산연구&amp;middot;교육기구에 요하는 경비&lt;/li&gt;
&lt;li&gt;스마트 농업의 종합 추진 대책&lt;/li&gt;
&lt;li&gt;문샷형 농림수산 연구개발 사업&lt;/li&gt;
&lt;li&gt;전략적 기술개발&amp;middot;실증 사업&lt;/li&gt;
&lt;li&gt;푸드테크 비즈니스 실증 사업&lt;/li&gt;
&lt;li&gt;스타트업에 대한 종합적 지원(스타트업 종합 지원 프로그램(SBIR 지원))&lt;/li&gt;
&lt;li&gt;녹색 식량 시스템 기반 농업기술의 아시아 몬순 지역 응용 촉진 사업&lt;/li&gt;
&lt;li&gt;아그리&amp;middot;스타트업 창출 강화 대책&lt;/li&gt;
&lt;li&gt;오픈 이노베이션 연구&amp;middot;실용화 추진 사업&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6. 경제산업성 관계&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;우주산업 기술정보 기반정비 연구개발 사업(SERVIS 프로젝트)&lt;/li&gt;
&lt;li&gt;신에너지 등의 시즈 발굴&amp;middot;사업화를 향한 기술 연구개발 사업&lt;/li&gt;
&lt;li&gt;심지층의 연구시설을 사용한 시험연구 성과에 기초한 해당 시설의 이해촉진 사업비&lt;/li&gt;
&lt;li&gt;성장형 중소기업 등 연구개발 지원 사업&lt;/li&gt;
&lt;li&gt;우주태양광발전에서의 무선 송수전 기술의 고효율화를 향한 연구개발 사업 위탁비&lt;/li&gt;
&lt;li&gt;고레벨 방사성폐기물 등의 지층처분에 관한 기술개발 위탁비&lt;/li&gt;
&lt;li&gt;CCUS 연구개발&amp;middot;실증 관련 사업&lt;/li&gt;
&lt;li&gt;석유자원을 원격탐지하기 위한 하이퍼스펙트럴센서의 연구개발 사업비&lt;/li&gt;
&lt;li&gt;원자력의 이용상황 등에 관한 조사 위탁비&lt;/li&gt;
&lt;li&gt;해상풍력발전 등의 도입 확대를 향한 연구개발 사업&lt;/li&gt;
&lt;li&gt;원자력의 안전성 향상에 관한 기술개발 사업&lt;/li&gt;
&lt;li&gt;고속로 실증로 개발 사업&lt;/li&gt;
&lt;li&gt;탈탄소사회 실현을 향한 에너지절약 기술의 연구개발&amp;middot;사회실장 촉진 프로그램&lt;/li&gt;
&lt;li&gt;저레벨 방사성폐기물의 처분에 관한 기술개발 위탁비&lt;/li&gt;
&lt;li&gt;에너지&amp;middot;환경 분야의 중장기적 과제 해결에 관한 신기술 선도 연구 프로그램&lt;/li&gt;
&lt;li&gt;태양광발전의 도입 가능량 확대 등을 향한 기술개발 사업&lt;/li&gt;
&lt;li&gt;화석연료의 제로&amp;middot;이미션화를 향한 지속가능한 항공연료(SAF: Sustainable Aviation Fuel)&amp;middot;연료 암모니아 생산&amp;middot;이용 기술개발 사업&lt;/li&gt;
&lt;li&gt;주식회사 해외수요개척지원기구에 의한 투자안건&lt;/li&gt;
&lt;li&gt;카본리사이클&amp;middot;차세대 화력발전의 기술개발 사업&lt;/li&gt;
&lt;li&gt;국립연구개발법인 산업기술종합연구소에 요하는 경비&lt;/li&gt;
&lt;li&gt;IoT 사회 실현을 향한 차세대 인공지능&amp;middot;센싱 등 중핵 기술 개발&lt;/li&gt;
&lt;li&gt;전통적 공예품 산업 지원 보조금&lt;/li&gt;
&lt;li&gt;딥테크&amp;middot;스타트업 지원 사업&lt;/li&gt;
&lt;li&gt;방사성폐기물의 감용화를 향한 유리고화 기술의 기반 연구 위탁비&lt;/li&gt;
&lt;li&gt;신산업&amp;middot;혁신기술 창출을 향한 선도 연구 프로그램&lt;/li&gt;
&lt;li&gt;고효율&amp;middot;고속처리를 가능하게 하는 차세대 컴퓨팅의 기술개발 사업&lt;/li&gt;
&lt;li&gt;문샷형 연구개발 사업&lt;/li&gt;
&lt;li&gt;J-Startup 프로그램&lt;/li&gt;
&lt;li&gt;의료기기 등에서의 선진적 연구개발&amp;middot;개발체제 강인화 사업&lt;/li&gt;
&lt;li&gt;재생가능에너지의 대량 도입을 향한 차세대형 전력제어 기술개발 사업&lt;/li&gt;
&lt;li&gt;에너지&amp;middot;환경 분야에서의 혁신적 기술의 국제 공동연구개발&lt;/li&gt;
&lt;li&gt;의공 연계 이노베이션 추진 사업&lt;/li&gt;
&lt;li&gt;수소사회 실현을 향한 혁신적 연료전지 기술 등의 활용을 위한 연구개발 사업&lt;/li&gt;
&lt;li&gt;포스트 5G 정보통신 시스템 기반 강화 연구개발 사업&lt;/li&gt;
&lt;li&gt;항공기 엔진용 재료 개발&amp;middot;평가 시스템 기반 정비 사업&lt;/li&gt;
&lt;li&gt;차세대 복합재 창제 기술 개발 사업&lt;/li&gt;
&lt;li&gt;전기자동차용 혁신형 축전지 기술 개발&lt;/li&gt;
&lt;li&gt;5G 등의 활용에 의한 제조업의 다이내믹 캐퍼빌리티 강화를 향한 연구개발 사업&lt;/li&gt;
&lt;li&gt;에너지절약 일렉트로닉스의 제조 기반 강화를 향한 기술개발 사업&lt;/li&gt;
&lt;li&gt;카본 리사이클 실현을 가속하는 바이오 유래 제품 생산 기술의 개발 사업&lt;/li&gt;
&lt;li&gt;목질 바이오매스 연료 등의 안정적&amp;middot;효율적인 공급&amp;middot;이용 시스템 구축 지원 사업&lt;/li&gt;
&lt;li&gt;지열&amp;middot;지중열 등 도입 확대 기술개발 사업&lt;/li&gt;
&lt;li&gt;산업활동 등의 근본적인 탈탄소화를 향한 수소사회 모델 구축 실증 사업&lt;/li&gt;
&lt;li&gt;산업 DX를 위한 디지털 인프라 정비 사업&lt;/li&gt;
&lt;li&gt;플라스틱 유효이용 고도화 사업&lt;/li&gt;
&lt;li&gt;해상풍력발전 인재육성 사업비 보조금&lt;/li&gt;
&lt;li&gt;양자&amp;middot;고전 하이브리드 기술의 사이버&amp;middot;피지컬 개발 사업&lt;/li&gt;
&lt;li&gt;칩렛 설계 기반 구축을 향한 기술개발 사업&lt;/li&gt;
&lt;li&gt;에너지절약 AI 반도체 및 시스템에 관한 기술개발 사업&lt;/li&gt;
&lt;li&gt;자원 자율 경제 시스템 개발 촉진 사업&lt;/li&gt;
&lt;li&gt;GX 분야의 딥테크&amp;middot;스타트업 지원 사업&lt;/li&gt;
&lt;li&gt;차세대 헬스테크&amp;middot;스타트업 육성 지원 사업&lt;/li&gt;
&lt;li&gt;항공기용 혁신적 추진 시스템 개발 사업&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7. 환경성 관계&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;국립연구개발법인 국립환경연구소에 요하는 경비&lt;/li&gt;
&lt;li&gt;환경연구 종합 추진비&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8. 내각부&amp;middot;문부과학성&amp;middot;후생노동성&amp;middot;경제산업성 관계&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;건강&amp;middot;의료 분야에서의 문샷형 연구개발 등 사업&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;9. 문부과학성&amp;middot;경제산업성 관계&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;경제안전보장 중요기술 육성 프로그램&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;10. 부흥청&amp;middot;문부과학성&amp;middot;후생노동성&amp;middot;농림수산성&amp;middot;경제산업성&amp;middot;환경성 관계&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;후쿠시마 국제연구교육기구에 요하는 경비&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;11. 내각부&amp;middot;총무성&amp;middot;문부과학성&amp;middot;경제산업성 관계&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;우주전략 기금 사업&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h1&gt;고도인재 포인트제의 가점 대상이 되는 외국 자격, 표창 등 목록&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;令和 5년 12월 개정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고도인재 포인트제 신청을 하는 외국인이 아래의 외국 자격, 표창 등을 보유하고 있는 경우, 특별 가산으로 포인트가 가점됩니다(5점).&lt;br /&gt;&lt;br /&gt;1. 미국 공인회계사(USCPA): 미국 공인회계사협회(American Institute of Certified Public Accountants; AICPA)&lt;br /&gt;, 전미 주 공인회계사 심사회협회(National Association of State Boards of Accountancy; NASBA)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 외국 변호사: 각국・각주에서 실시&lt;br /&gt;※&amp;nbsp;대상이&amp;nbsp;되는&amp;nbsp;최신&amp;nbsp;자격은&amp;nbsp;&quot;외국법사무변호사&amp;nbsp;승인・지정&amp;nbsp;신청&amp;nbsp;안내&quot;(법무성&amp;nbsp;홈페이지(&lt;a href=&quot;https://www.moj.go.jp/housei/gaiben/housei07_00028.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.moj.go.jp/housei/gaiben/housei07_00028.html&lt;/a&gt; ))를 참조하십시오. &lt;br /&gt;&lt;br /&gt;(1)&amp;nbsp;브라질&amp;nbsp;연방공화국(Advogado)&lt;br /&gt;(2)&amp;nbsp;중화인민공화국(律師)&lt;br /&gt;(3)&amp;nbsp;홍콩(Solicitor&amp;nbsp;of&amp;nbsp;the&amp;nbsp;High&amp;nbsp;Court)&lt;br /&gt;(4)&amp;nbsp;프랑스&amp;nbsp;공화국(Avocat)&lt;br /&gt;(5)&amp;nbsp;독일&amp;nbsp;연방공화국(Rechtsanwalt)&lt;br /&gt;(6)&amp;nbsp;아일랜드(Solicitor)&lt;br /&gt;(7)&amp;nbsp;이탈리아&amp;nbsp;공화국(Avvocato)&lt;br /&gt;(8)&amp;nbsp;대한민국(Byonhosa/변호사)&lt;br /&gt;(9)&amp;nbsp;네덜란드&amp;nbsp;왕국(Advocaat)&lt;br /&gt;(10)&amp;nbsp;네팔&amp;nbsp;연방민주공화국(Advocate)&lt;br /&gt;(11)&amp;nbsp;뉴질랜드(Barrister&amp;nbsp;and&amp;nbsp;Solicitor)&lt;br /&gt;(12)&amp;nbsp;파라과이&amp;nbsp;공화국(Abogado)&lt;br /&gt;(13)&amp;nbsp;싱가포르&amp;nbsp;공화국(Adovocate&amp;nbsp;and&amp;nbsp;Solicitor)&lt;br /&gt;(14)&amp;nbsp;스페인&amp;nbsp;왕국(Abogado)&lt;br /&gt;(15)&amp;nbsp;스위스&amp;nbsp;연방공화국(Avocat)&lt;br /&gt;(16)&amp;nbsp;연합왕국(Solicitor&amp;nbsp;of&amp;nbsp;the&amp;nbsp;Senior&amp;nbsp;Courts)&lt;br /&gt;(17)&amp;nbsp;인도&amp;nbsp;공화국(Adovocate)&lt;br /&gt;(18)&amp;nbsp;사우디아라비아&amp;nbsp;왕국(Muhamy)&lt;br /&gt;(19)&amp;nbsp;필리핀&amp;nbsp;공화국(Attorney)&lt;br /&gt;(20)&amp;nbsp;러시아&amp;nbsp;연방(Advokat)&lt;br /&gt;(21)&amp;nbsp;대만(律師)&lt;br /&gt;(22)&amp;nbsp;벨기에&amp;nbsp;왕국(Advocaat)&lt;br /&gt;(23)&amp;nbsp;스리랑카&amp;nbsp;민주사회주의공화국(Attorney-at-Law)&lt;br /&gt;(24)&amp;nbsp;오스트리아&amp;nbsp;공화국(Rechtsanwalt)&lt;br /&gt;(25)&amp;nbsp;호주(수도특별지역(Legal&amp;nbsp;Practitioner&amp;nbsp;of&amp;nbsp;the&amp;nbsp;Supreme&amp;nbsp;Court),&amp;nbsp;뉴사우스웨일스주(Solicitor),&amp;nbsp;퀸즐랜드주(Solicitor&amp;nbsp;of&amp;nbsp;the&amp;nbsp;supreme&amp;nbsp;court),&amp;nbsp;빅토리아주(Australian&amp;nbsp;Lawyer),&amp;nbsp;서호주(Legal&amp;nbsp;Practitioner))&lt;br /&gt;(26)&amp;nbsp;캐나다(브리티시컬럼비아주(Barrister&amp;nbsp;and&amp;nbsp;Solicitor),&amp;nbsp;온타리오주(Barrister&amp;nbsp;and&amp;nbsp;Solicitor))&lt;br /&gt;(27)&amp;nbsp;미국(캘리포니아주(Attorney&amp;nbsp;at&amp;nbsp;Law),&amp;nbsp;콜로라도주(Attorney&amp;nbsp;and&amp;nbsp;Counselor&amp;nbsp;at&amp;nbsp;Law),&amp;nbsp;콜롬비아&amp;nbsp;특별구(Attorney&amp;nbsp;and&amp;nbsp;Counsellor),&amp;nbsp;코네티컷주(Attorney),&amp;nbsp;플로리다주(Attorney),&amp;nbsp;조지아주(Attorney&amp;nbsp;at&amp;nbsp;Law),&amp;nbsp;하와이주(Attorney&amp;nbsp;at&amp;nbsp;Law),&amp;nbsp;일리노이주(Attorney&amp;nbsp;and&amp;nbsp;Counselor&amp;nbsp;of&amp;nbsp;Law),&amp;nbsp;루이지애나주(Attorney&amp;nbsp;at&amp;nbsp;Law),&amp;nbsp;미네소타주(Attorney&amp;nbsp;and&amp;nbsp;Counselor&amp;nbsp;at&amp;nbsp;Law),&amp;nbsp;메릴랜드주(Attorney),&amp;nbsp;매사추세츠주(Attorney),&amp;nbsp;미시간주(Attorney),&amp;nbsp;미주리주(Attorney&amp;nbsp;and&amp;nbsp;Counselor&amp;nbsp;at&amp;nbsp;Law),&amp;nbsp;네바다주(Attorney&amp;nbsp;and&amp;nbsp;Counselor&amp;nbsp;at&amp;nbsp;law),&amp;nbsp;뉴저지주(Attorney&amp;nbsp;at&amp;nbsp;Law),&amp;nbsp;뉴욕주(Attorney&amp;nbsp;and&amp;nbsp;counsellor&amp;nbsp;at&amp;nbsp;law),&amp;nbsp;오하이오주(Attorney&amp;nbsp;and&amp;nbsp;Counselor&amp;nbsp;at&amp;nbsp;law),&amp;nbsp;오레곤주(Attorney&amp;nbsp;at&amp;nbsp;Law),&amp;nbsp;펜실베이니아주(Attorney&amp;nbsp;and&amp;nbsp;Counsellor&amp;nbsp;at&amp;nbsp;Law),&amp;nbsp;테네시주(Attorney),&amp;nbsp;텍사스주(Attorney&amp;nbsp;and&amp;nbsp;counsellor&amp;nbsp;at&amp;nbsp;law),&amp;nbsp;버지니아주(Attorney&amp;nbsp;and&amp;nbsp;Counselor&amp;nbsp;at&amp;nbsp;Law),&amp;nbsp;워싱턴주(Attorney&amp;nbsp;and&amp;nbsp;Counselor&amp;nbsp;at&amp;nbsp;Law),&amp;nbsp;노스캐롤라이나주(Attorney&amp;nbsp;and&amp;nbsp;Counselor&amp;nbsp;at&amp;nbsp;Law),&amp;nbsp;유타주(Attorney))&lt;br /&gt;&lt;br /&gt;3. 미국 보험계리사 자격(Fellow of the Society of Actuaries): 미국&amp;nbsp;보험계리사회&lt;br /&gt;영국 보험계리사 자격(Fellow of the Institute of Actuaries): 영국 보험계리사회&lt;br /&gt;4. iF 디자인 어워드(골드 어워드)(IF DESIGN AWARD(Gold Award)): iF 인터내셔널 포럼 디자인(iF International Forum Design GmbH)&lt;br /&gt;5. 인터내셔널 디자인 엑설런스 상(골드 어워드)(International Design Excellence Awards(Gold Award)): 미국 인더스트리얼 디자이너 협회(The Industrial Designers Society of America)&lt;br /&gt;6. 레드닷 디자인 상(베스트 오브 더 베스트)(Red Dot Design Award (Best of the Best)): 노르트라인-베스트팔렌 디자인센터(Design Zentrum Nordrhein Westfalen)&lt;br /&gt;7. 굿디자인 상(대상・금상)(GOOD DESIGN AWARD(GRAND AWARD・GOLD AWARD)): 공익재단법인 일본디자인진흥회(Japan Institute of Design Promotion)&lt;br /&gt;8. 아시아 디자인 상(그랜드 어워드(대상))(The DFA Design for Asia Awards(Grand Award)): 홍콩 디자인센터(Hong Kong Design Centre)&lt;br /&gt;9. ADC 애뉴얼 어워드(골드 어워드)(The ADC Annual Awards(Gold award)): 뉴욕 아트디렉터스클럽(Art Directors Club)&lt;br /&gt;10. D&amp;amp;AD 어워드(골드 어워드)(D&amp;amp;AD Awards(Gold award)): D&amp;amp;AD&lt;br /&gt;11. 칸 라이언즈 국제 크리에이티비티 페스티벌(디자인 부문 그랑프리・골드 어워드)(Cannes Lions International Festival of Creativity(Design: Gold award)): 라이언즈 페스티벌즈(Lions Festivals)&lt;br /&gt;12. LVMH 프라이즈 포 영 패션 디자이너즈(우승)(LVMH Prize for Young Fashion Designers (Winner)): LVMH&lt;br /&gt;13. 인터내셔널 울마크 프라이즈(맨즈웨어 부문(우승), 위민즈웨어 부문(우승))(International Woolmark Prize): 더 울마크 컴퍼니(The Woolmark Company)&lt;br /&gt;14. 패션 어워드(디자이너 오브 더 이어(우승))(British Fashion Council (Design of the year)): 영국 패션 평의회(British Fashion Council)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;출입국관리 및 난민인정법 제7조 제1항 제2호의 기준을 정하는 성령의 기술・인문지식・국제업무의 재류자격에 관한 기준의 특례를 정하는 건&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;(平成 25년 법무성 고시 제437호)&lt;br /&gt;&lt;br /&gt;최근 개정 令和 2년 7월 20일 법무성 고시 제118호&lt;br /&gt;&lt;br /&gt;출입국관리 및 난민인정법 제7조 제1항 제2호의 기준을 정하는 성령(平成 2년 법무성령 제16호)의 표의 법 별표 제1의 2의 표의 기술・인문지식・국제업무의 항의 하단 란에 게재된 활동의 항 하단 란 제1호 단서의 규정에 근거하여 정하는 정보처리기술에 관한 시험은 다음 제1호부터 제10호까지에 정하는 것으로 하고, 정보처리기술에 관한 자격은 제11호 및 제12호에 정하는 것으로 한다.&lt;br /&gt;&lt;br /&gt;1.&amp;nbsp;일본&amp;nbsp;내&amp;nbsp;시험으로&amp;nbsp;다음에&amp;nbsp;열거하는&amp;nbsp;것&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; イ 정보처리의 촉진에 관한 법률(소화 45년 법률 제90호)에 근거하여 경제산업대신이 실시하는 정보처리안전확보지원사 시험&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; ロ 정보처리의 촉진에 관한 법률에 근거하여 경제산업대신이 실시하는 정보처리기술자 시험 중 다음에 열거하는 것&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(1)&amp;nbsp;IT&amp;nbsp;스트래티지스트&amp;nbsp;시험&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(2)&amp;nbsp;시스템&amp;nbsp;아키텍트&amp;nbsp;시험&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(3)&amp;nbsp;프로젝트&amp;nbsp;매니저&amp;nbsp;시험&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(4)&amp;nbsp;네트워크&amp;nbsp;스페셜리스트&amp;nbsp;시험&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(5)&amp;nbsp;데이터베이스&amp;nbsp;스페셜리스트&amp;nbsp;시험&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(6)&amp;nbsp;임베디드&amp;nbsp;시스템&amp;nbsp;스페셜리스트&amp;nbsp;시험&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(7)&amp;nbsp;IT&amp;nbsp;서비스&amp;nbsp;매니저&amp;nbsp;시험&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(8)&amp;nbsp;시스템&amp;nbsp;감사&amp;nbsp;기술자&amp;nbsp;시험&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(9)&amp;nbsp;응용&amp;nbsp;정보기술자&amp;nbsp;시험&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(10)&amp;nbsp;기본&amp;nbsp;정보기술자&amp;nbsp;시험&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(11)&amp;nbsp;정보&amp;nbsp;보안&amp;nbsp;매니지먼트&amp;nbsp;시험&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; ハ 통상산업대신 또는 경제산업대신이 실시한 정보처리기술자 시험으로 다음에 열거하는 것&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(1)&amp;nbsp;제1종&amp;nbsp;정보처리기술자&amp;nbsp;인정시험&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(2)&amp;nbsp;제2종&amp;nbsp;정보처리기술자&amp;nbsp;인정시험&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(3)&amp;nbsp;제1종&amp;nbsp;정보처리기술자&amp;nbsp;시험&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(4)&amp;nbsp;제2종&amp;nbsp;정보처리기술자&amp;nbsp;시험&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(5)&amp;nbsp;특종&amp;nbsp;정보처리기술자&amp;nbsp;시험&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(6)&amp;nbsp;정보처리시스템&amp;nbsp;감사기술자&amp;nbsp;시험&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(7)&amp;nbsp;온라인&amp;nbsp;정보처리기술자&amp;nbsp;시험&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(8)&amp;nbsp;네트워크&amp;nbsp;스페셜리스트&amp;nbsp;시험&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(9)&amp;nbsp;시스템&amp;nbsp;운용관리&amp;nbsp;엔지니어&amp;nbsp;시험&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(10)&amp;nbsp;프로덕션&amp;nbsp;엔지니어&amp;nbsp;시험&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(11)&amp;nbsp;데이터베이스&amp;nbsp;스페셜리스트&amp;nbsp;시험&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(12)&amp;nbsp;마이콘&amp;nbsp;응용&amp;nbsp;시스템&amp;nbsp;엔지니어&amp;nbsp;시험&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(13)&amp;nbsp;계통분석사&amp;nbsp;시험&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(14)&amp;nbsp;시스템&amp;nbsp;감사기술자&amp;nbsp;시험&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(15)&amp;nbsp;애플리케이션&amp;nbsp;엔지니어&amp;nbsp;시험&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(16)&amp;nbsp;프로젝트&amp;nbsp;매니저&amp;nbsp;시험&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(17)&amp;nbsp;상급&amp;nbsp;시스템&amp;nbsp;어드미니스트레이터&amp;nbsp;시험&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(18)&amp;nbsp;소프트웨어&amp;nbsp;개발기술자&amp;nbsp;시험&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(19)&amp;nbsp;테크니컬&amp;nbsp;엔지니어(네트워크)&amp;nbsp;시험&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(20)&amp;nbsp;테크니컬&amp;nbsp;엔지니어(데이터베이스)&amp;nbsp;시험&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(21)&amp;nbsp;테크니컬&amp;nbsp;엔지니어(시스템&amp;nbsp;관리)&amp;nbsp;시험&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(22)&amp;nbsp;테크니컬&amp;nbsp;엔지니어(임베디드&amp;nbsp;시스템)&amp;nbsp;시험&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(23)&amp;nbsp;테크니컬&amp;nbsp;엔지니어(정보&amp;nbsp;보안)&amp;nbsp;시험&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(24)&amp;nbsp;정보&amp;nbsp;보안&amp;nbsp;어드미니스트레이터&amp;nbsp;시험&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(25)&amp;nbsp;정보&amp;nbsp;보안&amp;nbsp;스페셜리스트&amp;nbsp;시험&lt;br /&gt;&lt;br /&gt;2.&amp;nbsp;중국&amp;nbsp;내&amp;nbsp;시험으로&amp;nbsp;다음에&amp;nbsp;열거하는&amp;nbsp;것&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; イ 중국 공업화신식화부 교육여고시중심이 실시하는 시험 중 다음에 열거하는 것&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(1)&amp;nbsp;계통분석사(시스템&amp;nbsp;애널리스트)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(2)&amp;nbsp;신식계통항목관리사(인포메이션&amp;nbsp;시스템&amp;nbsp;프로젝트&amp;nbsp;매니저)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(3)&amp;nbsp;계통가구설계사(시스템&amp;nbsp;아키텍트)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(4)&amp;nbsp;연건설계사(소프트웨어&amp;nbsp;설계&amp;nbsp;엔지니어)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(5)&amp;nbsp;망락공정사(네트워크&amp;nbsp;엔지니어)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(6)&amp;nbsp;수거고계통공정사(데이터베이스&amp;nbsp;시스템&amp;nbsp;엔지니어)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(7)&amp;nbsp;정서원(프로그래머)&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; ロ 중국 신식산업부 전자교육중심 또는 중국 공업화신식화부 전자교육여고시중심이 실시한 시험 중 다음에 열거하는 것&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(1)&amp;nbsp;계통분석원(시스템&amp;nbsp;애널리스트)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(2)&amp;nbsp;고급정서원(소프트웨어&amp;nbsp;엔지니어)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(3)&amp;nbsp;계통분석사(시스템&amp;nbsp;애널리스트)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(4)&amp;nbsp;연건설계사(소프트웨어&amp;nbsp;설계&amp;nbsp;엔지니어)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(5)&amp;nbsp;망락공정사(네트워크&amp;nbsp;엔지니어)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(6)&amp;nbsp;수거고계통공정사(데이터베이스&amp;nbsp;시스템&amp;nbsp;엔지니어)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(7)&amp;nbsp;정서원(프로그래머)&lt;br /&gt;&lt;br /&gt;3.&amp;nbsp;필리핀&amp;nbsp;내&amp;nbsp;시험으로&amp;nbsp;다음에&amp;nbsp;열거하는&amp;nbsp;것&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;イ&lt;/span&gt;&lt;/span&gt; 필리핀 국가정보기술표준재단(PhilNITS)이 실시하는 시험 중 다음에 열거하는 것&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(1)&amp;nbsp;기본&amp;nbsp;정보기술자(펀더멘털&amp;nbsp;인포메이션&amp;nbsp;테크놀로지&amp;nbsp;엔지니어)&amp;nbsp;시험&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(2)&amp;nbsp;응용&amp;nbsp;정보기술자(어플라이드&amp;nbsp;인포메이션&amp;nbsp;테크놀로지&amp;nbsp;엔지니어)&amp;nbsp;시험&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; ロ 필리핀・일본 정보기술표준시험재단(JITSE Phil)이 실시한 기본 정보기술자(펀더멘털 인포메이션 테크놀로지 엔지니어) 시험&lt;br /&gt;&lt;br /&gt;4.&amp;nbsp;베트남&amp;nbsp;내&amp;nbsp;시험으로&amp;nbsp;다음에&amp;nbsp;열거하는&amp;nbsp;것&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;イ&lt;/span&gt;&lt;/span&gt; 하이테크 인큐베이션 트레이닝 센터(HITC)가 실시하는 시험 중 다음에 열거하는 것&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(1)&amp;nbsp;기본&amp;nbsp;정보기술자(펀더멘털&amp;nbsp;인포메이션&amp;nbsp;테크놀로지&amp;nbsp;엔지니어)&amp;nbsp;시험&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(2)&amp;nbsp;응용&amp;nbsp;정보기술자(어플라이드&amp;nbsp;인포메이션&amp;nbsp;테크놀로지&amp;nbsp;엔지니어)&amp;nbsp;시험&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; ロ 베트남 정보기술시험훈련지원센터(VITEC) 또는 베트남 훈련시험센터(VITEC)가 실시한 시험 중 다음에 열거하는 것&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(1)&amp;nbsp;기본&amp;nbsp;정보기술자(펀더멘털&amp;nbsp;인포메이션&amp;nbsp;테크놀로지&amp;nbsp;엔지니어)&amp;nbsp;시험&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(2)&amp;nbsp;소프트웨어&amp;nbsp;개발기술자(소프트웨어&amp;nbsp;디자인&amp;nbsp;앤드&amp;nbsp;디벨롭먼트&amp;nbsp;엔지니어)&amp;nbsp;시험&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(3)&amp;nbsp;응용&amp;nbsp;정보기술자(어플라이드&amp;nbsp;인포메이션&amp;nbsp;테크놀로지&amp;nbsp;엔지니어)&amp;nbsp;시험&lt;br /&gt;&lt;br /&gt;5.&amp;nbsp;미얀마&amp;nbsp;내&amp;nbsp;미얀마컴퓨터연맹(MCF)이&amp;nbsp;실시하는&amp;nbsp;시험&amp;nbsp;중&amp;nbsp;다음에&amp;nbsp;열거하는&amp;nbsp;것&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; イ 기본 정보기술자(펀더멘털 인포메이션 테크놀로지 엔지니어) 시험&lt;br /&gt;&amp;nbsp;&amp;nbsp; ロ 응용 정보기술자(어플라이드 인포메이션 테크놀로지 엔지니어) 시험&lt;br /&gt;&lt;br /&gt;6.&amp;nbsp;대만&amp;nbsp;내&amp;nbsp;재단법인자신공업책진회(III)가&amp;nbsp;실시한&amp;nbsp;시험&amp;nbsp;중&amp;nbsp;다음에&amp;nbsp;열거하는&amp;nbsp;것&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;イ&lt;/span&gt;&lt;/span&gt; 연체설계전업인원(소프트웨어 디자인 앤드 디벨롭먼트 IT 엑스퍼트) 시험&lt;br /&gt;&amp;nbsp;&amp;nbsp; ロ 망로통훈전업인원(네트워크 커뮤니케이션 IT 엑스퍼트) 시험&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; ハ&amp;nbsp;자신안전관리전업인원(인포메이션 시스템 시큐리티 IT 엑스퍼트) 시험&lt;br /&gt;&lt;br /&gt;7.&amp;nbsp;말레이시아&amp;nbsp;내&amp;nbsp;멀티미디어&amp;nbsp;기술촉진본부(METEOR)가&amp;nbsp;실시하는&amp;nbsp;기본&amp;nbsp;정보기술자(펀더멘털&amp;nbsp;인포메이션&amp;nbsp;테크놀로지&amp;nbsp;프로페셔널)&amp;nbsp;시험&lt;br /&gt;&lt;br /&gt;8.&amp;nbsp;태국&amp;nbsp;내&amp;nbsp;시험으로&amp;nbsp;다음에&amp;nbsp;열거하는&amp;nbsp;것&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; イ 국립과학기술개발청(NSTDA)이 실시하는 시험 중 다음에 열거하는 것&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(1)&amp;nbsp;기본&amp;nbsp;정보기술자(펀더멘털&amp;nbsp;인포메이션&amp;nbsp;테크놀로지&amp;nbsp;엔지니어)&amp;nbsp;시험&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(2)&amp;nbsp;응용&amp;nbsp;정보기술자(어플라이드&amp;nbsp;인포메이션&amp;nbsp;테크놀로지&amp;nbsp;엔지니어)&amp;nbsp;시험&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; ロ 국립전자컴퓨터기술센터(NECTEC)가 실시한 기본 정보기술자(펀더멘털 인포메이션 테크놀로지 엔지니어) 시험&lt;br /&gt;&lt;br /&gt;9.&amp;nbsp;몽골&amp;nbsp;내&amp;nbsp;몽골국립&amp;nbsp;IT파크(NITP)가&amp;nbsp;실시하는&amp;nbsp;시험&amp;nbsp;중&amp;nbsp;다음에&amp;nbsp;열거하는&amp;nbsp;것&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; イ 기본 정보기술자(펀더멘털 인포메이션 테크놀로지 엔지니어) 시험&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; ロ 응용 정보기술자(어플라이드 인포메이션 테크놀로지 엔지니어) 시험&lt;br /&gt;&lt;br /&gt;10.&amp;nbsp;방글라데시&amp;nbsp;내&amp;nbsp;방글라데시컴퓨터평의회(BCC)가&amp;nbsp;실시하는&amp;nbsp;시험&amp;nbsp;중&amp;nbsp;다음에&amp;nbsp;열거하는&amp;nbsp;것&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; イ 기본 정보기술자(펀더멘털 인포메이션 테크놀로지 엔지니어) 시험&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ロ 응용 정보기술자(어플라이드 인포메이션 테크놀로지 엔지니어) 시험&lt;br /&gt;&lt;br /&gt;11.&amp;nbsp;싱가포르&amp;nbsp;내&amp;nbsp;싱가포르컴퓨터소사이어티(SCS)가&amp;nbsp;인정하는&amp;nbsp;서티파이드&amp;nbsp;IT&amp;nbsp;프로젝트&amp;nbsp;매니저(CITPM)&lt;br /&gt;&lt;br /&gt;12.&amp;nbsp;한국&amp;nbsp;내&amp;nbsp;한국산업인력공단이&amp;nbsp;인정하는&amp;nbsp;자격&amp;nbsp;중&amp;nbsp;다음에&amp;nbsp;열거하는&amp;nbsp;것&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; イ 정보처리기사(엔지니어 인포메이션 프로세싱)&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ロ 정보처리산업기사(인더스트리얼 엔지니어 인포메이션 프로세싱)&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/113</guid>
      <comments>https://pscr.tistory.com/113#entry113comment</comments>
      <pubDate>Thu, 22 May 2025 21:37:12 +0900</pubDate>
    </item>
    <item>
      <title>EU261 - 유럽연합 항공편 지연 및 취소 보상 규정과 &amp;quot;특수한 사정&amp;quot;</title>
      <link>https://pscr.tistory.com/112</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;T모 항공사의 유럽발 노선 대-지연 사건으로 한국에도 그 존재가 조금 알려진 EU261, 혹은 EC261은 흔히 '연착 3시간 되면 600유로를 보상하라고 하는 유럽연합의 법' 정도로 알려져 있습니다만은, 실은 그보다는 좀 더 복잡합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뭐가 복잡하냐... 하면 일단 이름부터가 더 복잡한데요, 이것의 정식 명칭은 &quot;항공편의 탑승 거부, 취소, 장거리 지연이 발생한 경우의 탑승객에 대한 보상과 보조에 관한 기본 규칙을 확립하고, 규정 (EEC) 제295/91호를 폐지하는 데 있어서의 유럽의회와 유럽위원회의 2004년 2월 11일 규정 (EC) 제261/2004호&quot;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 이걸 풀네임으로 부르는 조금 이상한 사람은 없고, 일반적으로는 흔히 EU261 내지는 EC261이라고 합니다. 좀 formal한 문서에서도 그냥 &quot;Regulation (EC) No 261/2004&quot;라고 하고요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;이 규제가 적용되는 항공사&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EU261은 한국 국내법이나 국제법이 아니라 유럽연합의 규정이므로, 당연히 모든 항공편에 이 규제가 적용되는 것은 아닙니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;European-Union.png&quot; data-origin-width=&quot;532&quot; data-origin-height=&quot;362&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c9VONG/btsK1KMgdpb/tbqI4hsA2IDBycV14YQK6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c9VONG/btsK1KMgdpb/tbqI4hsA2IDBycV14YQK6k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c9VONG/btsK1KMgdpb/tbqI4hsA2IDBycV14YQK6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc9VONG%2FbtsK1KMgdpb%2FtbqI4hsA2IDBycV14YQK6k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;532&quot; height=&quot;362&quot; data-filename=&quot;European-Union.png&quot; data-origin-width=&quot;532&quot; data-origin-height=&quot;362&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 규제의 적용 대상은 다음과 같습니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;유럽연합(EU)/유럽경제구역(EEA)/스위스(CH)에서 출발&lt;/b&gt;하는 모든 항공편
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;항공사 또는 승객의 국적과 무관하게 적용됩니다. 한국 항공사든 미국 항공사든 EU/EEA/CH 지역에서 출발하는 편이라면 마찬가지로 이 규제의 대상이 됩니다.&lt;/li&gt;
&lt;li&gt;하지만 EU/EEA/CH &lt;b&gt;바깥&lt;/b&gt;에서 출발하여 EU/EEA/CH 지역에 &lt;b&gt;도착&lt;/b&gt;하는 항공편에는 적용되지 않습니다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;유럽연합/유럽경제구역(EEA)에 &lt;b&gt;소재&lt;/b&gt;한 항공사가 운영하는 &lt;b&gt;모든&lt;/b&gt; 항공편
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 경우 실제 항공기를 운영하는 회사가 유럽연합에 거점을 둔 항공사여야 할 필요가 있습니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예를 들어 네덜란드 KLM 홈페이지에서 인천에서 김해로 가는 KL3396편을 구매했는데 지연된 경우, 이것은 실제로는 KLM 비행기가 아니라 코드셰어를 통해 대한항공이 운영하는 공동운항편이므로, EU261의 보상대상이 되지 않습니다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;반대로 대한항공에서 인천에서 암스테르담으로 가는 KE5925편이 지연되었다면, 이것은 코드셰어를 통해 실제로는 네덜란드 항공사 KLM이 운영하는 공동운항편이므로 EU261의 보상대상이 됩니다.&lt;/li&gt;
&lt;/ul&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;이외에도,&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;영국&lt;/b&gt;은 EU를 탈퇴하여 더 이상 EU 회원국이 아니지만, 브렉시트 당시 EU261에 상당하는 내용을 국내법화(Assimilated Law)하여 적용 중입니다(UK261).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;터키(튀르키예)&lt;/b&gt;에서도 SHY-PASSENGER라는 자체 법률로 비슷한 내용을 보상합니다.&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;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;결항/취소보상&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;항공편이 취소되었을 때, 규제의 대상이 되는 항공사는 EU261에 규정된 보상금을 지급해야 합니다. 하지만 항공사가 다음과 같은 면책 조치를 취했을 경우, 보상금 청구 대상이 되지 않습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;항공편의 예정 출발시간으로부터 &lt;b&gt;2주 이상&lt;/b&gt; 남았다면:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;취소 사실을 안내&lt;/b&gt;하기만 하면, 항공사의 &lt;b&gt;보상 책임은 면제&lt;/b&gt;됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;항공편의 예정 출발시간으로부터 &lt;b&gt;14일~7일&lt;/b&gt; 사이의 시간이 남았다면:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;취소 사실을 안내함과 동시에, 원래 예정되어 있던 도착 시간보다 ~4시간 늦게 도착하는 대체 항공편을 제공하는 경우 항공사는 보상 책임에서 면제됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;항공편의 예정 출발시간으로부터 &lt;b&gt;7일보다 적은&lt;/b&gt; 시간이 남았다면:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;항공편의 취소 사실을 안내함과 동시에, 원래 예정되어 있던 도착 시간보다 ~1시간 늦게 도착하는 대체 항공편을 제공하는 경우 항공사는 보상 책임에서 면제됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 책임 면제에 해당되지 않는다면, 고객은 아래의 취소 배상금을 청구할 수 있습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;취소보상 금액&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단거리 (비행거리 1500km 미만): &lt;b&gt;250유로&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;중거리 (유럽연합 내부를 오가는 항공편인 경우 비행거리 1500km 이상, 그렇지 않은 항공편인 경우 비행거리 1500km 이상 3500km 미만): &lt;b&gt;400유로&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;장거리 (유럽연합 내부를 오가는 항공편이 아니면서, 비행거리 3500km 이상): &lt;b&gt;600유로&lt;/b&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;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;지연보상, 오버부킹/탑승거부 보상&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;항공편이 지연되었을 때의 보상에 관한 내용은 사실 규정 본문에는 없습니다. 하지만 C-402/07 및 C-432/07(병합 EU:C:2009:716) 판례에 따라 &lt;b&gt;3시간 이상의 지연이 발생하는 경우, 항공편 취소 시와 같은 보상이 적용&lt;/b&gt;되도록 되어 있습니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;따라서 항공편이 취소된 승객과 항공편 지연으로 영향을 받은 승객은 모두 시간 손실이라는 유사한 손해를 겪으므로 규정 261/2004 제7조에 따른 보상 권리 적용에 있어 비교 가능한 상황에 처한다고 할 수 있다. (...중략...) 취소 및 장시간 지연 상황에서 항공 승객이 겪는 피해가 유사하므로, 원칙상 지연된 항공편의 승객과 취소된 항공편의 승객을 다르게 취급하는 것은 동등 대우 원칙에 위배된다. (...중략...) 따라서 규정 261/2004 제5, 6, 7조는 &lt;b&gt;지연된 항공편 승객을 취소된 항공편 승객과 동일하게 간주하여 보상 권리를 인정할 수 있다고 해석&lt;/b&gt;되어야 한다.&lt;/blockquote&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;&lt;b&gt;원래 도착 예정시간&lt;/b&gt;&quot;과 &quot;&lt;b&gt;실제로 목적지에 도착해서 비행기 문이 열린 시간&lt;/b&gt;&quot;의 차이로 계산됩니다. (&lt;i&gt;Germanwings GmbH v. Ronny Henning&lt;/i&gt; 사건번호 C-452/13, EU:C:2014:2141 참조)&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;h4 data-ke-size=&quot;size20&quot;&gt;지연보상 금액&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단거리 (비행거리 1500km 미만): &lt;b&gt;250유로&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;중거리 (유럽연합 내부를 오가는 항공편인 경우 비행거리 1500km 이상, 그렇지 않은 항공편인 경우 비행거리 1500km 이상 3500km 미만): &lt;b&gt;400유로&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;장거리 (유럽연합 내부를 오가는 항공편이 아니면서, 비행거리 3500km 이상): &lt;b&gt;600유로&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;고객에 대한 지원(Care)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 위의 지연보상과는 &lt;b&gt;별개&lt;/b&gt;로, 단거리의 경우 2시간 이상, 중거리의 경우 3시간 이상, 장거리의 경우 4시간 이상 지연되었다면 항공사는 고객에게 지원(care)을 제공하여야 합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;지연 시간에 따라 적절하게 &lt;b&gt;식사, 간식&lt;/b&gt; 제공
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;보통 공항 내 음식점에서 쓸 수 있는 바우처같은 걸 줍니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;무료 연락 수단&lt;/b&gt; (전화/이메일/텔렉스/팩스) 2건 제공&lt;/li&gt;
&lt;li&gt;지연 시간이 1박을 넘겼을 경우, 숙소 제공 &amp;amp; 숙소와 공항 간 교통편 제공&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;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&quot;특별한 사정&quot;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EC261 5조 3항에는 다음과 같은 규정이 있습니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;해당&amp;nbsp;취소가&amp;nbsp;&lt;b&gt;가능한&amp;nbsp;모든&amp;nbsp;합리적인&amp;nbsp;조치를&amp;nbsp;취하였다고&amp;nbsp;하더라도&amp;nbsp;방지할&amp;nbsp;수&amp;nbsp;없었을&amp;nbsp;특수한&amp;nbsp;상황&lt;/b&gt;(extraordinary&amp;nbsp;circumstances)에&amp;nbsp;의해&amp;nbsp;발생하였다는&amp;nbsp;것을&amp;nbsp;입증할&amp;nbsp;수&amp;nbsp;있을&amp;nbsp;경우,&amp;nbsp;운영&amp;nbsp;항공사는&amp;nbsp;제7조에&amp;nbsp;따른&amp;nbsp;보상&amp;nbsp;지불의&amp;nbsp;의무를&amp;nbsp;지지&amp;nbsp;않는다.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;i&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;An&amp;nbsp;operating&amp;nbsp;air&amp;nbsp;carrier&amp;nbsp;shall&amp;nbsp;not&amp;nbsp;be&amp;nbsp;obliged&amp;nbsp;to&amp;nbsp;pay&amp;nbsp;compensation&amp;nbsp;in&amp;nbsp;accordance&amp;nbsp;with&amp;nbsp;Article&amp;nbsp;7,&amp;nbsp;if&amp;nbsp;it&amp;nbsp;can&amp;nbsp;prove&amp;nbsp;that&amp;nbsp;the&amp;nbsp;cancellation&amp;nbsp;is&amp;nbsp;caused&amp;nbsp;by&amp;nbsp;extraordinary&amp;nbsp;circumstances&amp;nbsp;which&amp;nbsp;could&amp;nbsp;not&amp;nbsp;have&amp;nbsp;been&amp;nbsp;avoided&amp;nbsp;even&amp;nbsp;if&amp;nbsp;all&amp;nbsp;reasonable&amp;nbsp;measures&amp;nbsp;had&amp;nbsp;been&amp;nbsp;taken.&lt;/span&gt;&lt;/i&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 승객에게 돈을 안 주기 위해, '우리 지연/취소 사유는 extraordinary circumstances임~~ 돈 못줌~~~'이라고 나오는 양아치들이 좀 있습니다. 특히 한국 포함, EU 국외에 소재한 항공사들 중에 이러는 비율이 많습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 항공사의 지연 사유가 EU261에서 가리키는 특별한 사정으로 인정받기 위해서는, &lt;b&gt;천재지변처럼 진짜 특별한 사정&lt;/b&gt;이지 않으면 안됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유럽연합 일반재판소 제4부는 2008년 &lt;i&gt;Wallentin-Hermann v. Alitalia&lt;/i&gt; (사건번호 C-549/07, EU:C:2008:771) 사건에서, EC261에서 규정한 &quot;특별한 사정&quot;에 대해 다음과 같이 판시했습니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;항공기의 기술적 문제가 항공편 취소로 이어진 경우에&lt;/span&gt;&lt;/span&gt;, 그 문제가 항공사의 정상적인 활동에 내재적이지 않으며 그 통제 범위를 벗어나는 성질이나 기원을 가지는 사건에서 비롯되지 않는 한, &lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;규정 제261/2004호 제5조(3)에서 규정하는 &amp;lsquo;특별한 사정&amp;rsquo;의 &lt;/span&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;개념에 해당되지 않는&lt;/span&gt; 것으로 해석되어야 한다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;...&amp;nbsp;Article&amp;nbsp;5(3)&amp;nbsp;of&amp;nbsp;Regulation&amp;nbsp;No&amp;nbsp;261/2004&amp;nbsp;must&amp;nbsp;be&amp;nbsp;interpreted&amp;nbsp;as&amp;nbsp;meaning&amp;nbsp;that&amp;nbsp;a&amp;nbsp;technical&amp;nbsp;problem&amp;nbsp;in&amp;nbsp;an&amp;nbsp;aircraft&amp;nbsp;which&amp;nbsp;leads&amp;nbsp;to&amp;nbsp;the&amp;nbsp;cancellation&amp;nbsp;of&amp;nbsp;a&amp;nbsp;flight&amp;nbsp;is&amp;nbsp;not&amp;nbsp;covered&amp;nbsp;by&amp;nbsp;the&amp;nbsp;concept&amp;nbsp;of&amp;nbsp;&amp;lsquo;extraordinary&amp;nbsp;circumstances&amp;rsquo;&amp;nbsp;within&amp;nbsp;the&amp;nbsp;meaning&amp;nbsp;of&amp;nbsp;that&amp;nbsp;provision,&amp;nbsp;unless&amp;nbsp;that&amp;nbsp;problem&amp;nbsp;stems&amp;nbsp;from&amp;nbsp;events&amp;nbsp;which,&amp;nbsp;by&amp;nbsp;their&amp;nbsp;nature&amp;nbsp;or&amp;nbsp;origin,&amp;nbsp;are&amp;nbsp;not&amp;nbsp;inherent&amp;nbsp;in&amp;nbsp;the&amp;nbsp;normal&amp;nbsp;exercise&amp;nbsp;of&amp;nbsp;the&amp;nbsp;activity&amp;nbsp;of&amp;nbsp;the&amp;nbsp;air&amp;nbsp;carrier&amp;nbsp;concerned&amp;nbsp;and&amp;nbsp;are&amp;nbsp;beyond&amp;nbsp;its&amp;nbsp;actual&amp;nbsp;control.&lt;/span&gt;&lt;/i&gt;&lt;/blockquote&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;blockquote data-ke-style=&quot;style3&quot;&gt;재판소는 &lt;b&gt;항공기 정비 중 발견된 기술적 문제 또는 정비 실패로 인해 발생한 기술적 문제는 '특별한 사정'으로 간주될 수 없음을 명확히 하였다&lt;/b&gt;. 재판소는 예기치 않게 발생한 기술적 문제가 정비 불량에 기인하지 않고 정기 정비 점검 중에 발견되지 않았다 하더라도, 해당 문제가 항공사의 정상적인 활동 수행에 내재적이라면 '특별한 사정'의 정의에 포함되지 않는다고 보았다.&lt;br /&gt;&lt;br /&gt;예를 들어, 특정한 항공기 부품의 조기 고장과 같은 문제를 예기치 못한 사건으로 간주할 수 있을지 모른다. 그럼에도 불구하고 이러한 고장의 발생은, 특정한 조건(특히 기상 조건)이 좋지 않거나 극단적인 상황 하에서 항공사에 의해 운영되는 항공기의 매우 복잡한 운영 체계에 본질적인 인과가 있을 뿐더러, 이와 더불어 항공기의 어떤 부품도 영구적이지 않다는 점을 고려해야 한다. 따라서, 이러한 예기치 못한 사건은 항공사의 정상적인 활동 수행에 내재적인 것으로 간주되어야 한다.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;- Interpretative Guidelines on Regulation (EC) No 261/2004 (C/2016/3502) &lt;/i&gt;중 발췌, 발-번역&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EC261상 특수한 사례로 인정되기 위한 조건은 굉장히 보수적이라서, 전반적으로 항공사 입장에서 진짜 온 우주가 억까한 수준의 원인이 아닌 이상 특별한 사정으로 인정받지 않습니다.&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;으로 간주되지 않았습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비행기가 근처에 있던 탑승용 계단과 충돌하여 고장남 (C-394/14, &lt;i&gt;Siewert v. Condor Flugdienst GmbH&lt;/i&gt;)&lt;/li&gt;
&lt;li&gt;승무원의 파업 (C-28/20, &lt;i&gt;Airhelp v. SAS&lt;/i&gt;)&lt;/li&gt;
&lt;li&gt;승무원의 기습 파업 (C-195/17, &lt;i&gt;Kr&amp;uuml;semann and Others v. TUIfly GmbH&lt;/i&gt;)&lt;/li&gt;
&lt;li&gt;활주로에 놓여 있던 못이 타이어에 박힘 (C-501/17, &lt;i&gt;Germanwings GmbH v. Wolfgang Pauels&lt;/i&gt;)&lt;/li&gt;
&lt;li&gt;부조종사가 극단적인 선택을 하여 비행 2시간 전, 승무원 숙소에서 숨진 채로 발견 (C-156/22, &lt;i&gt;TAP Portugal v. flightright and Myflyright&lt;/i&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;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;진짜 특별한 사정&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 대체 어떤 상황이 진짜 &quot;특별한 사정&quot;인 걸까요?&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;snow_airplane.png&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;782&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BalJ0/btsK2WEEHtZ/ZW0cl32rAYE2lI0uUea67K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BalJ0/btsK2WEEHtZ/ZW0cl32rAYE2lI0uUea67K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BalJ0/btsK2WEEHtZ/ZW0cl32rAYE2lI0uUea67K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBalJ0%2FbtsK2WEEHtZ%2FZW0cl32rAYE2lI0uUea67K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;391&quot; data-filename=&quot;snow_airplane.png&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;782&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;폭우, 폭설, 화산 폭발 등의 &lt;b&gt;자연재해&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;테러 신고, 정치적 불안정성(전쟁, 쿠데타, ...) 등등&lt;/li&gt;
&lt;li&gt;버드 스트라이크로 인한 엔진 고장&lt;/li&gt;
&lt;li&gt;항공사 직원 이외의, 운항에 필수적인 타사 직원의 파업&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;항공관제사, 공항 직원 파업 등등... 이 해당됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;항공기에 숨겨진 제조상의 결함(hidden manufacturing defects)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;제조사에서 기체에 내재된 결함이 있다는 사실을 항공사에 숨기는 경우가 해당됩니다.&lt;/li&gt;
&lt;li&gt;이 경우 해당 모델 항공기의 모든 제품에 해당 결함이 숨겨져 있으면서, 운행상 명백하게 안전에 영향을 끼치는 결함이어야 합니다. 대표적인 사례로는 소프트웨어 결함으로 추락 사례가 발생한 보잉 737MAX 사건이 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;등에 의한 결항/지연은 진짜 &quot;특별한 사정&quot;으로 인정되어 &lt;b&gt;보상 대상이 되지 않습니다&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h1&gt;보상 신청 절차&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 EU261 보상 신청은 고객센터의 온라인 폼, 혹은 이메일이나 우편 등을 통해 접수할 수 있도록 되어 있습니다. 이 절차는 항공사마다 다릅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 EU261 보상 신청을 위한 전용 폼을 운영하는 항공사라면 항공사 이름 + EU261 등으로 검색하면 신청하는 사이트가 나옵니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런 게 없다면 고객센터 이메일 등으로 접수를 해야 합니다. 일반적으로 다음의 정보를 기입하고, EC261에 따른 보상(compensation under EC261)을 요구하면 됩니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예약번호(Reference No.), 항공권 번호(E-Ticket No.)&lt;/li&gt;
&lt;li&gt;자신의 성명&lt;/li&gt;
&lt;li&gt;항공편명&lt;/li&gt;
&lt;li&gt;출발 및 도착 공항&lt;/li&gt;
&lt;li&gt;연락처 (주소, 전화번호, 이메일)&lt;/li&gt;
&lt;li&gt;예상 출발/도착시간&lt;/li&gt;
&lt;li&gt;실제 출발/도착시간&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;배째라는데요???&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;항공사가 보상을 거부하는 대부분의 경우에서, 『예기치 못한 고장에 의한 지연/결항은 &quot;특별한 사정&quot;에 해당되므로 보상 대상이 아니다~』 뭐 이런 소리를 할겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 일단 적절한 판례(&lt;i&gt;Wallentin-Hermann v. Alitalia&lt;/i&gt;나 &lt;i&gt;B&amp;ouml;ck v. Air France&lt;/i&gt; 등)를 제시하며 반박하고, 항공사가 계속해서 보상을 거부할 경우 관할 NEB에 신고하겠다고 이의를 제기하는 식으로 대응할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 NEB(National Enforcement Body)라는 것은 해당 규정의 집행을 위해 지정된 국가별 정부기관을 가리킵니다. 각 EU/EEA/CH 국가별 NEB 기관은 이 링크에서 확인할 수 있습니다: &lt;a href=&quot;https://transport.ec.europa.eu/document/download/d7b5dd33-4083-4faa-8132-b6dc8b3a1c07_en?filename=2004_261_national_enforcement_bodies.pdf&quot;&gt;https://transport.ec.europa.eu/document/download/d7b5dd33-4083-4faa-8132-b6dc8b3a1c07_en?filename=2004_261_national_enforcement_bodies.pdf&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼에도 불구하고 항공사가 보상을 거부할 경우, NEB에 직접 신고하여 대응할 수 있습니다. 그러면 해당 국가의 정부기관에서 조사를 진행하고, 항공사에 책임이 있을 경우 시정조치나 과징금을 때리도록 되어 있습니다. 단 NEB는 조사의 결과로서 항공사에 제재를 부여할 뿐, 개인에 대한 보상 지급을 보장해 주지는 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;낮은 확률로 NEB의 말조차도 듣지 않는 막장 케이스라면, 권리 구제를 위해 소재국/출발국의 법원이나 EU 재판소를 통한 법적 절차를 밟아야 할 수 있습니다.&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;배째기 대행 서비스&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 개인이 혼자서 배를 째주기는 시간도 어렵고 여러 모로 어려운데요, 이런 집요한 거부를 당했거나 어떻게 해야 할 지 잘 모르겠는 사람들을 위한 &lt;b&gt;보상 청구 대행 서비스&lt;/b&gt;들이 있습니다. 대행 서비스로 유명한 곳으로는 AirHelp, AirAdvisor, Flightright 등등이 있습니다.&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;EU261 관련 판례를 찾다 보면 AirHelp, Flightright, Myflyright 등 이런 대행사가 원고 자격으로 종종 등장합니다. 그러니까 해당 케이스에서는 대행사들이 법원에 소송까지 해서 떼인 돈을 받아줬다는 겁니다. 꽤 든든하죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 소송까지 가게 되는 케이스라면, 변호사비같은 게 공제되기 때문에 꽤 액수가 줄어든다고는 합니다만은 아무래도 못 받는 것보다는 나은 것입니다.&lt;/p&gt;</description>
      <category>기타</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/112</guid>
      <comments>https://pscr.tistory.com/112#entry112comment</comments>
      <pubDate>Sat, 30 Nov 2024 14:53:03 +0900</pubDate>
    </item>
    <item>
      <title>바이엘 원어데이 컴플리트 멀티비타민 타블렛 300정 직구</title>
      <link>https://pscr.tistory.com/111</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;원어데이(One A Day&amp;reg;)는 독일계 유명 화학회사인 바이엘(Bayer)사의 영양제 브랜드입니다. 거대 브랜드에서 오는 안심감과 적당히 저렴한 가격, 무난한 성분구성으로 미국 아마존 영양제 상위랭킹을 거의 언제나 사수하고 있지요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;얼마나 저렴한가... 하면, 쿠팡 로켓직구를 통해 미국에서 구매하면, 300정짜리가 보통 3만원 초반대를 왔다갔다합니다. 대략 1알에 백 원이 조금 안 되는 수준입니다. 바이엘코리아판 국내유통 원어데이 대비 1/4 수준에 불과하니 상당히 파격적인 가격책정이지요.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-09-28 오후 3.20.57.png&quot; data-origin-width=&quot;1820&quot; data-origin-height=&quot;860&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dn9J1b/btsJQ4QLmMh/3DEBnppbixha6VtsHEWNL0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dn9J1b/btsJQ4QLmMh/3DEBnppbixha6VtsHEWNL0/img.png&quot; data-alt=&quot;쿠팡 로켓직구 가격&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dn9J1b/btsJQ4QLmMh/3DEBnppbixha6VtsHEWNL0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdn9J1b%2FbtsJQ4QLmMh%2F3DEBnppbixha6VtsHEWNL0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1820&quot; height=&quot;860&quot; data-filename=&quot;스크린샷 2024-09-28 오후 3.20.57.png&quot; data-origin-width=&quot;1820&quot; data-origin-height=&quot;860&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;쿠팡 로켓직구 가격&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-09-28 오후 3.22.23.png&quot; data-origin-width=&quot;1822&quot; data-origin-height=&quot;982&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o4q0J/btsJPLEWNsZ/wKg1KylFB9SOtmbIqyMlQK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o4q0J/btsJPLEWNsZ/wKg1KylFB9SOtmbIqyMlQK/img.png&quot; data-alt=&quot;바이엘코리아 정발판 네이버 쇼핑 가격&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o4q0J/btsJPLEWNsZ/wKg1KylFB9SOtmbIqyMlQK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo4q0J%2FbtsJPLEWNsZ%2FwKg1KylFB9SOtmbIqyMlQK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1822&quot; height=&quot;982&quot; data-filename=&quot;스크린샷 2024-09-28 오후 3.22.23.png&quot; data-origin-width=&quot;1822&quot; data-origin-height=&quot;982&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;미국 아마존에서도 200정짜리가 17.48달러쯤으로 1정당 0.09달러, 120원 정도가 나오는데다 이건 배대지까지 써야 하기 때문에, 그냥 쿠팡 로켓직구로 사는 편이 가성비가 좋습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-09-28 오후 3.23.58.png&quot; data-origin-width=&quot;1624&quot; data-origin-height=&quot;830&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2736x/btsJReltX7e/BkD4WvTE8OO1r4WotUMKpk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2736x/btsJReltX7e/BkD4WvTE8OO1r4WotUMKpk/img.png&quot; data-alt=&quot;아마존 가격(미국 내 배송만 가능)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2736x/btsJReltX7e/BkD4WvTE8OO1r4WotUMKpk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2736x%2FbtsJReltX7e%2FBkD4WvTE8OO1r4WotUMKpk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1624&quot; height=&quot;830&quot; data-filename=&quot;스크린샷 2024-09-28 오후 3.23.58.png&quot; data-origin-width=&quot;1624&quot; data-origin-height=&quot;830&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;원어데이라는 이름처럼 1일 1알 정도 먹는 것을 전제로 설계되었고, 다양한 영양소들을 대략 일일권장량 수준으로 맞춰 넣은 종합비타민입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보시는 바와 같이 대충 100% 근처에 맞춰 성분이 설계되어 있기 때문에, 특정 성분의 과량투여(오버도스)를 원하는 극단적인 케이스에는 맞지 않을 수 있습니다. 이 경우에는 쏜리서치 제품처럼 고함량 비타민을 선택하는 게 좋겠습니다.&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비타민&amp;nbsp;A&amp;nbsp;(베타카로틴으로서&amp;nbsp;10%)&amp;nbsp;900&amp;nbsp;mcg,&amp;nbsp;일일권장치의&amp;nbsp;100%&lt;/li&gt;
&lt;li&gt;비타민&amp;nbsp;C&amp;nbsp;99&amp;nbsp;mg,&amp;nbsp;일일권장치의&amp;nbsp;110%&lt;/li&gt;
&lt;li&gt;비타민&amp;nbsp;D&amp;nbsp;25&amp;nbsp;mcg&amp;nbsp;(1000&amp;nbsp;IU),&amp;nbsp;일일권장치의&amp;nbsp;125%&lt;/li&gt;
&lt;li&gt;비타민&amp;nbsp;E&amp;nbsp;15&amp;nbsp;mg,&amp;nbsp;일일권장치의&amp;nbsp;100%&lt;/li&gt;
&lt;li&gt;티아민&amp;nbsp;(B₁)&amp;nbsp;1.32&amp;nbsp;mg,&amp;nbsp;일일권장치의&amp;nbsp;110%&lt;/li&gt;
&lt;li&gt;리보플라빈&amp;nbsp;(B₂)&amp;nbsp;1.43&amp;nbsp;mg,&amp;nbsp;일일권장치의&amp;nbsp;110%&lt;/li&gt;
&lt;li&gt;나이아신&amp;nbsp;17.6&amp;nbsp;mg,&amp;nbsp;일일권장치의&amp;nbsp;110%&lt;/li&gt;
&lt;li&gt;비타민&amp;nbsp;B₆&amp;nbsp;2.17&amp;nbsp;mg,&amp;nbsp;일일권장치의&amp;nbsp;128%&lt;/li&gt;
&lt;li&gt;엽산 400 mcg DFE (엽산으로서 240 mcg), 일일권장치의 100%&lt;/li&gt;
&lt;li&gt;비타민&amp;nbsp;B₁₂&amp;nbsp;6.24&amp;nbsp;mcg,&amp;nbsp;일일권장치의&amp;nbsp;260%&lt;/li&gt;
&lt;li&gt;비오틴&amp;nbsp;43&amp;nbsp;mcg,&amp;nbsp;일일권장치의&amp;nbsp;143%&lt;/li&gt;
&lt;li&gt;판토텐산&amp;nbsp;15.5&amp;nbsp;mg,&amp;nbsp;일일권장치의&amp;nbsp;310%&lt;/li&gt;
&lt;li&gt;칼슘&amp;nbsp;210&amp;nbsp;mg,&amp;nbsp;일일권장치의&amp;nbsp;16%&lt;/li&gt;
&lt;li&gt;철분&amp;nbsp;0&amp;nbsp;mg,&amp;nbsp;일일권장치의&amp;nbsp;0%&lt;/li&gt;
&lt;li&gt;요오드&amp;nbsp;150&amp;nbsp;mcg,&amp;nbsp;일일권장치의&amp;nbsp;100%&lt;/li&gt;
&lt;li&gt;마그네슘&amp;nbsp;120&amp;nbsp;mg,&amp;nbsp;일일권장치의&amp;nbsp;29%&lt;/li&gt;
&lt;li&gt;아연&amp;nbsp;11&amp;nbsp;mg,&amp;nbsp;일일권장치의&amp;nbsp;100%&lt;/li&gt;
&lt;li&gt;셀레늄&amp;nbsp;55&amp;nbsp;mcg,&amp;nbsp;일일권장치의&amp;nbsp;100%&lt;/li&gt;
&lt;li&gt;구리&amp;nbsp;0.9&amp;nbsp;mg,&amp;nbsp;일일권장치의&amp;nbsp;100%&lt;/li&gt;
&lt;li&gt;망간&amp;nbsp;2.3&amp;nbsp;mg,&amp;nbsp;일일권장치의&amp;nbsp;100%&lt;/li&gt;
&lt;li&gt;크롬&amp;nbsp;35&amp;nbsp;mcg,&amp;nbsp;일일권장치의&amp;nbsp;100%&lt;/li&gt;
&lt;li&gt;라이코펜 300 mcg (일일권장치 없음)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;성분&lt;/b&gt;:&lt;br /&gt;칼슘 카보네이트, 마그네슘 옥사이드, 미세결정 셀룰로오스, 아스코르브산, 말토덱스트린, &lt;span&gt;dl-&amp;alpha;-&lt;/span&gt;토코페릴 아세테이트 (2% 미만: 베타카로틴), 비오틴, 콜레칼시페롤, 크롬 클로라이드, 황산구리, 가교카복시메틸셀룰로스나트륨, 시아노코발라민, D-칼슘 판토테네이트, 엽산, 젤라틴, 하이드록시프로필 메틸셀룰로오스, 이눌린, 라이코펜, 황산 망간, 중쇄 트리글리세라이드, 니코틴아마이드, 폴리비닐폴리피롤리돈, 아이오딘화 칼륨, 피리독신 하이드로클로라이드, 리보플라빈, 이산화 규소, 셀레나이트 나트륨, 스테아르산, 티아민 모노니트레이트, 비타민 A 아세테이트, 산화아연&lt;/p&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;&lt;b&gt;우먼스(여성용):&lt;/b&gt; &lt;b&gt;영양성분표&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비타민&amp;nbsp;A&amp;nbsp;700&amp;nbsp;mcg,&amp;nbsp;일일권장치의&amp;nbsp;78%&lt;/li&gt;
&lt;li&gt;비타민&amp;nbsp;C&amp;nbsp;90&amp;nbsp;mg,&amp;nbsp;일일권장치의&amp;nbsp;100%&lt;/li&gt;
&lt;li&gt;비타민&amp;nbsp;D&amp;nbsp;25&amp;nbsp;mcg&amp;nbsp;(1000&amp;nbsp;IU),&amp;nbsp;일일권장치의&amp;nbsp;125%&lt;/li&gt;
&lt;li&gt;비타민&amp;nbsp;E&amp;nbsp;15&amp;nbsp;mg,&amp;nbsp;일일권장치의&amp;nbsp;100%&lt;/li&gt;
&lt;li&gt;티아민&amp;nbsp;(B₁)&amp;nbsp;2.4&amp;nbsp;mg,&amp;nbsp;일일권장치의&amp;nbsp;200%&lt;/li&gt;
&lt;li&gt;리보플라빈&amp;nbsp;(B₂)&amp;nbsp;1.95&amp;nbsp;mg,&amp;nbsp;일일권장치의&amp;nbsp;150%&lt;/li&gt;
&lt;li&gt;나이아신&amp;nbsp;24&amp;nbsp;mg,&amp;nbsp;일일권장치의&amp;nbsp;150%&lt;/li&gt;
&lt;li&gt;비타민&amp;nbsp;B₆&amp;nbsp;3.4&amp;nbsp;mg,&amp;nbsp;일일권장치의&amp;nbsp;200%&lt;/li&gt;
&lt;li&gt;엽산 605 mcg DFE (엽산으로서 400 mcg), 일일권장치의 166%&lt;/li&gt;
&lt;li&gt;비타민&amp;nbsp;B₁₂&amp;nbsp;9.6&amp;nbsp;mcg,&amp;nbsp;일일권장치의&amp;nbsp;400%&lt;/li&gt;
&lt;li&gt;비오틴&amp;nbsp;45&amp;nbsp;mcg,&amp;nbsp;일일권장치의&amp;nbsp;150%&lt;/li&gt;
&lt;li&gt;판토텐산&amp;nbsp;7.5&amp;nbsp;mg,&amp;nbsp;일일권장치의&amp;nbsp;150%&lt;/li&gt;
&lt;li&gt;칼슘&amp;nbsp;130&amp;nbsp;mg,&amp;nbsp;일일권장치의&amp;nbsp;10%&lt;/li&gt;
&lt;li&gt;철분&amp;nbsp;18&amp;nbsp;mg,&amp;nbsp;일일권장치의&amp;nbsp;100%&lt;/li&gt;
&lt;li&gt;요오드&amp;nbsp;150&amp;nbsp;mcg,&amp;nbsp;일일권장치의&amp;nbsp;100%&lt;/li&gt;
&lt;li&gt;마그네슘&amp;nbsp;42&amp;nbsp;mg,&amp;nbsp;일일권장치의&amp;nbsp;10%&lt;/li&gt;
&lt;li&gt;아연&amp;nbsp;8&amp;nbsp;mg,&amp;nbsp;일일권장치의&amp;nbsp;73%&lt;/li&gt;
&lt;li&gt;셀레늄&amp;nbsp;41&amp;nbsp;mcg,&amp;nbsp;일일권장치의&amp;nbsp;75%&lt;/li&gt;
&lt;li&gt;구리&amp;nbsp;1.35&amp;nbsp;mg,&amp;nbsp;일일권장치의&amp;nbsp;150%&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;성분&lt;/b&gt;: &lt;br /&gt;칼슘 카보네이트, 미세결정 셀룰로오스, 아스코르브산, 마그네슘 옥사이드, 푸마르산 철, &lt;span&gt;dl-&amp;alpha;-&lt;/span&gt;토코페릴 아세테이트, 니코틴아마이드, 젤라틴, 말토덱스트린; 2% 미만: 비오틴, 콜레칼시페롤, 색소 (리보플라빈, 이산화 티타늄, 채소 주스), 황산 구리, 옥수수 전분, 크로스카멜로오스 나트륨, 시아노코발라민, D-칼슘 판토테네이트, 엽산, 구아검, 하이드록시프로필 메틸셀룰로오스, 중쇄 트리글리세리드, 폴리비닐 알코올, 아이오딘화 칼륨, 피리독신 하이드로클로라이드, 리보플라빈, 이산화 규소, 셀레나이트 나트륨, 스테아르산, 탈크, 티아민 모노니트레이트, 비타민 A 아세테이트, 산화 아연&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로켓직구 상품이기 때문에 배송도 상당히 빠릅니다. 저는 9월 9일에 주문해서 9월 12일에 받았습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_Photo_2024-09-28-15-19-51.jpeg&quot; data-origin-width=&quot;648&quot; data-origin-height=&quot;1185&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b04A01/btsJPBQfkth/awdhXszjsKPLK72hbX3eqk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b04A01/btsJPBQfkth/awdhXszjsKPLK72hbX3eqk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b04A01/btsJPBQfkth/awdhXszjsKPLK72hbX3eqk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb04A01%2FbtsJPBQfkth%2FawdhXszjsKPLK72hbX3eqk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;648&quot; height=&quot;1185&quot; data-filename=&quot;KakaoTalk_Photo_2024-09-28-15-19-51.jpeg&quot; data-origin-width=&quot;648&quot; data-origin-height=&quot;1185&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;300알이나 들어있는 만큼 꽤 묵직한 통에 담겨 옵니다. 동성 정로환 통과 비교하면 이 정도 사이즈.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_Photo_2024-09-28-16-16-04.jpeg&quot; data-origin-width=&quot;1387&quot; data-origin-height=&quot;1042&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Jhhz0/btsJPMDO5vO/KF5KxTw0sxKQCAE6pNs6zK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Jhhz0/btsJPMDO5vO/KF5KxTw0sxKQCAE6pNs6zK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Jhhz0/btsJPMDO5vO/KF5KxTw0sxKQCAE6pNs6zK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJhhz0%2FbtsJPMDO5vO%2FKF5KxTw0sxKQCAE6pNs6zK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1387&quot; height=&quot;1042&quot; data-filename=&quot;KakaoTalk_Photo_2024-09-28-16-16-04.jpeg&quot; data-origin-width=&quot;1387&quot; data-origin-height=&quot;1042&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개인적으로는 속쓰림이 없다는 점이 제일 좋았던 것 같습니다. 예전에 먹었던 미국판 센트룸은 밥을 먹고 먹더라도 속쓰림이 있었는데, 원어데이는 공복에 먹어도 괜찮았습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 제품은 아래의 링크를 눌러 로켓직구로 구매할 수 있습니다. 쿠팡 와우회원이 아니어도 한국까지 무료배송입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://link.coupang.com/a/bTWbbe&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;https://image6.coupangcdn.com/image/affiliate/banner/20df31cb28882a179f21694e16ad7157@2x.jpg&quot; alt=&quot;원어데이 멘스 컴플리트 멀티비타민 타블렛, 1개, 300정&quot; width=&quot;120&quot; height=&quot;240&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://link.coupang.com/a/bTWJlD&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;https://image2.coupangcdn.com/image/affiliate/banner/d3c94a7abade9e74882f915f2d94d9d4@2x.jpg&quot; alt=&quot;원어데이 우먼스 포뮬러 멀티비타민 타블렛, 1개, 300정&quot; width=&quot;120&quot; height=&quot;240&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;※ 위의 링크는 &quot;쿠팡 파트너스&quot; 링크입니다. 이것을 눌러서 구매하시면 쿠팡에서 제게 일정액의 수수료를 지급합니다.&lt;br /&gt;&lt;/i&gt;&lt;br /&gt;&lt;i&gt;그렇지만 어차피 링크를 타고 가서 구매하든, 아니면 쿠팡에 직접 검색해서 구매하든 기본적으로 가격에는 차이가 없기 때문에, 여러분이 손해볼 것은 딱히 없습니다. 감사합니다.&lt;br /&gt;&lt;/i&gt;&lt;/p&gt;</description>
      <category>기타</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/111</guid>
      <comments>https://pscr.tistory.com/111#entry111comment</comments>
      <pubDate>Sat, 28 Sep 2024 16:19:42 +0900</pubDate>
    </item>
    <item>
      <title>Linux와 GNU/Linux 템플릿 밈</title>
      <link>https://pscr.tistory.com/109</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;리눅스 배포판들을 &quot;GNU/Linux&quot;라고 불러야 하나, &quot;Linux&quot;라고 불러도 상관없냐, 라는 논쟁은 거의 30년은 된 퀘퀘묵은 떡밥입니다. 오늘날 대부분의 배포판들은 그냥 Linux라는 이름을 사용하지만, 데비안(Debian GNU/Linux) 처럼 GNU/Linux 표기를 쓰는 유명 배포판도 남아 있지요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영어권 리눅스 커뮤니티에서는 이런 논쟁에 으레 등장하는 오래된 copypasta(템플릿 밈)이 있습니다. (흔히 맨 처음 부분을 따서 &lt;a href=&quot;https://wiki.installgentoo.com/index.php/Interjection&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;I'd just like to interject for a moment&lt;/a&gt;라고 부릅니다) 아래에 해당 밈의 원문과 번역을 같이 싣었습니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;잠시 좀 끼어들겠습니다. 여러분이 Linux라고 부르는 것은 사실 GNU/Linux 내지는 GNU 플러스 Linux(최근에 제가 사용하기 시작한 명칭입니다)입니다. Linux는 그 자체로는 운영 체제가 아닙니다. Linux는 GNU의 corelibs・셸 유틸리티・중요 시스템 컴포넌트의 힘으로 사용성을 얻고, POSIX에 정의된 바에 따라 완전한 OS를 구성하는 GNU 시스템에 있어, 또 하나의 자유 컴포넌트에 지나지 않습니다.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;I'd just like to interject for a moment. What you're referring to as Linux, is in fact, GNU/Linux, or as I've recently taken to calling it, GNU plus Linux. Linux is not an operating system unto itself, but rather another free component of a fully functioning GNU system made useful by the GNU corelibs, shell utilities and vital system components comprising a full OS as defined by POSIX.&lt;/i&gt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;많은 컴퓨터 사용자들이 그 사실을 알지도 못한 채로 GNU 시스템의 수정된 판본을 매일 구동하고 있습니다. 해괴한 일들이 여럿 일어난 탓에 세간에서 오늘날 널리 사용되는 그 GNU 시스템의 판본을 &quot;Linux&quot;라고 부르는 일이 많으며, 사용자들 중 다수가 이것이 GNU 프로젝트에서 개발한 GNU 시스템이라는 사실을 인지하지 못하고 있습니다.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Many computer users run a modified version of the GNU system every day, without realizing it. Through a peculiar turn of events, the version of GNU which is widely used today is often called &amp;ldquo;Linux,&amp;rdquo; and many of its users are not aware that it is basically the GNU system, developed by the GNU Project. There really is a Linux, and these people are using it, but it is just a part of the system they use. &lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Linux라는 것은 존재하며, 아까 말한 그 사람들은 실제로 Linux를 사용하는 것이 맞기는 합니다. 하지만 그건 그들이 이용하는 시스템의 한 부품에 불과합니다. Linux는 커널입니다: 시스템의 자원을 여러분이 구동하는 다른 프로그램에게 할당하는 시스템 내부의 프로그램 말입니다. 커널은 운영체제에 있어 중요한 부품이지만, 그 자체로는 쓸모가 없습니다. 커널은 오직 완전한 운영체제라는 배경에서만 기능할 수 있습니다. Linux는 일반적으로 GNU 운영체제와 결합되어 사용되며, 따라서 그 전체 시스템은 근본적으로 GNU에 Linux가 더해진 것이며, 혹은 GNU/Linux라고도 하겠습니다. 소위 &quot;Linux&quot; 배포판이라는 것들은 실제로는 모두 GNU/Linux 배포판입니다.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Linux is the kernel: the program in the system that allocates the machine's resources to the other programs that you run. The kernel is an essential part of an operating system, but useless by itself; it can only function in the context of a complete operating system. Linux is normally used in combination with the GNU operating system: the whole system is basically GNU with Linux added, or GNU/Linux. All the so-called &amp;ldquo;Linux&amp;rdquo; distributions are really distributions of GNU/Linux.&lt;/i&gt;&lt;/blockquote&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.gnu.org/gnu/incorrect-quotation.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;자기가 쓴 글이 아니라고 부정했&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;또 위 copypasta에 대한 반론을 담고 있는 copypasta도 있습니다. 보통 누가 위의 copypasta를 달면 으레 아래의 copypasta를 들고옵니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;아니에요, 리처드. &quot;Linux&quot;지 &quot;GNU/Linux&quot;가 아니랍니다. FSF(자유 소프트웨어 재단)이 Linux에 대해 만든 가장 중요한 기여를 꼽으라면 GPL과 GCC 컴파일러를 꼽을 수 있습니다. 이들은 잘 만들어졌고 훌륭한 제품들입니다. GCC는 그야말로 기념비적인 업적이라고 할 수 있으며 당신 RMS(리처드 매튜 스톨먼)와 자유 소프트웨어 재단이 무수한 찬사와 감사를 받게 했습니다.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;No, Richard, it's 'Linux', not 'GNU/Linux'. The most important contributions that the FSF made to Linux were the creation of the GPL and the GCC compiler. Those are fine and inspired products. GCC is a monumental achievement and has earned you, RMS, and the Free Software Foundation countless kudos and much appreciation.&lt;/i&gt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;다음은 당신의 FAQ에서 답변한 내용을 일부 포함해서, 당신이 생각해 봐야 할 이유 몇 가지입니다.&lt;br /&gt;&lt;i&gt;Following are some reasons for you to mull over, including some already answered in your FAQ.&lt;/i&gt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;리누스 토르발스라는 사람이 운영체제(그래요, 리눅스는 OS가 맞습니다. 자세한 건 이 뒤에 설명)를 만들기 위해 GCC를 사용했습니다. 그의 친구들의 도움을 조금 받아 이를 'Linux'라고 이름붙였지요. 왜 그가 이 운영체제를 GNU/Linux라고 부르지 않냐고요? 그가 당신이 아니라 그의 친구들의 도움을 더 많이 받아 이걸 만들었으니까요. 당신은 당신이 만든 거에 이름을 붙이고, 나는 내가 만든 거(GCC를 이용해 작성한 소프트웨어를 포함해서)에 이름을 붙이고, 리누스는 리누스가 만든 거에 이름을 붙이는 겁니다. 리누스 토르발즈가 리눅스가 맞다고 했으니 올바른 이름은 그게 맞습니다. 리누스가 그렇게 말했습니다. 그의 권위를 인정하세요. 그렇지 않으면 떼쟁이(nag)가 되는 겁니다. 세상에 떼쟁이로 소문나고 싶지는 않겠지요?&lt;br /&gt;&lt;br /&gt;&lt;i&gt;One guy, Linus Torvalds, used GCC to make his operating system (yes, Linux is an OS -- more on this later). He named it 'Linux' with a little help from his friends. Why doesn't he call it GNU/Linux? Because he wrote it, with more help from his friends, not you. You named your stuff, I named my stuff -- including the software I wrote using GCC -- and Linus named his stuff. The proper name is Linux because Linus Torvalds says so. Linus has spoken. Accept his authority. To do otherwise is to become a nag. You don't want to be known as a nag, do you?&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;(운영체제) != (배포판)입니다. Linux는 운영체제입니다. 나는 운영체제를 소프트웨어에 컴퓨터의 하드웨어 자원에 대한 접근을 제공하고 또 제한하는 소프트웨어로써 정의합니다. 이 정의는 Linux가 사용되는 어디에서든 적용됩니다. 하지만, Linux는 일반적으로 이를 데스크톱 시스템이나 서버, 개발용 도구, 그래픽 워크스테이션 내지는 사용자가 필요로 하는 용도에 맞춰 쉽게 구성할 수 있도록 여러 유틸리티와 애플리케이션과 함께 배포됩니다. 이러한 구성을 우리는 리눅스 (기반) 배포판이라고 합니다. 당신이 우기는 이름 'GNU/Linux'에 대한 가장 큰 논거가 바로 이것일 것입니다 (번들된 소프트웨어 중 많은 수를 FSF에서 만들었기 때문에). 그럼 배포판 제작사에 그렇게 말하세요. Red Hat, Mandrake, Slackware에 가서 그렇게 말하세요. 최소한 그쪽에서는 논쟁의 여지라도 있을 겁니다. Linux는 아무 GNU 소프트웨어 없이도 그 자체만으로도 다양한 사용 용도에 적용할 수 있는 운영체제입니다. 임베디드 환경이 대표적인 예입니다.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;(An operating system) != (a distribution). Linux is an operating system. By my definition, an operating system is that software which provides and limits access to hardware resources on a computer. That definition applies whereever you see Linux in use. However, Linux is usually distributed with a collection of utilities and applications to make it easily configurable as a desktop system, a server, a development box, or a graphics workstation, or whatever the user needs. In such a configuration, we have a Linux (based) distribution. Therein lies your strongest argument for the unwieldy title 'GNU/Linux' (when said bundled software is largely from the FSF). Go bug the distribution makers on that one. Take your beef to Red Hat, Mandrake, and Slackware. At least there you have an argument. Linux alone is an operating system that can be used in various applications without any GNU software whatsoever. Embedded applications come to mind as an obvious example.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;다음으로, GNU/Linux라는 이름을 GNU 기반 리눅스 배포판에 한정짓는다고 해도, 또 다른 명백한 문제에 부닥치게 될 것입니다. 특정한 Linux 환경에서는 모든 GNU 기여분을 합쳐도 XFree86이 더 중요할 수도 있습니다. 그럼 이 배포판은 XFree86/Linux라고 불러야 맞을까요? 아니면, 최소한 XFree86/GNU/Linux라고 할까요? 다른 좋은 기여분들을 이름에 올릴지 말지의 선을 긋는 것은 물론 굉장히 자의적인 것입니다. 그래요, 아마 이 얘기를 전에도 들어봤을 거란 걸 압니다. 익숙해지시길 바라요. 여기에 완벽히 반박할 수 있게 되기 전까지는 계속 듣게 될 겁니다.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Next, even if we limit the GNU/Linux title to the GNU-based Linux distributions, we run into another obvious problem. XFree86 may well be more important to a particular Linux installation than the sum of all the GNU contributions. More properly, shouldn't the distribution be called XFree86/Linux? Or, at a minimum, XFree86/GNU/Linux? Of course, it would be rather arbitrary to draw the line there when many other fine contributions go unlisted. Yes, I know you've heard this one before. Get used to it. You'll keep hearing it until you can cleanly counter it.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;당신은 코드 줄 수(Line-of-code, LoC) 지표를 좋아하는 것 같습니다. 일반적인 Linux 배포판에는 GNU 코드 라인 수가 많이 들어 있습니다. 당신은 (더 많은 LoC) == (더 중요함)이라고 생각하는 것 같더군요. 하지만, 나는 LoC의 수가 중요성과 직접적으로 연관되지 않는다는 의견을 개진하고자 합니다. 나는 해당 코드에서 소모되는 클럭 사이클이 더 나은 지표라는 것을 제안하고자 합니다. 예를 들어, 만약 내 시스템이 실행 시간의 90%를 XFree86 코드 실행에 쓰고 있다면, 내 시스템에서 가장 중요한 코드 뭉치는 XFree86이 될 것입니다. 만약 내가 열 배 더 많은 라인 수의 코드로 구성된, 아무 쓸모없는 블로트웨어를 시스템에다가 설치한 뒤 그 블로트웨어를 한 번도 실행하지 않는다고 한다면, 분명히 그 블로트웨어보다 XFree86의 중요성이 높을 것입니다. 물론 이 지표도 완벽하지 않지만, LoC는 진짜, 진짜 구립니다. 무슨 주장을 하든 간에 다시는 LoC 지표를 쓰지 말 것을 권해드리는 바입니다.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;You seem to like the lines-of-code metric. There are many lines of GNU code in a typical Linux distribution. You seem to suggest that (more LOC) == (more important). However, I submit to you that raw LOC numbers do not directly correlate with importance. I would suggest that clock cycles spent on code is a better metric. For example, if my system spends 90% of its time executing XFree86 code, XFree86 is probably the single most important collection of code on my system. Even if I loaded ten times as many lines of useless bloatware on my system and I never excuted that bloatware, it certainly isn't more important code than XFree86. Obviously, this metric isn't perfect either, but LOC really, really sucks. Please refrain from using it ever again in supporting any argument.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;마지막으로 우리 Linux와 GNU 사용자들은 다른 사람들의 소프트웨어에 이름짓는 것 가지고 서로 싸워서는 안 된다는 점을 지적하고 싶습니다. 하지만 알 게 뭐람, 나는 지금 기분이 매우 안 좋습니다. GCC가 그렇게 유명해진 이유는, 이를 유용하게 사용할 수 있는 Linux가 개발되었기 때문이라는 얘기를 해고 싶을 정도로 불쾌합니다. 적절한 존중과 감사의 의미를 담아 당신과 다른 사람들 모두 GCC를 '리눅스 컴파일러'라고 불러야 하지 않을까요? 아니면 최소한 'Linux GCC'라든가요? 아니 정말로, Linux가 없었으면 당신의 그 걸작은 어디 갔겠습니까? 뭐 HURD 가지고 삽질하는데?&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Last, I'd like to point out that we Linux and GNU users shouldn't be fighting among ourselves over naming other people's software. But what the heck, I'm in a bad mood now. I think I'm feeling sufficiently obnoxious to make the point that GCC is so very famous and, yes, so very useful only because Linux was developed. In a show of proper respect and gratitude, shouldn't you and everyone refer to GCC as 'the Linux compiler'? Or at least, 'Linux GCC'? Seriously, where would your masterpiece be without Linux? Languishing with the HURD?&lt;/i&gt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;이 폭언 뒤에 숨겨져 있는 교훈이 있다고 한다면, 아마 이런 내용일 겁니다.&lt;br /&gt;자신의 능력과 자신의 엄청난 성공, 자신의 상당한 명성에 감사하십시오. 그 성공과 명성을 지금처럼 좋은 일에 쓰고, 나쁜 일에 쓰지 마십시오. 특히, 그 성공에 있어 Linux의 큰 기여가 있었다는 것에 감사하십시오. 당신 RMS와 자유 소프트웨어 재단, GNU 소프트웨어가 지금의 높은 명성을 얻을 수 있었던 것의 상당 부분은 Linux가 뒷받침하고 있었기 때문입니다. 당신은 세상을 바꿨습니다. 이제 떼는 그만 쓰고, 이만 가세요. 경청해 주신 데에 감사합니다.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;If there is a moral buried in this rant, maybe it is this: &lt;/i&gt;&lt;br /&gt;&lt;i&gt;Be grateful for your abilities and your incredible success and your considerable fame. Continue to use that success and fame for good, not evil. Also, be especially grateful for Linux' huge contribution to that success. You, RMS, the Free Software Foundation, and GNU software have reached their current high profiles largely on the back of Linux. You have changed the world. Now, go forth and don't be a nag. Thanks for listening.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것도 얼마나 오랫동안 인터넷의 구천을 떠돌아다닌 글인지는 알 수 없습니다. 다만 맨드레이크 리눅스나 XFree86같은 고대 유물들이 언급되는 것을 봐서 대략 1999년 ~ 00년대 초쯤에 작성된 글으로 보이기는 합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;XFree86은 90년대 초에 개발이 시작되어 2000년대 초까지 널리 사용되었던 오픈소스 X11 구현체입니다. 하지만 2004년에 라이선스를 GPL과 호환되지 않는 독자 라이선스로 바꾸면서 대부분의 배포판이 떨어져나갔고, 2008년에 개발이 중단됩니다.&lt;/li&gt;
&lt;li&gt;맨드레이크 리눅스는 1998년 11월 처음 출시되었습니다. 2005년에는 상표권 분쟁에서 져서 맨드리바 리눅스로 이름을 바꿨고 2011년에 단종되었습니다.&lt;/li&gt;
&lt;li&gt;원시 고대 리눅스 배포판 중에는 실제로 &quot;Linux/GNU/X&quot;라는 표현을 쓰는 배포판이 있었습니다(Yggdrasil Linux/GNU/X).&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>콤퓨우터/Linux</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/109</guid>
      <comments>https://pscr.tistory.com/109#entry109comment</comments>
      <pubDate>Sat, 20 Jul 2024 22:37:24 +0900</pubDate>
    </item>
    <item>
      <title>263. JSON Path</title>
      <link>https://pscr.tistory.com/108</link>
      <description>&lt;pre&gt;&lt;code&gt;{
  &amp;quot;asdf&amp;quot;: &amp;quot;bsdf&amp;quot;,
  &amp;quot;csdf&amp;quot;: [
    {
      &amp;quot;dsdf&amp;quot;: &amp;quot;esdf&amp;quot;,
      &amp;quot;fsdf&amp;quot;: &amp;quot;gsdf&amp;quot;
    }, 
    {
      &amp;quot;hsdf&amp;quot;: &amp;quot;isdf&amp;quot;,
      &amp;quot;jsdf&amp;quot;: &amp;quot;ksdf&amp;quot;
    }
  ]
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;여기에서 &amp;quot;gsdf&amp;quot;를 추출하는 JSON Path: &lt;code&gt;$.csdf[0].fsdf&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;Criteria&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;[1, 2, 10, 476, 388, 3287]&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;에서 40 이상인 수만 추출하기: &lt;code&gt;$[?(@ &amp;gt;= 40)]&lt;/code&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$&lt;/code&gt;: root element. root element상의 list이므로 거기에 &lt;code&gt;[]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;?()&lt;/code&gt;: check if&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@&lt;/code&gt;: each element&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;에서 &lt;code&gt;40, 476&lt;/code&gt;이 아닌 수만 추출하기: &lt;code&gt;$[?( @ nin [40, 476])]&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Wildcard&lt;/h3&gt;
&lt;h3&gt;Lists&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;[&amp;quot;Apple&amp;quot;, &amp;quot;Google&amp;quot;, &amp;quot;Coca-Cola&amp;quot;, &amp;quot;Samsung&amp;quot;, &amp;quot;Amazon&amp;quot;]&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;에서 &lt;code&gt;[&amp;quot;Apple&amp;quot;, &amp;quot;Coca-Cola&amp;quot;]&lt;/code&gt; 출력하기: &lt;code&gt;$[0, 2]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;에서 &lt;code&gt;[&amp;quot;Apple&amp;quot;, &amp;quot;Google&amp;quot;, &amp;quot;Coca-Cola&amp;quot;]&lt;/code&gt; 출력하기: &lt;code&gt;$[0:3]&lt;/code&gt;&lt;ul&gt;
&lt;li&gt;3이라는 데 주의&lt;/li&gt;
&lt;li&gt;&lt;code&gt;for(int i=0; i&amp;lt;3; i++)&lt;/code&gt; 같은 것&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;에서 &lt;code&gt;[&amp;quot;Apple&amp;quot;, &amp;quot;Coca-Cola&amp;quot;, &amp;quot;Amazon&amp;quot;]&lt;/code&gt; 출력하기: &lt;code&gt;$[0:6:2]&lt;/code&gt;&lt;ul&gt;
&lt;li&gt;뒤의 2는 Step by 2 (2칸씩 뛰어넘기)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;for(int i=0; i&amp;lt;6; i+=2)&lt;/code&gt; 같은 것&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;에서 &lt;code&gt;[&amp;quot;Amazon&amp;quot;]&lt;/code&gt; 출력하기: &lt;code&gt;$[-1]&lt;/code&gt;&lt;ul&gt;
&lt;li&gt;일부 implementation에서는 &lt;code&gt;$[-1:]&lt;/code&gt;으로 해야 작동하는 경우가 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Kubectl에서 사용하는 JSON Path&lt;/h1&gt;
&lt;p&gt;kubectl은 대량의 데이터를 탐색할 때 JSON Path를 사용할 수 있는 옵션을 제공한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;애초에 kubectl이 kube-apiserver에서 받아 오는 반환값 자체가 JSON 형식이다&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;사용할 kubectl 명령어 확보 (예를 들어 &lt;code&gt;kubectl get pods&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;해당 kubectl 명령어를 JSON으로 출력 (`kubectl get pods -o json)&lt;/li&gt;
&lt;li&gt;필요한 정보를 뽑아낼 JSON Path 쿼리 작성&lt;/li&gt;
&lt;li&gt;kubectl에 JSON Path과 함께 명령 (`kubectl get pods -o=jsonpath=&amp;#39;{.items[0].spec.containers[0].image})&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;여러 JSON Path 쿼리를 함께 사용할 수 있다&lt;ul&gt;
&lt;li&gt;&lt;code&gt;kubectl get nodes -o=jsonpath=&amp;#39;{.items[*].metadata.name}{items[*].status.capacity.cpu}&amp;#39;&lt;/code&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;master node01 4 4&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;{&amp;quot;\n&amp;quot;}&lt;/code&gt;이나 &lt;code&gt;{&amp;quot;\t&amp;quot;}&lt;/code&gt; 등을 넣어 출력을 예쁘게 만들 수 있다&lt;/li&gt;
&lt;li&gt;&lt;code&gt;# kubectl get nodes -o=jsonpath=&amp;#39;{.items[*].metadata.name}{&amp;quot;\n&amp;quot;}{items[*].status.capacity.cpu}&amp;#39;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;master node01&lt;br&gt;4 4&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--sort-by=.status.capcity.cpu&lt;/code&gt; 같이 JSON Path를 이용해 결과물을 소팅하는 것이 가능하다 &lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;심화: JSON Path와 Range 사용&lt;/h3&gt;
&lt;p&gt;(CKA 자격 수준에서는 필요한 내용은 아니다)&lt;/p&gt;
&lt;p&gt;대충 이런 pseudocode를 생각해보자&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
foreach N in nodes {  
print (N.metadata.name + &amp;quot;\\t&amp;quot; + N.status.capaicty.cpu + &amp;quot;\\n&amp;quot;;  
}  
/\* 출력결과:  
master 4  
node01 4  
\*/
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;이것은 kubectl의 JSON Path 표현으로는 이렇게 나타낼 수 있다&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
&amp;#39;{range .items\[\*\]}  
{.metadata.name}{&amp;quot;\\t&amp;quot;}{.status.capcity.cpu}{&amp;quot;\\n&amp;quot;}  
{end}&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;심화: Custom Column 옵션&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;-o=custom-columns=NODE:.metadata.name,CPU:.status.capacity.cpu&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
NODE CPU  
master 4  
node01 4  &lt;/code&gt;&lt;/pre&gt;</description>
      <category>콤퓨우터/필기: KodeKloud CKA 강의</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/108</guid>
      <comments>https://pscr.tistory.com/108#entry108comment</comments>
      <pubDate>Fri, 17 May 2024 00:55:57 +0900</pubDate>
    </item>
    <item>
      <title>252-261. Troubleshooting</title>
      <link>https://pscr.tistory.com/107</link>
      <description>&lt;p&gt;지도를 그려서, 모든 오브젝트와 링크를 확인해본다&lt;br&gt;(DB Pod) |DB-Service&amp;gt; (Web Pod) | Web-Service&amp;gt; User&lt;/p&gt;
&lt;p&gt;웹서비스일 경우, curl로 web-service:port를 확인해본다&lt;br&gt;&lt;code&gt;Failed to connect: Connection timed out&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;web-service의 Selector와 Endpoint 등을 확인해본다&lt;br&gt;&lt;code&gt;kubectl describe service web-service&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Pod의 label과 Service의 Selector가 일치하는지 확인해본다&lt;/p&gt;
&lt;p&gt;Pod가 running state인지 확인해본다, &lt;code&gt;kubectl get pod&lt;/code&gt;에서 RESTARTS가 누적되고 있는지 확인한다,&lt;br&gt;&lt;code&gt;kubectl describe&lt;/code&gt;와 &lt;code&gt;kubectl log&lt;/code&gt;로 상태를 확인한다&lt;br&gt;(컨테이너가 무한재시작되고 있다면 &lt;code&gt;kubectl log&lt;/code&gt;는 재시작 이후의 로그만 보여준다. 이 경우 &lt;code&gt;-f&lt;/code&gt;나 &lt;code&gt;--previous&lt;/code&gt;옵션을 이용할 것)&lt;/p&gt;
&lt;p&gt;kubernets.io/docs/tasks/debug-application-cluster/debug-application 참고&lt;/p&gt;
&lt;h1&gt;Control Plane Failure&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;일단 노드와 Pod의 상태를 확인한다.&lt;/li&gt;
&lt;li&gt;만약 kubeadm으로 컨트롤플레인을 구성하였다면, &lt;code&gt;kube-system&lt;/code&gt; 네임스페이스의 Pod의 상태를 확인한다.&lt;ul&gt;
&lt;li&gt;&lt;code&gt;kubeadm log Pod명 -n kube-system&lt;/code&gt;으로 로그를 확인한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;만약 Systemd 서비스로 컨트롤플레인 컴포넌트가 올라가 있다면,  service 상태를 확인한다.&lt;ul&gt;
&lt;li&gt;&lt;code&gt;journalctl -u 서비스명&lt;/code&gt;으로 로그를 확인한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;kubernets.io/docs/tasks/debug-application-cluster/debug-cluster 참조&lt;/p&gt;
&lt;h1&gt;Worker Node Failure&lt;/h1&gt;
&lt;p&gt;kubectl get nodes - kubectl describe node&lt;br&gt;문제를 파악하면 노드에 접속해서 해당 문제를 해결한다 (kubelet logs, certificates, )&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Conditions:
  Type                 Status    LastHeartbeatTime                 LastTransitionTime                Reason              Message
  ----                 ------    -----------------                 ------------------                ------              -------
  NetworkUnavailable   False     Sun, 12 May 2024 15:02:07 +0000   Sun, 12 May 2024 15:02:07 +0000   FlannelIsUp         Flannel is running on this node
  MemoryPressure       Unknown   Sun, 12 May 2024 15:02:33 +0000   Sun, 12 May 2024 15:04:55 +0000   NodeStatusUnknown   Kubelet stopped posting node status.
  DiskPressure         Unknown   Sun, 12 May 2024 15:02:33 +0000   Sun, 12 May 2024 15:04:55 +0000   NodeStatusUnknown   Kubelet stopped posting node status.&lt;/code&gt;&lt;/pre&gt;&lt;h1&gt;Network Failure&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://kubernetes.io/docs/concepts/cluster-administration/addons/#networking-and-network-policy&quot;&gt;https://kubernetes.io/docs/concepts/cluster-administration/addons/#networking-and-network-policy&lt;/a&gt;&lt;br&gt;쿠버 공식 문서 이외의 다른 사이트에 접속을 차단하는 CKA와 CKAD 시험 특성상 외부 도큐멘테이션을 봐야 하는 CNI 플러그인 설치 문제는 출제되지 않으며, 출제되더라도 설치를 위한 URL이 제공될 것이다.&lt;/p&gt;
&lt;h3&gt;CoreDNS in Kubernetes&lt;/h3&gt;
&lt;p&gt;쿠버에서 사용되는 CoreDNS 리소스는 다음과 같다&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;coredns (서비스)&lt;/li&gt;
&lt;li&gt;coredns, kube-dns ([[160-164. Authorisation, RBAC and Cluster Roles#Cluster Roles|cluster role]]) &lt;/li&gt;
&lt;li&gt;coredns, kube-dns (cluster role bindings)&lt;/li&gt;
&lt;li&gt;coredns (deployment)&lt;/li&gt;
&lt;li&gt;coredns (ConfigMap)&lt;/li&gt;
&lt;li&gt;coredns (Service)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>콤퓨우터/필기: KodeKloud CKA 강의</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/107</guid>
      <comments>https://pscr.tistory.com/107#entry107comment</comments>
      <pubDate>Fri, 17 May 2024 00:55:35 +0900</pubDate>
    </item>
    <item>
      <title>241. etcd in HA</title>
      <link>https://pscr.tistory.com/106</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;etcd는 분산 시스템을 채용하는 K-V 데이터베이스임&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;K-V 데이터베이스는 k-v 페어 여러 개로 구성된 페이지로 구성된다&lt;/li&gt;
&lt;li&gt;쿠버의 여러 컴포넌트 중 etcd와 직접 통신하는 컴포넌트는 kube-apiserver뿐이다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;etcd 서버는 1개만 존재할 수도 있지만, 여러 개의 분산형 구조를 할 수도 있음 (High Availability etcd 구성)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 경우 모든 etcd 서버에 같은 데이터가 저장됨
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하지만 어떻게?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선, Read operation의 경우, 모든 서버에 저장된 데이터가 동일하게 유지되므로, 아무 서버에서 Read를 하든 상관없음&lt;br /&gt;하지만, Write 시에 데이터를 어떻게 consistent하게 유지할 수 있는가?&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여러 etcd 서버 중 하나를 leader로 선출하여, write 작업이 들어오면 전부 leader로 보내버림
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;leader는 write 작업을 진행한 뒤 해당 작업을 나머지 노드(follower)들에 전파
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;나머지 노드들에 전파되었는지 leader가 확인을 받으면 write 작업이 완료&lt;/li&gt;
&lt;/ul&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;h1&gt;리더 선출&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클러스터가 시작되면, 노드별로 랜덤하게 정해진 타이머가 지난 뒤에, 리더 권한 요청을 다른 노드에게 보냄&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;한 노드로부터 리더 권한 요청을 받은 다른 노드들은, 해당 노드에 대한 리더 신임을 반환
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다른 노드들로부터 리더 신임을 받으면, 그 노드가 리더가 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리더가 선출된 뒤에도, 리더 노드는 일정 간격으로 다른 노드들에 리더를 계속하겠다는 요청을 보냄&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;만약 리더 노드가 죽어서 일정 기간이 지난 뒤에도 다른 노드들에 리더 계속 요청을 보내지 못하면, 다시 리더 선정이 시작됨&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;나머지 노드들에 전파되었는지 leader가 확인을 받으면 write 작업이 완료&quot; 라고 했다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하지만 노드 하나가 죽어서 응답이 안 오면 어떻게 할까?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;과반수가 응답했으면 해당 write 작업은 완료된 것으로 봄&lt;/li&gt;
&lt;li&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;h1&gt;정족수(Quorum)&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;write 작업이 완료 처리되기 위해 필요한 최소 응답 노드의 수: (노드수/2) + 1&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;만약 2개의 노드가 있다면 Quorum은 (2/2 + 1 =) 2이다 =&amp;gt; HA의 의미가 없다!
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;따라서 etcd의 HA 구성에서는 최소 3개의 노드가 필요하다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;etcd의 노드수는 홀수로 할 것이 권장되는데, 만약 네트워크가 쪼개지더라도 살아남을 확률이 더 높기 때문이다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예를 들어 7개 노드가 네트워크 장애로 4:3으로 쪼개지더라도 4개 쪽 클러스터는 살아남을 것이다 (Quorum=4)&lt;/li&gt;
&lt;li&gt;하지만 6개 노드가 3:3으로 쪼개지면 클러스터 둘 다 살아남지 못한다 (Quorum=4)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;실제 구성&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;etcd 바이너리를 받아서 적절한 위치 (&lt;code&gt;/usr/local/bin&lt;/code&gt;)에 놓고 적절한 설정경로(&lt;code&gt;/etc/etcd&lt;/code&gt;, &lt;code&gt;/var/lib/etcd&lt;/code&gt;)를 만들어준다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 인증서 섹션에서 공부했던 것처럼 인증서를 만들고, SystemD Service를 생성한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주의할 점은, etcd의 파라미터에, &lt;code&gt;--initial-cluster peer-1=https://peer1:2380,peer-2=https://peer2:2380&lt;/code&gt;처럼, 초기 피어 정보를 넣어주어야 한다는 것이다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치가 완료되었다면 etcdctl 명령어로 확인할 수 있다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;export ETCDCTL_API=3&lt;/code&gt; (etcd API v3 사용)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;etcdctl put name john&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;etcdctl get name&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;etcdctl get / --prefix --keys-only&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>콤퓨우터/필기: KodeKloud CKA 강의</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/106</guid>
      <comments>https://pscr.tistory.com/106#entry106comment</comments>
      <pubDate>Fri, 17 May 2024 00:53:19 +0900</pubDate>
    </item>
    <item>
      <title>230. Ingress</title>
      <link>https://pscr.tistory.com/105</link>
      <description>&lt;h1&gt;시나리오 1: 온프레&lt;/h1&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Pasted image 20240509115021.png&quot; data-origin-width=&quot;1862&quot; data-origin-height=&quot;926&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tkjxh/btsHsRM5xFJ/83onRjTdefjAGx7zge5j01/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tkjxh/btsHsRM5xFJ/83onRjTdefjAGx7zge5j01/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tkjxh/btsHsRM5xFJ/83onRjTdefjAGx7zge5j01/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ftkjxh%2FbtsHsRM5xFJ%2F83onRjTdefjAGx7zge5j01%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1862&quot; height=&quot;926&quot; data-filename=&quot;Pasted image 20240509115021.png&quot; data-origin-width=&quot;1862&quot; data-origin-height=&quot;926&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 MySQL Pod와 (3개의 Replica된 Pod으로 구성된) Deployment로 구성된 간단한 웹사이트의 구성이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;MySQL과 웹서버 간의 통신을 위해 mysql-service ClusterIP Service를 생성&lt;/li&gt;
&lt;li&gt;웹서버의 외부 노출을 위해 wear-service NodePort Service를 생성&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 구성은 작동하지만, 문제가 있다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;포트 38080을 접속하는 사용자가 꼬박꼬박 입력해주어야함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;80같이 낮은 포트는 NodePort Service에 할당할 수가 없다!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 38080 앞에 80을 listen하는 리버스프록시를 추가해서 사용자 접속을 받은 뒤 38080으로 넘겨주는 구성으로 바꿀 수 있을것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;시나리오 2: GCP&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같은 온프레 구성이 아니라, GCP같은 퍼블릭클라우드 상에서 위의 애플리케이션을 구성한다고 해 보자&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그렇다면 wear-service 서비스 종류를 NodePort가 아니라 LoadBalancer로 지정할 수도 있을 것이다
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;LoadBalancer구성에서는, 쿠버는 일단 NodePort에서처럼 높은 포트(38080같은)를 할당하지만, 동시에 GCP에 로드밸런서를 생성하도록 GCP API를 부른다&lt;/li&gt;
&lt;li&gt;GCP 로드밸런서 역시 리버스 프록시로 기능하여 클라이언트로부터 80을 listen하고 38080에 붙는다
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DNS를 해당 로드밸런서의 IP로 잡아주면 도메인:80으로 해당 사이트에 접속할 수 있을것이다&lt;/li&gt;
&lt;/ul&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;h1&gt;시나리오 3: 새로운 애플리케이션의 추가&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 시나리오를 확장하여, &lt;code&gt;my-online-store.com/watch&lt;/code&gt;에 접속했을 때 비디오 스트리밍 서비스를, &lt;code&gt;my-online-store.com/wear&lt;/code&gt;에 접속했을 때 기존의 서비스를 제공하는 시나리오를 구성해야 한다고 해 보자&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Pasted image 20240509131902.png&quot; data-origin-width=&quot;1718&quot; data-origin-height=&quot;818&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cECxtl/btsHrURm8mz/0qIx3gkkKXReTAbKbFKCsk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cECxtl/btsHrURm8mz/0qIx3gkkKXReTAbKbFKCsk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cECxtl/btsHrURm8mz/0qIx3gkkKXReTAbKbFKCsk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcECxtl%2FbtsHrURm8mz%2F0qIx3gkkKXReTAbKbFKCsk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1718&quot; height=&quot;818&quot; data-filename=&quot;Pasted image 20240509131902.png&quot; data-origin-width=&quot;1718&quot; data-origin-height=&quot;818&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기존 서비스와 새로운 비디오 스트리밍 서비스는 완전히 다른 애플리케이션이지만, 같은 클러스터의 리소스를 공유하기 위하여, 비디오 스트리밍 역시 같은 클러스터에 별도의 Deployment로 구현
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;또, 여기에 대한 새로운 LoadBalancer 서비스를 생성
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GCP는 이에 대한 새로운 로드밸런서를 배치함 (돈은 더 든다)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;게다가 같은 서브도메인을 공유하면서 URL 파라미터로 다른 서비스를 매칭시켜야 하기 때문에 로드밸런서가 또 필요함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;돈이 더 더 든다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;여기에 TLS 설정, 방화벽 설정, ... 같은 설정을 추가해야 한다고 하면 그만큼 설정을 더 잡아줘야함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;더 나은 선택지는 없을까요???&lt;/li&gt;
&lt;/ul&gt;
&lt;/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;h1&gt;Ingress로 해결&lt;/h1&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Pasted image 20240509131929.png&quot; data-origin-width=&quot;1612&quot; data-origin-height=&quot;726&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/w8yZQ/btsHqsodips/okvNv5iNssTtXon27oITd1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/w8yZQ/btsHqsodips/okvNv5iNssTtXon27oITd1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/w8yZQ/btsHqsodips/okvNv5iNssTtXon27oITd1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fw8yZQ%2FbtsHqsodips%2FokvNv5iNssTtXon27oITd1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1612&quot; height=&quot;726&quot; data-filename=&quot;Pasted image 20240509131929.png&quot; data-origin-width=&quot;1612&quot; data-origin-height=&quot;726&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ingress를 이용하면, 클러스터 내에서 다양한 서비스로 들어가는 route를 URL 기반으로 설정할 수 있다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Ingress 또한 외부로 노출해 줄 필요는 있다 (NodePort나 LoadBalancer 사용)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;어떻게 작동하는가?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 Ingress가 없다고 가정하면, URL에 따른 route나 SSL 설정 등은 nginx나 HAProxy 같은 reverse proxy를 Pod로 디플로이하여 구현할 수 있었을것이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Ingress도 사실 똑같이 동작한다!
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;먼저 nginx, haproxy 등을 디플로이하고(이것을 Ingress Controller라고 한다)&lt;/li&gt;
&lt;li&gt;그 다음에 rule들을 설정한다 (이것을 ingress resources라고 한다)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주의할 점은, Ingress Controller는 쿠버에 포함되어 있지 않다는 것이다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사실, 쿠버 1.19 이후로 Ingress의 추가개발은 중지되고 Gateway API로 대체될 예정이지만, CKA 1.29 시험에서도 Gateway API가 아니라 Ingress를 다루고 있으므로 Ingress를 잘 알아두자.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Ingress Controller의 종류&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GCP Application Load Balancer&lt;/li&gt;
&lt;li&gt;nginx&lt;/li&gt;
&lt;li&gt;haproxy, traefik, ...&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주의할 점은 Ingress Controller == nginx가 아니라는 점이다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;nginx는 Ingress Controller를 구성하는 가장 큰 구성요소이지만, Ingress Controller 그 자체는 아님
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;쿠버 클러스터 모니터링을 통해 ingress resources 변경을 감지하고 nginx 설정을 변경해주는 시스템이 탑재되어 있음&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;h1&gt;Ingress Controller의 생성&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ingress Controller의 nginx 파트는 일반적인 Deployment와 거의 같음&lt;br /&gt;차이점:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일반 NGINX 이미지가 아니라 쿠버네티스 전용 빌드를 사용&lt;/li&gt;
&lt;li&gt;nginx image와 설정값을 분리하기 위해 설정값을 담을 ConfigMap&lt;/li&gt;
&lt;li&gt;Pod의 이름과 네임스페이스를 담을 Env Var&lt;/li&gt;
&lt;li&gt;Ingress Controller에서 사용할 포트&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;spec:
  replicas: 1
  selector:
    matchLabels:
      name: nginx-ingress
  template:
     metadata;
       labels:
         name: nginx-ingress
     spec:
       containers:
         args:
         - /nginx-ingress-controller
         - --configmap=$(POD_NAMESPACE)/nginx-configuration
         env:
         - name: POD_NAME
           valueFrom:
             fieldRef:
               fieldPath: metadata.name 
         - name: POD_NAMESPACE
           # ...
        ports:
        - name: http
          containerPort: 80
        - name: https
          containerPort: 443
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또, 외부에 Ingress Controller를 노출하기 위해 NodePort 서비스를 label selector를 곁들여 생성&lt;/p&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;spec:
  type: NodePort
  #...
  selector:
    name: nginx-ingress&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로, Ingress Controller에 내장된 쿠버네티스 클러스터 모니터링 기능을 사용하기 위하여 적절한 권한이 있는 ServiceAccount를 설정하여야 함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;Ingress Resource의 생성&lt;/h1&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;모든 inbound 트래픽을 특정 애플리케이션에 전달&lt;/li&gt;
&lt;li&gt;URL별로 다른 애플리케이션에 트래픽을 라우팅&lt;/li&gt;
&lt;li&gt;서브도메인별로 다른 애플리케이션에 트래픽을 라우팅&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조합도 가능하다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서브도메인별로 다른 애플리케이션에 트래픽을 라우팅하면서 URL별 규칙을 적용하는 것도 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단한 Ingress Resource Object definition file의 예시:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;주의: 강의에서는 구버전(&lt;code&gt;extensions/v1beta1&lt;/code&gt;) Ingress 정의를 보여주고 있다. 새로운 API(&lt;code&gt;networking.k8s.io/v1&lt;/code&gt;)
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-video
spec:
backend:
  service:
    name: video-service
    port: 
      number: 80&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;시나리오 3의 해결&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;my-online-store.com/watch&lt;/code&gt;에 접속했을 때 비디오 스트리밍 서비스를, &lt;code&gt;my-online-store.com/wear&lt;/code&gt;에 접속했을 때 기존의 서비스를 제공하는 시나리오였다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Rule: domain match &lt;code&gt;www.my-online-store.com&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Path: &lt;code&gt;/wear&lt;/code&gt;, &lt;code&gt;/watch&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-wear-watch
  annotati
spec:
  rules:
  - http:
    paths:
    - path: /wear
      backend:
        service:
          name: video-service
          port: 
            number: 80

    - path: /watch
      backend:
        service:
          name: watch-service
          port: 
            number: 80&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;spec.rules.host[]&lt;/code&gt;를 명시하지 않았으므로, 이 규칙은 모든 호스트(도메인)에 대해 매칭된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;서브도메인을 이용한 라우팅&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;wear.my-online-store.com&lt;/code&gt;과 &lt;code&gt;watch.my-online-store.com&lt;/code&gt;에 대해, 각각 다른 애플리케이션에서 서비스를 제공하는 시나리오이다.&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-wear-watch-subdomains
spec:
  rules:
  - host: wear.my-online-store.com
    http:
      paths:
      - backend:
          serviceName: wear-service
          servicePort: 80

  - host: watch.my-online-store.com
    http:
      paths:
      - backend:
          serviceName: watch-service
          servicePort: 80&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;# kubectl describe ingress ingress-wear-watch -n app-space
Name:             ingress-wear-watch
Labels:           &amp;lt;none&amp;gt;
Namespace:        app-space
Address:          10.99.182.171
Ingress Class:    &amp;lt;none&amp;gt;
Default backend:  &amp;lt;default&amp;gt;
Rules:
  Host        Path  Backends
  ----        ----  --------
  *           
              /wear    wear-service:8080 (10.244.0.4:8080)
              /watch   video-service:8080 (10.244.0.5:8080)
Annotations:  nginx.ingress.kubernetes.io/rewrite-target: /
              nginx.ingress.kubernetes.io/ssl-redirect: false
Events:
  Type    Reason  Age                From                      Message
  ----    ------  ----               ----                      -------
  Normal  Sync    31s (x2 over 31s)  nginx-ingress-controller  Scheduled for sync
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;호스트가 &lt;code&gt;*&lt;/code&gt; (전체 도메인 매칭)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Default backend: &amp;lt;default&amp;gt;&lt;/code&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;path와 매칭되지 않은 요청은 &lt;code&gt;app-space/default-backend-service&lt;/code&gt;로 보내진다
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이유: &lt;code&gt;spec.template.spec.containers[].args[]&lt;/code&gt;에 &lt;code&gt;--default-backend-service=app-space/default-backend-service&lt;/code&gt;로 되어 있기 때문&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;kubectl get deployment -A -o wide
NAMESPACE       NAME                       READY   UP-TO-DATE   AVAILABLE   AGE     CONTAINERS      IMAGES                                                                                                                    SELECTOR
app-space       default-backend            1/1     1            1           116s    simple-webapp   kodekloud/ecommerce:404                                                                                                   app=default-backend
app-space       webapp-video               1/1     1            1           116s    simple-webapp   kodekloud/ecommerce:video                                                                                                 app=webapp-video
app-space       webapp-wear                1/1     1            1           116s    simple-webapp   kodekloud/ecommerce:apparels                                                                                              app=webapp-wear
ingress-nginx   ingress-nginx-controller   1/1     1            1           114s    controller      registry.k8s.io/ingress-nginx/controller:v1.1.2@sha256:28b11ce69e57843de44e3db6413e98d09de0f6688e33d4bd384002a44f78405c   app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx
kube-system     coredns                    2/2     2            2           6m40s   coredns         registry.k8s.io/coredns/coredns:v1.10.1                                                                                   k8s-app=kube-dns
&lt;/code&gt;&lt;/pre&gt;</description>
      <category>콤퓨우터/필기: KodeKloud CKA 강의</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/105</guid>
      <comments>https://pscr.tistory.com/105#entry105comment</comments>
      <pubDate>Fri, 17 May 2024 00:50:42 +0900</pubDate>
    </item>
    <item>
      <title>226-227. DNS and CoreDNS in Kubernetes</title>
      <link>https://pscr.tistory.com/104</link>
      <description>&lt;p&gt;쿠버는 기본적으로 클러스터를 설정할 때 내장 DNS 서버를 디플로이한다&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;단, 수동 구축했을 경우 이것도 수동으로 설정해주어야함&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;클러스터의 다른 노드에 Pod A와 B가 있다고 하자 &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A: IP 10.244.1.5&lt;/li&gt;
&lt;li&gt;B: IP 10.244.2.5&lt;ul&gt;
&lt;li&gt;Service b-service: 10.107.37.188&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;IP 대역이 다르므로, A와 B는 서로 다른 노드에 있을 것이다 - 하지만 별 상관이 없다, 쿠버가 정상적으로 설정되었다면 모든 클러스터 내의 Pod끼리는 스스로의 IP로 통신을 할 수 있어야 한다&lt;/p&gt;
&lt;p&gt;하지만, 대부분의 경우, b에 대한 Service를 만들어 이것으로 통신을 한다 (이 경우 b-service (NodePort, etc.))&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Service가 생성되면, 쿠버 DNS 서비스가 해당 서비스에 대한 레코드를 생성한다&lt;ul&gt;
&lt;li&gt;A  b-service  10.107.37.188&lt;/li&gt;
&lt;li&gt;이를 통해 다른 Pod에서 해당 서비스의 이름을 통해 B Pod에 접속할 수가 있다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;같은 Namespace상에서는, 그냥 서비스명으로도 접근이 가능하다&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;하지만 다른 네임스페이스의 Pod이라면, &lt;code&gt;서비스명.네임스페이스명&lt;/code&gt; 식으로 접근해야한다&lt;ul&gt;
&lt;li&gt;full FQDN은, &lt;code&gt;서비스명.네임스페이스명.svc.cluster.local&lt;/code&gt;이다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;서비스가 아니라 Pod은 어떨까?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;기본적으로는, Pod에 대해 DNS 레코드는 생성되지 않는다&lt;/li&gt;
&lt;li&gt;하지만, 원한다면 자동 레코드 생성을 활성화할 수 있다&lt;ul&gt;
&lt;li&gt;예를 들어 IP가 10.244.2.5면 &lt;code&gt;10-244-2-5&lt;/code&gt; 같이 생성&lt;ul&gt;
&lt;li&gt;풀 FQDN은 &lt;code&gt;10-244-2-5.네임스페이스명.pod.cluster.local&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;실제 구현&lt;/h1&gt;
&lt;p&gt;모든 Pod의 컨테이너의 &lt;code&gt;/etc/hosts&lt;/code&gt;에 필요한 모든 DNS 엔트리를 때려박아 수동관리하는 것은 조금 힘겨운 일이다&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;쿠버는 중앙 DNS 서버를 만들어 DNS 엔트리를 관리하고, 모든 Pod 컨테이너의 &lt;code&gt;/etc/resolv.conf&lt;/code&gt;에 해당 DNS 서버의 IP를 집어넣는다&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이 &amp;quot;중앙 DNS 서버&amp;quot;는 구버전에서는 &lt;code&gt;kube-dns&lt;/code&gt;였으나, 쿠버 1.12부터는 CoreDNS로 변경되었다&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CoreDNS는 클러스터에 Pod으로 배포된다&lt;ul&gt;
&lt;li&gt;사실 Pod&lt;strong&gt;s&lt;/strong&gt;로 배포된다 - 2개가 한 쌍인 Deployment로 배포되기 때문&lt;ul&gt;
&lt;li&gt;아무튼 Pod은 Pod이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/etc/coredns/Corefile&lt;/code&gt; 설정파일을 이용&lt;ul&gt;
&lt;li&gt;각 행 맨 앞의 errors니, health니, kubernetes니 하는 것은 전부 CoreDNS의 plugin이다&lt;ul&gt;
&lt;li&gt;CoreDNS는 kubernetes 플러그인을 통해 쿠버와 상호작용함?&lt;ul&gt;
&lt;li&gt;또 여기에서 클러스터의 TLD가 결정됨 (cluster.local)&lt;ul&gt;
&lt;li&gt;따라서 이 하위에 있는 모든 레코드는 이 TLD하위에 들어가게됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pods insecure&lt;/code&gt;: Pod에 대해서도 DNS 레코드를 생성하는 옵션 (기본값: 비활성화)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;proxy . /etc/resolv.conf&lt;/code&gt;: CoreDNS가 모르는 도메인은 기본 네임서버로 넘겨버림&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;이 설정파일은 Pod에 ConfigMap으로 전달됨&lt;pre&gt;&lt;code&gt;.:53 {
errors
health
kubernetes cluster.local in-addr.arpa ip6.arpa {
 pods insecure
 fallthrough in-addr.arpa ip6.arpa
 ttl 30
}
prometheus :9153
forward . /etc/resolv.conf {
 max_concurrent 1000
}
cache 30
loop
reload
loadbalance
}&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;다른 Pod들은 어떻게 CoreDNS 서버에 DNS쿼리를 쏘는가?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;자동 생성된 Service를 이용&lt;ul&gt;
&lt;li&gt;기본값은 &lt;code&gt;kube-dns&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;이 서비스의 IP가 새로 생성되는 Pod에 대해 기본 resolver (네임서버)로 들어가게 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이걸 누가 설정해주는가?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;대 황 k u b e l e t&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Kubelet 설정파일을 보면 이것을 담당하는 설정파일인 clusterDNS와 clisterDomain 엔트리를 볼 수 있다&lt;/p&gt;
&lt;h3&gt;짧은 형태의 도메인&lt;/h3&gt;
&lt;p&gt;그런데 host나 nslookup으로 짧은 형태의 도메인 (예를 들어 b-service)를 쿼리해 보면, 반환값이 FQDN이 되는 것을 볼 수 있다&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# kubectl exec hr -- nslookup mysql.payroll
Server:         10.96.0.10
Address:        10.96.0.10#53

Name:   mysql.payroll.svc.cluster.local
Address: 10.102.178.7&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;왜째서인가?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;기본적으로 Pod에 설정되는 resolv.conf 내용은 네임서버만 있는 것이 아니다&lt;/li&gt;
&lt;li&gt;&lt;code&gt;search default.svc.cluster local svc.cluster.local cluster.local&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;따라서 자동으로 긴 형태의 도메인이 쿼리될수있는것이다&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;p&gt;A &lt;strong&gt;search domain&lt;/strong&gt; is a domain used as part of a domain search list. The search list, as well as the local domain name, is used by a &lt;a href=&quot;https://en.wikipedia.org/wiki/Domain_Name_System#DNS_resolvers&quot; title=&quot;Domain Name System&quot;&gt;resolver&lt;/a&gt; to create a &lt;a href=&quot;https://en.wikipedia.org/wiki/Fully_qualified_domain_name&quot; title=&quot;Fully qualified domain name&quot;&gt;fully qualified domain name (FQDN)&lt;/a&gt; from a relative name.&lt;a href=&quot;https://en.wikipedia.org/wiki/Search_domain#cite_note-ietf_spec_dn_cf-1&quot;&gt;1&lt;/a&gt; For this purpose, the local domain name functions as a single-item search list.&lt;br&gt;-&lt;em&gt;Wikipedia&lt;/em&gt;&lt;/p&gt;
&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt;</description>
      <category>콤퓨우터/필기: KodeKloud CKA 강의</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/104</guid>
      <comments>https://pscr.tistory.com/104#entry104comment</comments>
      <pubDate>Fri, 17 May 2024 00:48:45 +0900</pubDate>
    </item>
    <item>
      <title>223. Service Networking</title>
      <link>https://pscr.tistory.com/103</link>
      <description>&lt;p&gt;쿠버에서 Pod이 다른 Pod와 자유롭게 통신할 수 있도록 되어 있다고 해도, 이걸 직접 통신하는 데 사용하는 일은 잘 없다&lt;br&gt;보통은 Service를 사용하는 게 일반적 &lt;/p&gt;
&lt;p&gt;예를 들어 같은 노드에 있는 Pod A (10.244.1.2)와 Pod B(10.244.1.3)이 있다고 하자&lt;br&gt;Pod A에서 Pod B에 접속할 때, 10.244.1.3으로 그냥 IP 입력해서 접속하는 것도 가능은 하다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;하지만 보통은, B 접속용 서비스를 생성하고 그 서비스의 이름이나 IP로 접속을 한다&lt;ul&gt;
&lt;li&gt;서비스는, Pod이 어떤 노드에 있던간에, 클러스터의 모든 노드에서 접속이 가능하다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;(ClusterIP): 클러스터 내부에서만 접속이 가능하다&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;클러스터 내부에서만 접속 가능하면 되는 시나리오 (DB 서버라든가)에 적합&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;(NodePort): ClusterIP의 기능을 모두 하는 동시에, 모든 노드의 포트를 열고 앱을 연결해줌&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;그러니까, 어떤 노드로든 NordPort에서 연 포트로 inbound 패킷이 들어오면, NodePort에 연결된 Pod로 리다이렉트됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;어떻게 작동하는가&lt;/h1&gt;
&lt;p&gt;모든 쿠버 노드에서는 Kubelet이 돌아간다&lt;br&gt;Kubelet은 kube-apiserver를 통해 노드에 대한 변경사항을 감지하고, 새로운 Pod이 생성되어야 할 때 Pod 생성을 진행한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pod를 생성하였으면, 해당 Pod에 대한 네트워크를 구성하기 위해 CNI 플러그인을 인보크한다&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;또, 모든 쿠버 노드에서는 kube-proxy가 돌아간다&lt;br&gt;kube-proxy는 kube-apiserver를 통해 클러스터의 변경사항을 감지하고, 새로운 서비스가 생성되어야 할 때 서비스 생성을 진행한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pod랑은 달리 서비스는 각 노드&amp;quot;에&amp;quot; 생성되거나, 노드&amp;quot;에&amp;quot; 할당되는 것이 아니다&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;서비스는 클러스터 단위&lt;/strong&gt;로 돌아감 - 클러스터의 모든 노드에 공존함&lt;ul&gt;
&lt;li&gt;(사실 &amp;quot;존재&amp;quot;하는 것조차 아님, 해당 서비스에 대해 listen을 하는 서버, 프로세스, 네임스페이스 따위는 존재하지 않음!)&lt;ul&gt;
&lt;li&gt;예를 들어 서비스가 iptables을 사용한다고 가정하면, 그냥 모든 노드에 있는 kube-proxy가 똑같은 iptables DNAT rule을 추가하는 것뿐임&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;p&gt;쿠버에서 서비스 오브젝트를 생성할 때, 기 지정된 범위의 IP 주소가 할당됨&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;각 노드에서 구동되는 kube-proxy가 해당 IP 주소를 받아, 클러스터의 각 노드에 forwarding rule을 생성&lt;ul&gt;
&lt;li&gt;&amp;quot;이 IP:port 구성으로 들어오는 inbound 트래픽은 전부 이 Pod의 IP로 갈 것&amp;quot;&lt;ul&gt;
&lt;li&gt;이것을 구현하기 위해 방법이 여러 가지 있다&lt;ul&gt;
&lt;li&gt;userspace&lt;/li&gt;
&lt;li&gt;iptables (기본값)&lt;/li&gt;
&lt;li&gt;ipvs&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;h1&gt;예시&lt;/h1&gt;
&lt;p&gt;node-1에 db Pod (IP: 10.244.1.2)이 있다고 하자.&lt;br&gt;이것을 위해 db-service ClusterIP Service를 생성하였으며, 서비스에 대한 IP는 10.103.132.104가 할당되었다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;kube-apiserver의 파라미터 service-cluster-ip-range 에서 변경가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;주의사항: Service의 IP Range와 Pod의 IP Range가 겹쳐서는 안됨&lt;/p&gt;
&lt;p&gt;&lt;code&gt;iptables -L -t nat | grep db-service&lt;/code&gt;를 하면, kube-proxy가 만든 rule들을 db-service라는 주석과 함께 확인할 수 있다&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;tcp anywhere 10.103.132.104 tcp dpt:3306&lt;/code&gt; 은, IP 10.103.132.104:3306 (서비스의 IP)으로 가는 모든 트래픽을 매칭&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DNAT tcp -- anywhere anywhere tcp to:10.244.1.2:3306&lt;/code&gt;은, 위에서 매칭된 트래픽을 전부 10.244.1.2:3306으로 보내버림&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;/var/log/kube-proxy.log&lt;/code&gt; 로그에서, 서비스 추가에 따라 iptables 엔트리를 추가하는 것을 볼 수 있다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;경로는 환경에 따라 다를 수 있음 / 로그 레벨 설정에 따라 안나올 수도 있음&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>콤퓨우터/필기: KodeKloud CKA 강의</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/103</guid>
      <comments>https://pscr.tistory.com/103#entry103comment</comments>
      <pubDate>Fri, 17 May 2024 00:48:00 +0900</pubDate>
    </item>
    <item>
      <title>215. CNI Weave</title>
      <link>https://pscr.tistory.com/102</link>
      <description>&lt;p&gt;Container Runtime은 컨테이너의 추가/삭제마다 Network plugin을 불러야 한다.&lt;/p&gt;
&lt;p&gt;Kubelet 서비스를 보면, &lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ExecStart=/user/local/bin/kubelet \\
...
  --network-plugin=cni \\
  --cni-bin-dir=/opt/cni/bin \\
  --cni-conf-dir=/etc/cni/net.d \\
...&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;처럼 되어 있다.&lt;/p&gt;
&lt;h3&gt;주의&lt;/h3&gt;
&lt;p&gt;쿠버 1.24 이전까지는 kubelet에서 &lt;code&gt;cni-bin-dir&lt;/code&gt;과 &lt;code&gt;network-plugin&lt;/code&gt; 파라미터를 통해 CNI 플러그인을 관리하는 것이 가능했으나, 이는 쿠버 1.24에서 삭제되었다!&lt;/p&gt;
&lt;p&gt;&lt;code&gt;/opt/cni/bin&lt;/code&gt;에는 bridge, dhcp, flannel, host-local 등 CNI Network Plugin의 executables이 들어 있다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;/etc/cni/net.d&lt;/code&gt;에는 어떤 플러그인을 사용할지에 대한 설정값이 들어 있다. (여러 파일이 있을 경우 알파벳 순으로 선택)&lt;/p&gt;
&lt;p&gt;conf 파일은 다음처럼 생겼다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
    &amp;quot;cniVersion&amp;quot;: &amp;quot;0.2.0&amp;quot;,
    &amp;quot;name&amp;quot;: &amp;quot;mynet&amp;quot;,
    &amp;quot;type&amp;quot;: &amp;quot;bridge&amp;quot;,
    &amp;quot;bridge&amp;quot;: &amp;quot;cni10&amp;quot;,
    &amp;quot;isGateway&amp;quot;: true,
    &amp;quot;isMasq&amp;quot;: true,
    &amp;quot;ipam&amp;quot;: {
        &amp;quot;type&amp;quot;: &amp;quot;host-local&amp;quot;,
        &amp;quot;subnet&amp;quot;: &amp;quot;10.22.0.0/16&amp;quot;,
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;isGateway: 생성되는 브리지 네트워크에 IP주소를 할당하여 게이트웨이 역할을 하게 할 것인가?&lt;/li&gt;
&lt;li&gt;isMasq: NAT Masquerading을 할 것인가?&lt;/li&gt;
&lt;li&gt;ipam: subnet, IP addr range, route 등을 선택&lt;ul&gt;
&lt;li&gt;host-local: IP 주소가 호스트에서 로컬로 관리&lt;ul&gt;
&lt;li&gt;(External DHCP server를 사용하여 remote에서 관리하는 옵션도 있음)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Weave&lt;/h1&gt;
&lt;p&gt;Weaveworks(R) Weave CNI 플러그인이 클러스터에 디플로이되면, 각 노드에 에이전트가 설치되어 다른 에이전트들과 정보를 주고받고, 전체 클러스터의 토폴로지를 파악한다.&lt;/p&gt;
&lt;p&gt;이를 위해 weave 에이전트끼리 사용하기 위한 브리지와 노드를 생성하고 IP를 할당한다. &lt;/p&gt;
&lt;p&gt;하나의 노드에 여러 브리지가 사용될 수 있음에 주의&lt;/p&gt;
&lt;p&gt;다른 노드로 가는 패킷을 발견하면, Weave가 패킷을 가로채서 수신자가 다른 네트워크에 있다는 것을 확인하고, 패킷을 캡슐화하여 다른 노드로 보낸다. 그렇게 다른 노드로 보내진 패킷은 해당 노드의 Weave에이전트에 의해 캡슐해제되어 목적지 Pod로 라우팅되게 된다.&lt;/p&gt;
&lt;h1&gt;Weave의 설치&lt;/h1&gt;
&lt;p&gt;각 노드에 Service나 Daemon 형태로 수동 설치할 수도 있지만, 일단 쿠버 기본 시스템이 작동되고 있다면 다음 명령어로 간단하게 설치할 수 있다.&lt;br&gt;&lt;code&gt;kubectl apply -f https://github.com/weaveworks/weave/releases/download/v2.8.1/weave-daemonset-k8s.yaml&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;이러면 Weave peer가 [[71. DaemonSet|DaemonSet]]으로 설치된다.&lt;/p&gt;
&lt;h1&gt;IP 주소 관리하기&lt;/h1&gt;
&lt;p&gt;콘테나에 IP를 할당하는 것은 CNI Plugin&lt;br&gt;하지만 어떻게 컨테이너의 IP들이 겹치지 않게 관리할 수 있는가?&lt;/p&gt;
&lt;p&gt;간단한 어프로치는 IP 목록 파일을 만들어서 할당 여부를 체크하는 것&lt;br&gt;하지만 이걸 굳이 CNI 스크립트에 기능으로 만들어 넣지 않아도, host-local plugin을 이용하면 된다&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;다만 스크립트 내에서 그러한 plugin을 부르기는 해야 한다&lt;ul&gt;
&lt;li&gt;이걸 하드코딩하지 않아도, CNI 설정파일의 &lt;code&gt;ipam&lt;/code&gt; 부분에서 어떤 플러그인을 부를지, 어떤 서브넷과 라우트를 쓸지를 읽어올 수 있다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Weave에서&lt;/h2&gt;
&lt;p&gt;Weave는 기본값으로 전체 네트워크에 10.32.0.0/12 (10.32.0.1 ~ 10.47.255.254)를 할당한다&lt;br&gt;이 커다란 네트워크들은 노드에 짤짤이로 나눠진다&lt;/p&gt;
&lt;p&gt;What is the range of IP addresses configured for PODs on this cluster?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# kubectl logs weave-net-f4xct -n kube-system
...
INFO: 2024/05/08 13:32:05.318172 Command line options: map[conn-limit:200 datapath:datapath db-prefix:/weavedb/weave-net docker-api: expect-npc:true http-addr:127.0.0.1:6784 ipalloc-init:consensus=0 ipalloc-range:10.244.0.0/16 metrics-addr:0.0.0.0:6782 name:52:79:16:46:d0:e0 nickname:controlplane no-dns:true no-masq-local:true port:6783]
...
INFO: 2024/05/08 13:32:07.349016 adding entry 10.244.0.0/16 to weaver-no-masq-local of 0
INFO: 2024/05/08 13:32:07.349048 added entry 10.244.0.0/16 to weaver-no-masq-local of 0&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;What is the IP Range configured for the services within the cluster?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ps -ef | grep ip
root        3746    3240  0 13:31 ?        00:02:36 kube-apiserver --advertise-address=192.27.58.9 --allow-privileged=true --authorization-mode=Node,RBAC --client-ca-file=/etc/kubernetes/pki/ca.crt --enable-admission-plugins=NodeRestriction --enable-bootstrap-token-auth=true --etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt --etcd-certfile=/etc/kubernetes/pki/apiserver-etcd-client.crt --etcd-keyfile=/etc/kubernetes/pki/apiserver-etcd-client.key --etcd-servers=https://127.0.0.1:2379 --kubelet-client-certificate=/etc/kubernetes/pki/apiserver-kubelet-client.crt --kubelet-client-key=/etc/kubernetes/pki/apiserver-kubelet-client.key --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname --proxy-client-cert-file=/etc/kubernetes/pki/front-proxy-client.crt --proxy-client-key-file=/etc/kubernetes/pki/front-proxy-client.key --requestheader-allowed-names=front-proxy-client --requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt --requestheader-extra-headers-prefix=X-Remote-Extra- --requestheader-group-headers=X-Remote-Group --requestheader-username-headers=X-Remote-User --secure-port=6443 --service-account-issuer=https://kubernetes.default.svc.cluster.local --service-account-key-file=/etc/kubernetes/pki/sa.pub --service-account-signing-key-file=/etc/kubernetes/pki/sa.key --service-cluster-ip-range=10.96.0.0/12 ...&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;kube-proxy가 어떤 것을 사용하는가: &lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl logs kube-proxy-r8pj7 -n kube-system
I0508 13:32:01.431839       1 server_others.go:72] &amp;quot;Using iptables proxy&amp;quot;&lt;/code&gt;&lt;/pre&gt;</description>
      <category>콤퓨우터/필기: KodeKloud CKA 강의</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/102</guid>
      <comments>https://pscr.tistory.com/102#entry102comment</comments>
      <pubDate>Fri, 17 May 2024 00:46:47 +0900</pubDate>
    </item>
    <item>
      <title>206. Docker Networking</title>
      <link>https://pscr.tistory.com/101</link>
      <description>&lt;h1&gt;None&lt;/h1&gt;
&lt;p&gt;네트워크가 없다. 외부로 통신 불가.&lt;/p&gt;
&lt;h1&gt;Host&lt;/h1&gt;
&lt;p&gt;호스트의 네트워크에 그대로 노출한다. 컨테이너 안에서 80을 열면 호스트의 IP로 80에 접근해서 내용을 볼 수 있다.&lt;br&gt;두 개의 컨테이너가 같은 포트를 열 수는 없다.&lt;/p&gt;
&lt;h1&gt;Bridge&lt;/h1&gt;
&lt;p&gt;기본값으로 172.17.0.0/24의 브리지 네트워크가 생성되어 내부 private network 주소를 할당받는다.&lt;/p&gt;
&lt;p&gt;기본값으로 &amp;quot;bridge&amp;quot;라는 이름의 네트워크가 생성된다. &lt;code&gt;docker network ls&lt;/code&gt;를 찍어 보면 Network 이름이 bridge로 되어 있으나, 실제로 호스트에서 생성되는 네트워크 이름은 docker0이다.&lt;/p&gt;
&lt;h2&gt;Docker에서&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;docker inspect&lt;/code&gt; 명령의 NetworkSettings 부분을 보면, 컨테이너의 네트워크 네임스페이스를 볼 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ip link&lt;/code&gt; 명령을 찍어보면, master를 docker0으로 하는 &lt;code&gt;veth뭐시기@if뭐&lt;/code&gt;라는 인터페이스가 생겨 있음을 볼 수 있다.&lt;br&gt;&lt;code&gt;ip -n 네임스페이스명 link&lt;/code&gt; 명령을 찍어보면, &lt;code&gt;eth0@if뭐+1&lt;/code&gt;라는 인터페이스가 컨테이너의 네트워크 네임스페이스에 연결되어 있음을 볼 수 있다.&lt;/p&gt;
&lt;p&gt;즉 &lt;code&gt;veth뭐시기@if뭐&lt;/code&gt;는 가상-스위치인 bridge(&lt;code&gt;docker0&lt;/code&gt;)에 꽂혀있고, &lt;code&gt;eth0@if뭐+1&lt;/code&gt;는 네트워크 네임스페이스(컨테이너)에 꽂혀있는 구성의 한 쌍의 가상-이더넷-케이블 구조를 생각하면 된다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;뭐&lt;/code&gt;는 자연수이다. 예를 들어 &lt;code&gt;veth뭐시기@if5&lt;/code&gt;와 연결된 상대는 &lt;code&gt;eth0@if6&lt;/code&gt;이라는 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이러한 구조는 네트워크가 bridge로 설정된 컨테이너가 켜질 때마다 계속 만들어진다.&lt;/p&gt;
&lt;h2&gt;포트 포워딩&lt;/h2&gt;
&lt;p&gt;아무것도 설정하지 않은 경우, 외부 네트워크에서 bridge 내부로 inbound로 들어올 수 없다.&lt;br&gt;&lt;code&gt;docker run -p 8080:80&lt;/code&gt; 처럼 포트포워딩 매핑을 해 주면, 호스트로 들어오는 8080 트래픽이 해당 컨테이너의 80으로 포워딩된다.&lt;/p&gt;
&lt;p&gt;이 때, 실제로는 docker에서 알아서 iptables NAT rule을 생성해주고 있는 것이다. &lt;code&gt;iptables -nvL -t nat&lt;/code&gt;를 찍어보면 도커가 만들어놓은 DNAT rule을 확인할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ip link
ip adr
ip addr add 192.168.1.0/24 dev eth0
ip route
ip route add 192.168.1.0/24 via 192.168.2.1
cat /proc/sys/net/ipv4/ip_forward
arp
netstat -plnt
route&lt;/code&gt;&lt;/pre&gt;</description>
      <category>콤퓨우터/필기: KodeKloud CKA 강의</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/101</guid>
      <comments>https://pscr.tistory.com/101#entry101comment</comments>
      <pubDate>Fri, 17 May 2024 00:46:06 +0900</pubDate>
    </item>
    <item>
      <title>204. Network Namespaces</title>
      <link>https://pscr.tistory.com/100</link>
      <description>&lt;p&gt;Network Namespace 개념은 리눅스 컨테이너에서 네트워크 분리를 위해 사용되는 기술이다.&lt;/p&gt;
&lt;p&gt;컨테이너는 Process Namespace로 격리되어 있어서, 컨테이너 위에서 돌아가는 프로세스만 볼 수 있다. 컨테이너 위에서 ps aux를 찍어 보면 CMD로 구동되는 프로세스의 PID가 1임을 볼 수 있다.&lt;br&gt;하지만 호스트에서 ps aux를 찍어 보면, 해당 프로세스의 PID가 전혀 다른 값으로 들어가 있는 것을 볼 수 있다.&lt;/p&gt;
&lt;p&gt;즉 같은 프로세스가 컨테이너 내부와 외부에서 전혀 다른 PID를 가지고 있는 것이다.&lt;/p&gt;
&lt;p&gt;네트워크 네임스페이스도 비슷하다. 호스트에는 Routing 및 ARP Table이 존재한다.&lt;br&gt;하지만 컨테이너 생성 시에는 네트워크 네임스페이스가 생성되며, 컨테이너 내부에서는 호스트의 네트워크 관련 정보를 전혀 볼 수 없다.&lt;br&gt;또한, 컨테이너는 네트워크 네임스페이스 내부에서 자신의 가상 인터페이스 (&lt;code&gt;veth0&lt;/code&gt;), 라우팅 테이블, ARP 테이블을 가지고 있다.&lt;/p&gt;
&lt;h1&gt;네트워크 네임스페이스의 생성&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;ip netns add name&lt;/code&gt;으로 네트워크 네임스페이스를 수동으로 생성할 수 있다.&lt;br&gt;&lt;code&gt;ip netns&lt;/code&gt;로 네트워크 네임스페이스를 볼 수 있다.&lt;/p&gt;
&lt;p&gt;호스트에서는, &lt;code&gt;ip link&lt;/code&gt;로 인터페이스 목록을 볼 수 있다. 네트워크 네임스페이스 내부의 인터페이스 목록은 어떻게 볼 수 있을까?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ip netns exec name ip link&lt;/code&gt; 를 실행하면 된다.&lt;/li&gt;
&lt;li&gt;혹은, &lt;code&gt;ip -n name link&lt;/code&gt;를 할 수도 있겠다. &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ARP Table이나 Routing Table 역시 비슷하게 볼 수 있다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ip netns exec name arp&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ip netns exec name route&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;두 네트워크 네임스페이스를 연결하기&lt;/h1&gt;
&lt;p&gt;가상 이더넷 쌍을 이용하여 두 네트워크 네임스페이스 &lt;code&gt;red&lt;/code&gt;와 &lt;code&gt;blue&lt;/code&gt;를 연결해 보자. (&amp;quot;Virtual Cable&amp;quot; 또는 &amp;quot;Pipe&amp;quot;)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;veth-red와 veth-blue 인터페이스를 생성한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ip link add veth-red type veth peer name veth-blue&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;각각의 인터페이스를 네트워크 네임스페이스에 할당한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ip link set veth-red netns red&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ip link set veth-blue netns blue&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;ip addr&lt;/code&gt; 명령어로 각 네임스페이스의 인터페이스에 IP를 할당한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ip -n red addr add 192.168.15.1 dev veth-red&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ip -n blue addr add 192.168.15.2 dev veth-blue&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;ip link set up&lt;/code&gt; 명령어로 인터페이스를 올린다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ip -n red link set veth-red up&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ip -n blue link set veth-blue up&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;이제 통신이 작동한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ip netns exec red ping 192.168.15.2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;red 네트워크 네임스페이스의 ARP 테이블에는 veth-blue의 MAC주소와 IP가 기록된다.&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ip netns exec red arp&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;blue 네트워크 네임스페이스의 ARP 테이블에는 veth-red의 MAC주소와 IP가 기록된다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;호스트에서 &lt;code&gt;arp&lt;/code&gt;를 실행해보면, 이 네트워크 네임스페이스 내부의 ARP 정보는 전혀 확인할 수 없다&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;여러 네트워크 네임스페이스를 브리지로 연결하기&lt;/h1&gt;
&lt;p&gt;현실에서 여러 호스트를 이더넷으로 연결하려면 스위치를 사용한다.&lt;br&gt;마찬가지로 가상세계에서 여러 네트워크 네임스페이스를 가상 이더넷으로 연결하려면 가상 스위치를 사용하면 된다.&lt;/p&gt;
&lt;p&gt;리눅스의 브리지(Bridge)를 이용하여 이를 구현할 수 있다. &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;호스트에서 &lt;code&gt;ip link add vnet0 type bridge&lt;/code&gt;를 하여 브리지를 생성한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;호스트의 입장에서는 이것은 하나의 인터페이스이다. &lt;code&gt;ip link&lt;/code&gt;를 찍어 보면 목록에 lo, eth0과 함께 나온다.&lt;ul&gt;
&lt;li&gt;하지만 네트워크 네임스페이스에 있어서는 스위치처럼 기능한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;일단 &lt;code&gt;ip link set dev vnet0 up&lt;/code&gt;으로 링크를 올려준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;기존 단계에서 사용했던 link들은 삭제해준다. (&lt;code&gt;ip -n red link del veth-red&lt;/code&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;이제 veth-red와 &lt;code&gt;veth-red-br&lt;/code&gt; 간의 peer를 만들어주고, veth-red 인터페이스를 네트워크 인터페이스에 할당한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ip link add veth-red type veth peer name veth-red-br&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ip link set veth-red netns red&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;이제 veth-red-br을 브리지에 연결시켜주어야 한다. 이를 위해,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ip link set veth-red-br master vnet0&lt;/code&gt; 처럼, master를 vnet0으로 지정한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;나머지 과정은 위와 동일하다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ip addr&lt;/code&gt; 명령어로 각 네임스페이스의 인터페이스에 IP를 할당한다.&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ip -n red addr add 192.168.15.1 dev veth-red&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ip -n blue addr add 192.168.15.2 dev veth-blue&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ip link set up&lt;/code&gt; 명령어로 인터페이스를 올린다.&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ip -n red link set veth-red up&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ip -n blue link set veth-blue up&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;호스트와 브리지 간 통신&lt;/h2&gt;
&lt;p&gt;이 브리지라는 것은 호스트 입장에서는 네트워크 인터페이스이다. 그렇기에 호스트에서 vnet0에 IP를 할당해주기만 하면 호스트에서 브리지 네트워크 간에 서로 통신이 가능하다.&lt;br&gt;&lt;code&gt;ip addr add 192.168.15.254/24 dev vnet0&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;브리지에서 바깥 네트워크로 나가기&lt;/h2&gt;
&lt;p&gt;호스트의 eth0이 192.168.1.2/24라고 해 보자. pink 네임스페이스(192.168.15.1/24)에서 eth0과 연결된 LAN의 192.168.1.3에 접속하려면 어떻게 해야 할까?&lt;/p&gt;
&lt;p&gt;pink 네임스페이스에서 192.168.1.0/24에 대한 라우팅 정보, 이를테면 게이트웨이를 알아야 한다.&lt;br&gt;&lt;code&gt;ip netns exec blue ip route add 192.168.1.0/24 via 192.168.15.254&lt;/code&gt;를  해 주면, 이제 192.168.15.1에서 192.168.1.0/24로 패킷이 나갈 수 있다.&lt;/p&gt;
&lt;p&gt;하지만, 패킷이 다시 돌아올 수는 없다. 외부 네트워크는 192.168.15.0/24를 모르기 때문이다.&lt;br&gt;따라서 NAT를 설정해주어야 한다.&lt;/p&gt;
&lt;p&gt;iptables를 이용하여 NAT 기능을 추가할 수 있다.&lt;br&gt;&lt;code&gt;iptables -t nat -A POSTROUTING -s 192.168.15.0/24 -j MASQUERADE&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;인터넷에 연결하기&lt;/h3&gt;
&lt;p&gt;지금 pink의 라우팅 테이블에는 목적지 192.168.15.0/24, 192.168.1.0/24에 대한 정보밖에 없기 때문에, ping 8.8.8.8을 하면 Network is unreachable이 나올 것이다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ip netns exec pink ip route add default via 192.168.15.5&lt;/code&gt;로, 기본 라우트를 192.168.15.254로 잡아주면, 패킷이 외부로 나갈 수 있다.&lt;/p&gt;
&lt;h2&gt;외부 네트워크에서 브리지에 물린 네임스페이스로 inbound&lt;/h2&gt;
&lt;p&gt;192.168.15.0/24의 라우팅 정보를 외부 네트워크의 라우팅 테이블에 올리는 방법이 있긴 한데 이것은 별로 효율적인 방식은 아니다.&lt;br&gt;이것보다는 포트포워딩을 해 주는 것이 현실적이다.&lt;br&gt;&lt;code&gt;iptables -t nat -A PREROUTING --dport 80 --to-destination 192.168.15.2:80 -j DNAT&lt;/code&gt;&lt;/p&gt;</description>
      <category>콤퓨우터/필기: KodeKloud CKA 강의</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/100</guid>
      <comments>https://pscr.tistory.com/100#entry100comment</comments>
      <pubDate>Fri, 17 May 2024 00:45:35 +0900</pubDate>
    </item>
    <item>
      <title>189-191. Persistent Volumes, Persistent Volume Claims and Using PVCs in Pods</title>
      <link>https://pscr.tistory.com/99</link>
      <description>&lt;h1&gt;Persistent Volumes (PV)&lt;/h1&gt;
&lt;p&gt;Persistent Volume은 Storage Volume들의 클러스터 단위 pool이다. 클러스터의 사용자는 이 풀에서 스토리지를 선택하여 사용할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-vol1
spec:
  accessModes:
  - ReadWriteOnce # ReadOnlyMany | ReadWriteOnce | ReadWriteMany
  capacity:
    storage: 1Gi
  hostPath: # 이 옵션을 Production에서 실제로 사용해서는 안됨
    path: /tmp/data
  awsElasticBlockStore: # 혹은 외부 Storage Provider 사용 시
    volumeID: 
    fsType: ext4&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;주의: &lt;code&gt;spec.persistentVolumeReclaimPolicy&lt;/code&gt;라는 옵션을 외워둘것 - 쿠버 도큐멘테이션에서도 잘 안나온다&lt;/p&gt;
&lt;h1&gt;Persistent Volume Claim (PVC)&lt;/h1&gt;
&lt;p&gt;Persistent Volume Claim(PVC)는 PV를 사용하기 위한 object이다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;모든 PVC는 하나의 Persistent Volume에 매핑된다.&lt;/li&gt;
&lt;li&gt;매핑 과정에서 쿠버는 PVC의 요청에 맞는 스토리지를 찾는다.&lt;ul&gt;
&lt;li&gt;용량, Access Mode, Volume Mode, 스토리지 등급 등등...&lt;ul&gt;
&lt;li&gt;PVC의 요청을 만족하는 여러 개의 PV가 존재하는 경우, PVC에 label옵션을 넣어서 수동 선택하는 것도 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;만약 PVC의 조건에 정확히 맞는 PV가 없다면, PVC에서 요청한 용량보다 큰 PV가 매핑될 수도 있다.&lt;/li&gt;
&lt;li&gt;사용 가능한 PV가 없다면, PVC는 쓸 수 있는 PV가 나올 때까지 pending 상태로 대기하게 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;apiVersion: v1
kind: PersistentVolumeClaim
metadata;
  name: myclaim
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 500Mi&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;PVC의 생성은 &lt;code&gt;kubectl create -f&lt;/code&gt;, 삭제는 &lt;code&gt;kubectl delete persistentvolumeclaim&lt;/code&gt; 하면 된다.&lt;/p&gt;
&lt;h3&gt;PVC가 삭제되면&lt;/h3&gt;
&lt;p&gt;PVC가 삭제되면, 기본값 &lt;code&gt;perrsistentVolumeReclaimPolicy&lt;/code&gt;는 Retain이다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PV가 그대로 남아 있고, 다른 PVC가 들어와도 해당 PV를 할당하지 않는다!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;perrsistentVolumeReclaimPolicy를,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Delete (볼륨을 자동 삭제)나&lt;/li&gt;
&lt;li&gt;Recycle (데이터 볼륨의 데이터를 scrub한 뒤 타 PVC에 제공)으로 설정할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Pod에서 PVC 사용하기&lt;/h1&gt;
&lt;p&gt;Pod이나 ReplicaSets, Deployments의 definition에서는, &lt;code&gt;spec.volumes.persistentVolumeClaim&lt;/code&gt;을 지정하여, PVC를(그리고 이것에 따라오는 PV를) 사용할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;spec:
  containers:
    - image: nginx
      name: nginx
      volumeMounts:
      - mountPath: &amp;quot;/var/www/html&amp;quot;
        name: mypd
  volumes:
  - name: mypd
    persistentVolumeClaim:
      claimName: myClaim &lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We discussed how to configure an application to use a volume in the &amp;quot;Volumes&amp;quot; lecture using volumeMounts. This along with the practice test should be sufficient for the exam.&lt;/p&gt;
&lt;p&gt;Additional topics such as StatefulSets are out of scope for the exam. However, if you wish to learn them, they are covered in the  Certified Kubernetes Application Developer (CKAD) course.&lt;/p&gt;
&lt;h1&gt;Storage Class&lt;/h1&gt;
&lt;p&gt;지금까지의 방식에서는 - &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;예를 들어, GCP의 PersistentDisk CSI를 이용해 PV를 생성하려면, 일일이 GCP에서 디스크를 생성한 뒤에, PV Definition을 만들어주어야 한다.&lt;/li&gt;
&lt;li&gt;이러한 방식을 Static Provisioning Volume이라고 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이 과정을 수동으로 하지 않을 수 있을까? - 가능하다! &lt;/p&gt;
&lt;h3&gt;Dynamic Provisioning of Volumes&lt;/h3&gt;
&lt;p&gt;Storage Class를 이용하면, 알아서 스토리지를 프로비저닝하고 PV를 만들고 PVC에 붙여주는 가제트만능뭐시기인 Provisioner를 정의할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: google-storage
provisioner: kubernets.io/gce-pd &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이제 PV를 수동으로 만들 필요가 없다. &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PVC를 만들 때에는, &lt;code&gt;spec.storageClassName&lt;/code&gt;을 지정해준다.&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;spec:
accessModes:
- ReadWriteOnce
storageClassName: google-storage
resources:
  ...&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이제 해당 PVC가 요청되면, GCP 프로비저너가 알아서 구글클라우드에 디스크를 만들고, 해당 디스크를 이용해 PV를 생성해서 Pod에 갖다 준다.&lt;/p&gt;
&lt;p&gt;스토리지 제공업체에 따라 Provisoner에 다양한 파라미터를 받아 설정을 하기도 한다. 예를 들어 underlying 스토리지를 SSD로 할 것인지 HDD로 할 것인지를 설정한다든가...&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;이렇게 할당할 볼륨의 스토리지 &amp;quot;클래스&amp;quot;를 나눌 수 있기 때문에 이것을 &amp;quot;Storage Class&amp;quot;라고 부르는 것이다.&lt;/li&gt;
&lt;li&gt;상세 옵션은 해당 제공업체의 도큐멘테이션을 보십시요&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>콤퓨우터/필기: KodeKloud CKA 강의</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/99</guid>
      <comments>https://pscr.tistory.com/99#entry99comment</comments>
      <pubDate>Fri, 17 May 2024 00:44:59 +0900</pubDate>
    </item>
    <item>
      <title>184-185. Storage in Docker and Volume Driver Plugins</title>
      <link>https://pscr.tistory.com/98</link>
      <description>&lt;h1&gt;Storage In Docker&lt;/h1&gt;
&lt;p&gt;기본적으로 Docker는 /var/lib/docker 하위에 모든 데이터를 보관한다&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;aufs&lt;/li&gt;
&lt;li&gt;containers&lt;/li&gt;
&lt;li&gt;image&lt;/li&gt;
&lt;li&gt;volumes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Docker (OCI) Image는 Layered Architecture로 되어 있다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dockerfile의 각 line은 기존 이미지 위에 새로운 layer를 생성한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;FROM Ubuntu
RUN apt-get update &amp;amp;&amp;amp; apt-get -y install python
RUN pip install flask flask-mysql
COPY . /opt/source-code
ENTRYPOINT FLASK_APP=/opt/source-code/app.py flask run&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;Layer5: 엔트리포인트 변경 (0B)&lt;/li&gt;
&lt;li&gt;Layer4: 복사된 소스코드 (229B)&lt;/li&gt;
&lt;li&gt;Layer3: pip 패키지 설치 내역 (6.3MiB)&lt;/li&gt;
&lt;li&gt;Layer2: APT 업데이트 및 설치된 내역 (306MiB)&lt;/li&gt;
&lt;li&gt;Layer1: Ubuntu Base Image (120MiB)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;만약 이것과 매우 비슷한 Dockerfile로 이미지를 빌드한다면 어떨까?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;FROM Ubuntu
RUN apt-get update &amp;amp;&amp;amp; apt-get -y install python
RUN pip install flask flask-mysql
COPY . /opt/source-code2
ENTRYPOINT FLASK_APP=/opt/source-code2/app.py flask run&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;이 경우 Layer 3까지는 위의 Dockerfile와 동일한 구조를 공유하므로, Docker는 3개의 Layer를 재사용한다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;docker run&lt;/code&gt;을 해서 이렇게 만들어진 이미지를 구동하면, 그 위에 Container Layer를 새로 생성한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;이미지 레이어와는 달리 R/W가 가능하지만, 이 레이어의 수명은 컨테이너의 수명을 따라간다.&lt;/li&gt;
&lt;li&gt;하위에 있는 레이어는 R/O이다: 고정된 상태&lt;ul&gt;
&lt;li&gt;그렇다고 컨테이너 실행 중에 하위 레이어에 있는 데이터를 수정할 수 없는 것은 아니다.&lt;ul&gt;
&lt;li&gt;예를 들어 위의 케이스에서는 컨테이너 실행 중에 &lt;code&gt;vi /opt/source-code/app.py&lt;/code&gt;로 app.py의 내용을 바꿀 수 있다.&lt;/li&gt;
&lt;li&gt;하지만, 새로 만들어진 Container Layer에 수정된 app.py의 내용이 저장되는 것이지 실제로 이미지파일의 내용이 변하는 것은 아니다.&lt;ul&gt;
&lt;li&gt;Copy-on-write&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;h1&gt;Persistant storage: Volume&lt;/h1&gt;
&lt;p&gt;예를 들어 MySQL image를 쓴다고 하면, &lt;code&gt;docker volume create data_volume&lt;/code&gt;으로 MySQL 서버 데이터를 저장할 volume을 만든 뒤, 컨테이너에 마운트하여 이 볼륨을 사용할 수 있다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;docker run -v data_volume:/var/lib/mysql mysql&lt;/code&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/var/lib/docker/volumes/data_volume&lt;/code&gt;에 저장&lt;/li&gt;
&lt;li&gt;(Volume Mounting)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;외부 volume은 꼭 &lt;code&gt;/var/lib/docker/volumes&lt;/code&gt; 하위에 있지 않아도 된다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;docker run -v /data/mysql:/var/lib/mysql mysql&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;(Bind Mounting)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;주: &lt;code&gt;-v&lt;/code&gt; 옵션은 deprecated되었다, &lt;code&gt;--mount&lt;/code&gt; 명령이 권장됨&lt;/p&gt;
&lt;h1&gt;Storage Drivers&lt;/h1&gt;
&lt;p&gt;Layered Architecture의 유지, Writeable layer의 생성, Copy-and-Write를 위한 적절한 파일 이동 등등을 해 주는 친구를 Storage Driver라고 한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AUFS (Ubuntu 기본값)&lt;/li&gt;
&lt;li&gt;Device Mapper&lt;/li&gt;
&lt;li&gt;ZFS&lt;/li&gt;
&lt;li&gt;BTRFS 등등...&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Volume Drivers&lt;/h1&gt;
&lt;p&gt;Volume은 Storage Driver에 의해 처리되지 않는다&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Volume Driver가 따로 존재&lt;ul&gt;
&lt;li&gt;local&lt;/li&gt;
&lt;li&gt;Microsoft Azure File Storage&lt;/li&gt;
&lt;li&gt;gce-docker&lt;/li&gt;
&lt;li&gt;VMWare vSphere Storage...&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>콤퓨우터/필기: KodeKloud CKA 강의</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/98</guid>
      <comments>https://pscr.tistory.com/98#entry98comment</comments>
      <pubDate>Fri, 17 May 2024 00:41:30 +0900</pubDate>
    </item>
    <item>
      <title>177-178. Kubernetes Network Policy</title>
      <link>https://pscr.tistory.com/97</link>
      <description>&lt;h1&gt;Kubernetes Network Security&lt;/h1&gt;
&lt;p&gt;여러 노드로 구성된 클러스터가 있다고 하자.&lt;br&gt;이 클러스터에는 노드, 서비스, Pod 등등이 존재한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;그리고 이 노드, 서비스, Pod에는 모두 IP가 존재한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;쿠버에서는, (어떻게 구현을 했든지 상관없지만 아무튼) 같은 클러스터 내의 Pod들이 별도의 설정 없이도 서로 통신을 할 수 있어야 한다는 조건이 있다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;예를 들어, 클러스터 전체가 VPN에 물려 있을 수도 있다. 이 경우 IP와 Pod/Service Name을 통해 서로에게 접근할 수 있을 것이다.&lt;/li&gt;
&lt;li&gt;기본적으로, 쿠버에서는, &lt;strong&gt;클러스터 내부 Pod 간의 통신은 전부 허용 처리&lt;/strong&gt;하는 것으로 되어 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;예를 들어 웹서버 Pod, API서버 Pod, DB Pod으로 구성된 애플리케이션에 대해 생각해보자.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Service를 생성하여 이 3개의 Pod간의 통신을 가능하게 할 수 있다.&lt;/li&gt;
&lt;li&gt;기본값으로는, 이 3개 Pod는 다른 클러스터 구성요소들과 자유롭게 통신이 가능하다.&lt;ul&gt;
&lt;li&gt;하지만 예를 들어, 프론트 서버가 DB 서버에 직접 접근하지 못해야 한다는 제약조건이 생긴다면?&lt;ul&gt;
&lt;li&gt;Network Policy가 필요하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Network Policy&lt;/h2&gt;
&lt;p&gt;yet another Kubernetes object이다&lt;br&gt;NetworkPolicy를만든뒤, 1개 이상의 Pod에 물릴 수 있다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;또 NetworkPolicy 내부에서 rule을 정할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;label과 selector를 통해 어떤 NetworkPolicy를 어떤 Pod에 적용할지 선택 가능하다.&lt;/p&gt;
&lt;p&gt;예를 들어, &lt;code&gt;role: db&lt;/code&gt; label이 있는 Pod에서, Inbound 트래픽을 이름이 api-pod인 Pod에서 TCP/3306으로 들어오는 것만 허용하고, 나머지 Inbound 트래픽은 전부 차단하도록 구현해 보자.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: db-policy
spec:
  podSelector:
    matchLabels: # role:db label이 있는 Pod에 대해 해당 정책을 적용
      role: db
  policyTypes:
  - Ingress # 아래에서 허용된 것 이외의 모든 Inbound 트래픽은 차단

  ingress:
  - from:
    - podSelector: # api-pod에서 들어오는 TCP/3306 Inbound 트래픽을 허용
        matchLabels: 
          name: api-pod
    ports:
    - protocol: TCP
      port: 3306 &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(참고: Ingress=Inbound, Egress=Outbound)&lt;/p&gt;
&lt;h4&gt;주의사항&lt;/h4&gt;
&lt;p&gt;앞에서 &amp;quot;어떻게 구현을 했든지 상관없지만 아무튼&amp;quot; 이라는 표현을 했다. 이것은 쿠버에 사용할 수 있는 네트워크 솔루션이 여러 가지 있기 때문이다. (kube-router, flannel, ...)&lt;br&gt;이 중, flannel은 NetworkPolicy를 지원하지 않는다.&lt;/p&gt;
&lt;h3&gt;네임스페이스와 Network Policy&lt;/h3&gt;
&lt;p&gt;만약 dev, test, prod 네임스페이스에 전부 api-pod이라는 이름의 API Pod이 존재한다고 해 보자.&lt;br&gt;위에서 만든 NetworkPolicy로는, 이 Pod들 전부가 prod.db에 접근할 수 있다.&lt;/p&gt;
&lt;p&gt;prod 네임스페이스의 api-pod에서 보내는 요청만 받아들이도록 수정해보자.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;  ingress:
  - from:
    - podSelector: # api-pod에서 들어오는 TCP/3306 Inbound 트래픽을 허용
        matchLabels: 
          name: api-pod
      namespaceSelector:
        matchLabels:
          name: prod&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;주의사항: 이렇게 NetworkPolicy를 만들기 전에, 해당 label의 namespace가 이미 생성되어 있어야 한다.&lt;/p&gt;
&lt;p&gt;또, &lt;code&gt;podSelector&lt;/code&gt; 없이 &lt;code&gt;namespaceSelector&lt;/code&gt;만 사용하는 것도 가능하다. &lt;/p&gt;
&lt;h3&gt;Pod가 아닌 외부 엔티티의 접속&lt;/h3&gt;
&lt;p&gt;예를 들어, 외부 서버인 192.168.5.10에서 DB백업을 하기 위해 DB Pod에 접속해야 한다고 하자.&lt;br&gt;Pod이 아닌 외부 서버이기 때문에, podSelector는 이용할 수가 없다.&lt;/p&gt;
&lt;p&gt;이런 상황의 대응을 위해 ipBlock selector가 존재한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;  ingress:
  - from:
    - ipBlock:
        cidr: 192.168.5.10/32&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;룰의 판정&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;  ingress:
  - from:
    - podSelector: # api-pod에서 들어오는 TCP/3306 Inbound 트래픽을 허용
        matchLabels: 
          name: api-pod
      namespaceSelector:
        matchLabels:
          name: prod

    - ipBlock:
        cidr: 192.168.5.10/32&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;다음과 같은 룰에서, &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;(podSelector AND namespaceSelector)가 1개의 rule이고,&lt;/li&gt;
&lt;li&gt;ipBlock이 하나의 rule이다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-&lt;/code&gt;로 분리된 각각의 rule은 또한 OR로 판정된다. (&lt;code&gt;-&lt;/code&gt; 요건에 하나만 걸리면 OK판정)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>콤퓨우터/필기: KodeKloud CKA 강의</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/97</guid>
      <comments>https://pscr.tistory.com/97#entry97comment</comments>
      <pubDate>Fri, 17 May 2024 00:40:56 +0900</pubDate>
    </item>
    <item>
      <title>170-174. Image Security, Security Contexts</title>
      <link>https://pscr.tistory.com/96</link>
      <description>&lt;p&gt;Docker(OCI) 컨테이너에서, 기본적으로 이미지 파일명 컨벤션은 &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;image: domain.name/username/imagename:version&lt;/code&gt;이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;만약 &lt;code&gt;image:nginx&lt;/code&gt;라고 간단하게 적었다면, 이것은 &lt;code&gt;image: docker.io/library/nginx:latest&lt;/code&gt;로 해석된다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;library는 Docker의 기본 사용자명이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;로그인을 해야 쓸 수 있는 Private Registry가 존재한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;대부분의 클라우드 프로바이더에서는 Private Registry 서비스를 제공한다.&lt;/li&gt;
&lt;li&gt;docker.io, gchr.io같은 퍼블릭 레지스트리에도 로그인해야 사용할 수 있는 Private Repo들이 존재한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;하지만 Kubernetes에서 어떻게 프라이빗 레지스트리에 로그인을 할 수 있는가?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;docker-registry&lt;/code&gt;라는 타입에 이름은 &lt;code&gt;regcred&lt;/code&gt;으로 하여 Secret을 생성한다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# kubectl create secret --help
Create a secret with specified type.

A docker-registry type secret is for accessing a container registry.

A generic type secret indicate an Opaque secret type.

A tls type secret holds TLS certificate and its associated key.&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;이후 Pod definition의 &lt;code&gt;spec.imagePullSecrets[].name&lt;/code&gt;에 regcred를 넣으면 된다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Docker Security&lt;/h1&gt;
&lt;p&gt;컨테이너 속의 프로그램들은 컨테이너 외부와 동일한 리눅스 커널을 공유한다.&lt;br&gt;실제로 호스트에서 ps aux를 찍어 보면 컨테이너에 들어있는 프로그램들이 보인다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;하지만, 컨테이너와 컨테이너 외부는 namespace를 통해 분리되며, 컨테이너 내부의 프로그램들은 그 namespace 외부를 볼 수 없다.&lt;ul&gt;
&lt;li&gt;컨테이너 내부에서 ps aux를 찍어 보면, CMD로 돌아가고 있는 프로세스가 PID 1로 되어 있을 것이다.&lt;/li&gt;
&lt;li&gt;호스트에서 ps aux를 찍어 보면, 컨테이너에서 돌고 있는 프로세스가 보이되 PID가 전혀 다르게 되어 있다.&lt;ul&gt;
&lt;li&gt;같은 프로세스라도 다른 네임스페이스에서는 다른 PID를 가지고 있을 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;기본적으로, Docker에서는 컨테이너를 root 사용자로 구동한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dockerfile에 &lt;code&gt;USER uid&lt;/code&gt;를 지정하거나 Docker 커맨드라인에 &lt;code&gt;--user=uid&lt;/code&gt;를 주어 커스텀이 가능하다.&lt;/li&gt;
&lt;li&gt;컨테이너에 root를 주는 건 위험하지 않은가?&lt;ul&gt;
&lt;li&gt;기본적으로 docker는 Capability 제한을 걸어서 컨테이너 내부의 root가 &lt;code&gt;sys_admin&lt;/code&gt; 따위의 권한을 가지지 않도록 한다.&lt;/li&gt;
&lt;li&gt;privileged 플래그를 주면 모든 root권한을 주는 것도 가능은 하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Kubernetes Security&lt;/h1&gt;
&lt;p&gt;쿠버에서도 도커처럼 PID 설정, Capability 제한이 가능하다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pod 단위 설정, Container 단위 설정이 모두 가능하며, Container 단위 설정이 Pod 설정에 우선한다.&lt;ul&gt;
&lt;li&gt;Capability 설정은 컨테이너 단위에서만 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;spec:
  securityContext:
    runAsUser: 1000
containers:
- image: ubuntu
  name: ubuntu
  securityContext:
    capabilities:
      add: [&amp;quot;MAC_ADMIN&amp;quot;]&lt;/code&gt;&lt;/pre&gt;</description>
      <category>콤퓨우터/필기: KodeKloud CKA 강의</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/96</guid>
      <comments>https://pscr.tistory.com/96#entry96comment</comments>
      <pubDate>Fri, 17 May 2024 00:40:14 +0900</pubDate>
    </item>
    <item>
      <title>167. Service Accounts</title>
      <link>https://pscr.tistory.com/95</link>
      <description>&lt;p&gt;쿠버에는 2가지 종류의 account가 존재한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;User - 사람이 사용&lt;ul&gt;
&lt;li&gt;admin, developer, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Service - 봇이 사용&lt;ul&gt;
&lt;li&gt;Prometheus같은 모니터링 프로그램 (쿠버 API를 통해 통계 생성), Jenkins같은 CI/CD 툴 (클러스터에 디플로이)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Service Account 생성하기&lt;/h1&gt;
&lt;p&gt;예를 들어 쿠버 상태 대시보드같은 걸 만든다고 하자. 그럼 당연히 쿠버 API에 접속해서 정보를 받아올 수 있어야 한다. 이를 위해 Service Account가 필요하다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;kubectl create serviceaccount account-name&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ServiceAccount가 생성되면 자동으로 토큰을 생성한다*. 이 토큰을 이용하여 외부 애플리케이션이 Kubernetes API에 Authenticate할 수 있다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;kubectl describe serviceaccount account-name&lt;/code&gt;을 하면, &lt;code&gt;Tokens:&lt;/code&gt;에 &lt;code&gt;account-name-token-kbbdm&lt;/code&gt; 식으로 되어 있을 것이다.&lt;ul&gt;
&lt;li&gt;이것은 &lt;code&gt;account-name-token-kbbdm&lt;/code&gt; Secret object에 토큰이 들어있다는 것이다.&lt;ul&gt;
&lt;li&gt;&lt;code&gt;kubectl describe secret 시크릿명&lt;/code&gt;으로 secret 내부를 볼 수 있다.&lt;ul&gt;
&lt;li&gt;여기에 있는 토큰을 HTTP Bearer Auth로 쓰면 쿠버 API에 접속이 가능하다.&lt;ul&gt;
&lt;li&gt;&lt;code&gt;curl --header &amp;quot;Authorization: Bearer 토큰&amp;quot;&lt;/code&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;p&gt;※ 주의사항: 쿠버 1.24부터는 ServiceAccount 생성 시 자동으로 토큰을 생성하지 않는다. 아래 [[167. Service Accounts#쿠버 1.24의 변경사항|쿠버 1.24의 변경사항]] 참조.&lt;/p&gt;
&lt;h3&gt;쿠버 클러스터 내부에서 Service Account 사용&lt;/h3&gt;
&lt;p&gt;만약 그 애플리케이션이 쿠버 내부에 Pod으로 존재한다면 어떨까?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;그러면 토큰을 굳이 Secret에서 꺼내서 애플리케이션에 복사해줄 필요 없이, 그냥 Secret을 Pod 내부 Volume으로 마운트해서 쓸 수 있을 것이다.&lt;ul&gt;
&lt;li&gt;[[100-104. Environment Variables and Configure Secrets in Application#Secret의 사용|시크릿의 사용]] 참조&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;사실, 모든 Kubernetes 네임스페이스에서는 이미 default라는 이름의 Service Account가 자동 생성되어 있다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;또, 해당 네임스페이스의 default SA의 토큰 Secret이 Pod에 Volume Mount로 들어간다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;kubectl get pod 뭐시기 -o yaml&lt;/code&gt; 해 보면 알 수 있음&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kubectl exec -it my-kubernets-dashboard cat /var/run/secrets/kubernets.io/serviceaccount/token&lt;/code&gt;&lt;ul&gt;
&lt;li&gt;굳이 이 default SA를 사용하고 싶지 않다면, Pod의 &lt;code&gt;spec.automountServicAccountToken&lt;/code&gt;을 false로 지정하면 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;이 default SA는 사용할 수 있는 API라우트가 상당히 제약이 많은 친구이다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;커스텀 SA를 이용하려면, &lt;code&gt;spec.serviceAccountName&lt;/code&gt;에 지정해주면 된다.&lt;/li&gt;
&lt;li&gt;Pod의 경우, Service Account를 바꾸려면 삭제 후 다시 만들어야 한다.&lt;/li&gt;
&lt;li&gt;Deployment의 경우, edit나 apply로 SA 수정이 가능하다.&lt;ul&gt;
&lt;li&gt;SA가 수정되면, Deployment가 알아서 Pod을 삭제하고 재생성한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;쿠버 1.22의 변경사항&lt;/h2&gt;
&lt;p&gt;이 토큰이라는 것은 사실 JWT(JSON Web Token)이다. 토큰을 디코딩해 봤을 때, 구버전에서는 토큰의 만료일 값에 대한 언급이 없음을 알 수 있다.&lt;/p&gt;
&lt;p&gt;쿠버 1.22에서는 KEP 1205에 따라 &lt;code&gt;TokenRequestAPI&lt;/code&gt;가 등장하였다. TokenRequestAPI를 통해 생성된 토큰은,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Audience Bound&lt;/li&gt;
&lt;li&gt;Time Bound&lt;/li&gt;
&lt;li&gt;Object Bound&lt;br&gt;하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이제 Pod이 생성될 때 default service account 토큰을 이용하는 게 아니라, TokenRequestAPI를 통해 Service Account Admission Controller에 의해 유한한 수명을 가진 토큰이 생성되어, project volume으로 마운트되게 된다.&lt;/p&gt;
&lt;h2&gt;쿠버 1.24의 변경사항&lt;/h2&gt;
&lt;p&gt;KEP 2799에 따라, Service Account 생성 시 토큰이 자동으로 발행되지 않는다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;kubectl create token account-name&lt;/code&gt;을 해서 따로 토큰을 발행해야 한다.&lt;ul&gt;
&lt;li&gt;이렇게 발행된 토큰은 Secret으로 저장되지 않으며 그냥 콘솔에 출력된다.&lt;/li&gt;
&lt;li&gt;이렇게 발행된 토큰은 유효기간이 존재하는 신형 토큰이며, 유효기간의 기본값은 1시간이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;구버전식 무기한토큰을 생성하고자 하는 경우 따로 Secret definition file을 생성하여야 한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;apiVersion: v1
kind: Secret
type: kubernetes.io/service-account-token
metadata:
  name: secretname
  annotations:
    kubernetes.io/service-account.name: account-name&lt;/code&gt;&lt;/pre&gt;</description>
      <category>콤퓨우터/필기: KodeKloud CKA 강의</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/95</guid>
      <comments>https://pscr.tistory.com/95#entry95comment</comments>
      <pubDate>Fri, 17 May 2024 00:39:51 +0900</pubDate>
    </item>
    <item>
      <title>160-164. Authorisation, RBAC and Cluster Roles</title>
      <link>https://pscr.tistory.com/94</link>
      <description>&lt;h1&gt;Authentication and Authorization&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Authentication은 특정 사용자가 어떤 클러스터에 접근할 수 있는지 없는지를 결정&lt;/li&gt;
&lt;li&gt;Authorisation은 특정 사용자가 그 클러스터에서 뭘 할 수 있는지를 결정&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;특정 사용자에 대해 모든 관리 권한을 다 주고 싶지 않을 수 있다&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;노드를 삭제한다든지, 네트워크를 박살낸다든지 하는 위험한 짓은 하지 말고, Pod deployment 정도는 하게 할 수 있다.&lt;/li&gt;
&lt;li&gt;특정 봇에 대해서는 모니터링에 필요한 최소 권한만 주고자 할 수 있다.&lt;/li&gt;
&lt;li&gt;여러 클러스터를 공유하면서 네임스페이스로 논리적 분리한 환경에서는, 관리자가 할당된 네임스페이스에 대해서만 관리 가능하게 권한을 짜고자 할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Authorisation의 메커니즘&lt;/h2&gt;
&lt;h3&gt;Node based&lt;/h3&gt;
&lt;p&gt;예를 들어, kubelet의 인증서는 &lt;code&gt;/O=system:node&lt;/code&gt; 그룹이어야 하고 이름은 &lt;code&gt;/CN=system:node:뭐시기&lt;/code&gt; 형식을 따라야 한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;이런 형식의 인증서를 가지고 있으면 Node-authorizer를 통해 시스템 노드 권한을 부여받는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Attributed-Based Access Control (ABAC)&lt;/h3&gt;
&lt;p&gt;Attributed-Based Access Control (ABAC)는 특정 사용자나 그룹에 권한-뭉탱이를 할당하는것으로, API의 외부 접근 시 등에 사용할 수 있다.&lt;/p&gt;
&lt;p&gt;예를 들어 dev-user라는 사용자에 Pod에 대한 권한 (생성, 삭제, 확인)을 주고 싶다면,&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{&amp;quot;kin&amp;quot;: &amp;quot;Policy&amp;quot;, &amp;quot;spec&amp;quot;: {&amp;quot;user&amp;quot;: &amp;quot;dev-user&amp;quot;, &amp;quot;namespace&amp;quot;: &amp;quot;*&amp;quot;, &amp;quot;resource&amp;quot;: &amp;quot;pods&amp;quot;, &amp;quot;apiGroup&amp;quot;: &amp;quot;*&amp;quot;}}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;같은 파일을 kube-apiserver에 넣고 재시작해야한다.&lt;/p&gt;
&lt;p&gt;이것은 별로 scale-up되기 좋은 방식은 아니다.&lt;/p&gt;
&lt;h3&gt;Role-Based Access Control (RBAC)&lt;/h3&gt;
&lt;p&gt;특정한 Role(예를 들어 developer)을 만들고 권한-뭉탱이를 할당한 뒤, 그 role을 사용할 사용자나 그룹에 전부 그 role을 associate하는것이다.&lt;/p&gt;
&lt;h3&gt;Webhook&lt;/h3&gt;
&lt;p&gt;모든 authorization을 외부 authorization provider에 맡기기&lt;/p&gt;
&lt;h3&gt;AlwaysAllow &amp;amp; AlwaysDeny&lt;/h3&gt;
&lt;p&gt;제곧내&lt;/p&gt;
&lt;h2&gt;Authorisation Mode를 어떻게 설정하는가?&lt;/h2&gt;
&lt;p&gt;kube-apiserver 실행 파라미터에 들어가있다. 예를 들어 kube-apiserver가 systemd service로 디플로이되어 있다면,&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ExecStart=/usr/local/bin/kube-apiserver \\
...
  --authorization-mode=Node,RBAC,Webhook
...&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;같은 식이다.&lt;/p&gt;
&lt;p&gt;여러 개의 authorisation mode가 설정된 경우, 서순대로 작동한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;위의 예시에서는, 특정 요청이 Node에서 deny되면 RBAC로 넘어가고, RBAC에서도 deny당하면 Webhook으로 넘어간다.&lt;ul&gt;
&lt;li&gt;3개 중의 하나라도 OK사인을 주면 요청은 Accept된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;RBAC&lt;/h1&gt;
&lt;h3&gt;생성하기&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: developer
rules:
- apiGroups: [&amp;quot;&amp;quot;] # Core API Group일 경우 공백으로 비워둠
  resources: [&amp;quot;pods&amp;quot;]
  verbs: [&amp;quot;list&amp;quot;, &amp;quot;get&amp;quot;, &amp;quot;create&amp;quot;, &amp;quot;update&amp;quot;, &amp;quot;delete&amp;quot;]
  # Optional: 예를 들어 특정 Pod에 대해서만 권한을 허가하고 싶은 경우:
  resourceNames: [&amp;quot;blue&amp;quot;, &amp;quot;orange&amp;quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이후 &lt;code&gt;kubectl create -f&lt;/code&gt;로 생성, &lt;code&gt;kubectl get roles&lt;/code&gt;와 &lt;code&gt;kubectl describe role developer&lt;/code&gt;로 확인 가능하다.&lt;/p&gt;
&lt;h3&gt;사용자와 그룹을 Role에 Binding하기&lt;/h3&gt;
&lt;p&gt;이 때에는 Role Binding Object YAML 파일을 만들어야 한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: developer-binding
subjects:
- kind: User
  name: dev-user
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role # 생성한 Role의 이름
  name: developer
  apiGroup: rbac.authorization.k8s.io&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이후 &lt;code&gt;kubectl create -f&lt;/code&gt;로 생성, &lt;code&gt;kubectl get rolebindings&lt;/code&gt;와 &lt;code&gt;kubectl describe rolebinding developer-binding&lt;/code&gt;으로 확인 가능하다.&lt;/p&gt;
&lt;h2&gt;사용자 입장에서 권한 확인하기&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;kubectl auth can-i&lt;/code&gt; 명령어를 이용하면 yes, no로 대답해준다&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;kubectl auth can-i create deployments&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kubectl auth can-i delete nodes&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;관리자인 경우, 특정 사용자의 권한을 체크하는 것도 가능하다&lt;br&gt;&lt;code&gt;kubectl auth --as dev-user&lt;/code&gt; 같은 식으로 사용하면 된다.&lt;/p&gt;
&lt;h1&gt;Cluster Roles&lt;/h1&gt;
&lt;p&gt;Role와 Role Binding은 네임스페이스된다 - 별도의 지정이 없으면 네임스페이스 default에 대한 Role과 Role Binding으로 적용된다.&lt;/p&gt;
&lt;p&gt;하지만 생각해보자. &amp;quot;노드&amp;quot;는 네임스페이스에 할당할 수 없다!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;이것을 Cluster-Scoped라고 함&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;노드처럼 Cluster-Scoped된 리소스들에는 PV, CSR, namespaces 등이 있다&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;전체를 보려면 &lt;code&gt;kubectl api-resources --namespaced=true&lt;/code&gt; 로 확인 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이런 Cluster-Scoped 리소스를 할당하기 위해 Cluster Roles, Cluster Role Bindings이 존재한다&lt;/p&gt;
&lt;h3&gt;Cluster Role 생성하기&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: cluster-admin-role
rules:
- apiGroups: [&amp;quot;&amp;quot;] # Core API Group일 경우 공백으로 비워둠
  resources: [&amp;quot;nodes&amp;quot;]
  verbs: [&amp;quot;list&amp;quot;, &amp;quot;get&amp;quot;, &amp;quot;create&amp;quot;, &amp;quot;update&amp;quot;, &amp;quot;delete&amp;quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Cluster Role Binding 생성하기&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: cluster-admin-role-binding
subjects:
- kind: User
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role # 생성한 Role의 이름
  name: cluster-admin-role
  apiGroup: rbac.authorization.k8s.io&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;똣갓내;;&lt;/p&gt;
&lt;h3&gt;참조사항&lt;/h3&gt;
&lt;p&gt;Cluster Role은 Cluster-Scopped 리소스뿐만이 아니라 namespaced 리소스에 대해서도 적용이 가능하다&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;만약 Pod에 대한 Cluster Role을 주었다면, 해당 클러스터에 있는 노드 전체에 대해 적용되는 것이다&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>콤퓨우터/필기: KodeKloud CKA 강의</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/94</guid>
      <comments>https://pscr.tistory.com/94#entry94comment</comments>
      <pubDate>Fri, 17 May 2024 00:39:19 +0900</pubDate>
    </item>
    <item>
      <title>159. API Groups</title>
      <link>https://pscr.tistory.com/93</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;kubectl get pods&lt;/code&gt; 명령어같은 것들은 뒤에서는 &lt;code&gt;kube-apiserver&lt;/code&gt;에 6443번 포트, TLS로 붙어서 정보를 받아온다.&lt;br /&gt;즉 kubectl은 뒤에서 &lt;code&gt;GET /api/v1/pods HTTP/1.1&lt;/code&gt; 요청을 보내고, JSON으로 데이터가 반환되며, 이것을 예쁘게 가공해서 출력하는것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;kubectl version&lt;/code&gt;도 마찬가지다. &lt;code&gt;GET /version HTTP/1.1&lt;/code&gt;을 보낼것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(실제로는 HTTP 1.1은 아닐 수도 있겠지만, 아무튼)&lt;/p&gt;
&lt;h1&gt;엔드포인트&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 엔드포인트를 잘 보자.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;/api&lt;/code&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;/api/v1/pods&lt;/code&gt;, ...&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/version&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/metrics&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/healthz&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/apis&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/logs&lt;/code&gt;&lt;br /&gt;이렇게 쿠버 API는 역할별로 그룹이 나누어져 있는데, 이것이 API Group이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Pasted image 20240505040032.png&quot; data-origin-width=&quot;1162&quot; data-origin-height=&quot;902&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vushV/btsHsaNcTvN/xg5B4I5FEXjwhzXjGvSkjk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vushV/btsHsaNcTvN/xg5B4I5FEXjwhzXjGvSkjk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vushV/btsHsaNcTvN/xg5B4I5FEXjwhzXjGvSkjk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvushV%2FbtsHsaNcTvN%2Fxg5B4I5FEXjwhzXjGvSkjk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1162&quot; height=&quot;902&quot; data-filename=&quot;Pasted image 20240505040032.png&quot; data-origin-width=&quot;1162&quot; data-origin-height=&quot;902&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;code&gt;/api&lt;/code&gt;와 &lt;code&gt;/apis&lt;/code&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클러스터 기능에 직접적으로 영향을 주는 API들이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;/api/v1&lt;/code&gt;는 코어 그룹이다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;namespaces, pods, rc, events, endpoints, nodes, bindings, pv, pvc, configmaps, secrets, services... 같은 코어 기능들.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/apis&lt;/code&gt;는 조금 더 체계적으로 분류되어있는 API 그룹으로, 신기능들은 이 named group을 통해 제공된다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;apps, extensions, networking.k8s.io, storage.k8s.io, authentication.k8s.io, certificates.k8s.io,... 같은 API Groups이 있고
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그 하위에 Resources들이 있으며 &lt;code&gt;/apis/apps/v1/deployments&lt;/code&gt;, &lt;code&gt;/apis/apps/v1/replicasets&lt;/code&gt;, &lt;code&gt;/apis/apps/v1/statefulsets&lt;/code&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그 하위에 Verbs, (list, get ,create, delete, update, watch...) 들이 있다.&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;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;Pasted image 20240505040049.png&quot; data-origin-width=&quot;2360&quot; data-origin-height=&quot;1242&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcdiwW/btsHq6LHXIa/NV6N0mpGXSMcRIZGZTT1kK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcdiwW/btsHq6LHXIa/NV6N0mpGXSMcRIZGZTT1kK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcdiwW/btsHq6LHXIa/NV6N0mpGXSMcRIZGZTT1kK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcdiwW%2FbtsHq6LHXIa%2FNV6N0mpGXSMcRIZGZTT1kK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2360&quot; height=&quot;1242&quot; data-filename=&quot;Pasted image 20240505040049.png&quot; data-origin-width=&quot;2360&quot; data-origin-height=&quot;1242&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;h1&gt;curl로 API에 편하게 붙기: kubectl proxy&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 curl로 API에 붙으려면 클라이언트 인증서, CA 인증서 등등을 파라미터로 덕지덕지 붙여야한다.&lt;br /&gt;이 때 &lt;code&gt;kubectl proxy&lt;/code&gt;를 이용하면 kubectl이 대신 인증을 서 주는 프록시를 생성해주므로, 간단하게 curl을 쓸 수 있게 된다.&lt;/p&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;$ kubectl proxy
Starting to serve on 127.0.0.1:8001

$ curl http://localhost:8001 -k
{
 &quot;paths&quot;: [
   &quot;/api&quot;,
   ...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;kubectl proxy&lt;/code&gt;와 &lt;code&gt;kube proxy&lt;/code&gt;는 다른 것이므로 주의!&lt;/p&gt;</description>
      <category>콤퓨우터/필기: KodeKloud CKA 강의</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/93</guid>
      <comments>https://pscr.tistory.com/93#entry93comment</comments>
      <pubDate>Fri, 17 May 2024 00:38:59 +0900</pubDate>
    </item>
    <item>
      <title>155. Kubeconfig와 context</title>
      <link>https://pscr.tistory.com/92</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 쿠버 컴포넌트 간의 통신은 모두 TLS Client Certificate를 요구한다. curl로 직접 API에 엑세스한다면,&lt;br /&gt;&lt;code&gt;curl https://controlplane:6443/api/v1/pods --key admin.key --cert admin.crt --cacert ca.crt&lt;/code&gt; 같은 식으로 인증서를 제공해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kubectl에서도 마찬가지이다. 실제로&lt;br /&gt;&lt;code&gt;kubectl get pods --server controlplane --client-key admin.key --client-certificate admin.crt --certificate-authority ca.crt&lt;/code&gt;&lt;br /&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;기본적으로 kubeconfig 파일의 참조 기본값은 &lt;code&gt;$HOME/.kube/config&lt;/code&gt;이다.&lt;/p&gt;
&lt;h1&gt;구조&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kubeconfig 파일은 cluster, context, user의 3가지 구성요소로 구성&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Pasted image 20240505032653.png&quot; data-origin-width=&quot;1388&quot; data-origin-height=&quot;864&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c4VyDl/btsHr8BQqdZ/xxbkAYkqixv292RkOXltq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c4VyDl/btsHr8BQqdZ/xxbkAYkqixv292RkOXltq1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c4VyDl/btsHr8BQqdZ/xxbkAYkqixv292RkOXltq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc4VyDl%2FbtsHr8BQqdZ%2FxxbkAYkqixv292RkOXltq1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1388&quot; height=&quot;864&quot; data-filename=&quot;Pasted image 20240505032653.png&quot; data-origin-width=&quot;1388&quot; data-origin-height=&quot;864&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Cluster와 User를 짝지어놓은 것을 Context&lt;/b&gt;라고 한다.&lt;br /&gt;어떤 클러스터에 접근하기 위해 어떤 사용자를 사용할 것인가... 를 미리 짝지어 놓고, &lt;code&gt;kubeclt --context 뭐시기&lt;/code&gt;만으로 간편하게 리용하자는것이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Cluster에는 &lt;code&gt;--server controlplane:6443&lt;/code&gt;, &lt;code&gt;--certificate-authority ca.crt&lt;/code&gt;같은 정보가 들어감&lt;/li&gt;
&lt;li&gt;User에는 &lt;code&gt;--client-certificate&lt;/code&gt;, &lt;code&gt;client-key&lt;/code&gt;같은 정보가 들어감&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;http&quot;&gt;&lt;code&gt;apiVersion: v1
kind: Config

current-context: context-기본값

clusters:
- my-kube-playground
  cluster:
    certificate-authority: /path/to/ca.crt
    server: https://controlplane:6443

contexts:
- name: my-kube-admin@my-kube-playground
  context:
    cluster: my-kube-playground
    user: my-kube-admin
    namespace: finance # 네임스페이스 필드를 선언하지 않을 경우 default 네임스페이스 사용

users:
- name: my-kube-admin
  user:
    client-certificate: /path/to/client.crt
    client-key: /path/to/key.crt
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;KubeConfig Object는 &lt;code&gt;kubectl create -f&lt;/code&gt;로 생성하지 않는다&lt;/b&gt;. 그냥 적당한 위치(기본값은 &lt;code&gt;$HOME/.kube/config&lt;/code&gt;)에 놓으면 kubectl에서 알아서 읽는다.&lt;/p&gt;
&lt;h1&gt;kubectl에서 이용&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;kubectl config view&lt;/code&gt;로 사용하고 있는 kubeconfig를 볼 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--kubeconfig=&lt;/code&gt;로 다른 kubeconfig를 지정할 수 있다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;`kubectl config current-context --kubeconfig /root/my-kube-config&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Current Context의 변경&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;kubectl config use-context prod-user@production&lt;/code&gt; 같은 식으로 변경할 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이렇게 변경한 context는 &lt;b&gt;실제 KubeConfig Object 설정파일에도 반영&lt;/b&gt;된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;팁&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;clusterrs.cluster.certificate-authority: 경로&lt;/code&gt; 식으로 주지 않고, 그냥 &lt;code&gt;clusterrs.cluster.certificate-authority: (BASE64된-인증서)&lt;/code&gt; 식으로, kubeconfig 파일 내부에 인증서를 때려넣을수도 있다.&lt;/p&gt;</description>
      <category>콤퓨우터/필기: KodeKloud CKA 강의</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/92</guid>
      <comments>https://pscr.tistory.com/92#entry92comment</comments>
      <pubDate>Fri, 17 May 2024 00:35:57 +0900</pubDate>
    </item>
    <item>
      <title>147-152. View Certificate Details and Certificates API</title>
      <link>https://pscr.tistory.com/91</link>
      <description>&lt;h1&gt;인증서 문제&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿠버에서 인증서 관련 문제를 해결하려면 일단 해당 쿠버 클러스터가 어떻게 디플로이되었는지를 알아야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 kubeadm을 사용하여 올렸다면 상당 부분을 알아서 해준다&lt;br /&gt;kubeadm은 쿠버의 컴포넌트들을 Static Pods으로 올려준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 kube-apiserver는 &lt;code&gt;/etc/kubernetes/manifests/kube-apsierver.yaml&lt;/code&gt;에 Pod Specification이 있고, 이 파일의 &lt;code&gt;spec.containers.command&lt;/code&gt; 하위의 파라미터들을 통해, kube-apiserver의 인증서들의 존재를 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 인증서 파일에 대해 &lt;code&gt;openssl x509 -in /path/to/cert.crt -text&lt;/code&gt; 명령어로 Readable text 형태의 인증서를 볼 수 있다.&lt;br /&gt;확인해야 할 것:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Issuer CN&lt;/li&gt;
&lt;li&gt;Validity&lt;/li&gt;
&lt;li&gt;Subject CN&lt;/li&gt;
&lt;li&gt;SAN&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;로깅&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿠버 구축을 제로부터 시작했다면 systemd service로 구현했을 텐데, 그러면 &lt;code&gt;journalctl -u 서비스명&lt;/code&gt;을 통해 로그를 찍어보는것이 좋을것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kubeadm을 이용해 구축했다면 Static Pod이므로, &lt;code&gt;kubectl logs etcd-master&lt;/code&gt;처럼 Pod명으로 kubectl을 돌리면 된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;kube-apiserver나 etcd가 죽었다면 kubectl은 작동하지 않을것이다. 이 경우 &lt;code&gt;docker ps -a&lt;/code&gt;를 해서 컨테이너명을 확인한 뒤 &lt;code&gt;docker logs 컨테이너ID&lt;/code&gt;로 직접 컨테이너 로그를 찍어야 한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컨테이너 런타임이 docker가 아닌 경우 &lt;code&gt;crictl&lt;/code&gt;(CRI-O), &lt;code&gt;nerdctl&lt;/code&gt;(containerd) 등을 사용하면 된다&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;h1&gt;Certificates API - 왜 사용하는가&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;CA라는 것은 근본적으로는 인증서와 Private Key 파일 쌍&lt;/b&gt;에 불과하다.&lt;br /&gt;하지만 그 두 파일의 중요성은 말할 필요가 없다. CA 인증서와 키가 있으면 기본적으로 쿠버 클러스터에 대한 무제한적인 권한이 있는것과 다름없다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 인증서는 만료기간이 있으며, 이것을 계속해서 rotating(기간연장발급 후 교체)해 줘야 정상적으로 사용할 수 있다 (옛날 공인인증서를 생각해보자)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그럼 이것을 어떻게 보관할 것인가?&lt;/li&gt;
&lt;li&gt;또 인증서를 발행과 rotating을 위한 채널을 만들 수는 없을까?&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지는,&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;제로부터 구축하는 쿠버클러스터 구성에서는, 그냥 master node에 놓았다&lt;/li&gt;
&lt;li&gt;kubeadm으로 구축하더라도 마찬가지이다&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Certificates API&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CSR Request? API로 쏘세요
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;API Object인 CreateCertificateSigningRequest를 생성&lt;/li&gt;
&lt;li&gt;kubectl 명령어를 이용해 approve&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;실제 인증서 발행&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;PK 발행: &lt;code&gt;openssl genrsa -out jane.key 2048&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;CSR 생성: &lt;code&gt;openssl req -new -key jane.key -subj=&quot;/CN=jane&quot; -out jane.csr&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;다른 관리자가 이 CSR를 받아, CreateSigningRequest Object를 생성:
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: jane
spec:
  expirationSeconds: 600
  usages:
  - digital signature
  - key encipherment
  - server auth
  request:
    (base64 인코드된 CSR)&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kubectl create -f jane-csr.yaml&lt;/code&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;kubectl get csr&lt;/code&gt;로 생성된 CSR 요청을 볼 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kubectl certificate approve jane&lt;/code&gt;으로 인증서 발급 요청을 허가
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;kubectl get csr -o yaml&lt;/code&gt;로 발행된 인증서를 볼 수 있음 (base64 인코드됨)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Under the hood&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;controller-manager에서 처리 (&lt;code&gt;csr-approving&lt;/code&gt;, &lt;code&gt;csr-signing&lt;/code&gt;)&lt;br /&gt;Kubeadm으로 디플로이된 환경의 경우 &lt;code&gt;/etc/kubernetes/manifests/kube-controller-manager.yaml&lt;/code&gt;에서 CA Cert/Key 확인 가능&lt;/p&gt;</description>
      <category>콤퓨우터/필기: KodeKloud CKA 강의</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/91</guid>
      <comments>https://pscr.tistory.com/91#entry91comment</comments>
      <pubDate>Fri, 17 May 2024 00:33:51 +0900</pubDate>
    </item>
    <item>
      <title>146. TLS in Kubernetes</title>
      <link>https://pscr.tistory.com/90</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;쿠버에는 기본적으로 (관리자, 개발자 같은) 사용자라는 개념이 없다. &lt;code&gt;kubectl create user user-name&lt;/code&gt; 같은 식으로 사용자를 생성하는 것은 당연히 불가능&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다만, 사람이 아닌 entity를 위한 Service Account라는 개념은 존재한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 kube-apiserver에 들어오는 API 콜 (kubectl이든 HTTP API endpoint를 통한 직접 접근이든) 을 무조건 다 받아주면 안되는 것은 자명하다. 어떻게든 user authentication을 거친 뒤에 리퀘를 받아줘야 하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Kubernetes 1.19까지는 Client Certificate를 사용하지 않고 인증하는 방식들이 있었다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;비밀번호,사용자이름,사용자ID[,그룹]&lt;/code&gt; 형식의 CSV파일을 넣은 뒤, 요청 시 ID:PW를 HTTP 헤더에 넣어서 보내는 방법 (HTTP Digest Auth)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;토큰,사용자이름,사용자명[,그룹]&lt;/code&gt; 형식의 토큰 파일을 만든 뒤, 요청 시 해당 토큰을 HTTP 헤더에 넣어서 보내는 방법 (HTTP Basic Auth)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당연히 별로 안전한 방식은 아니었기 때문에 전부 지원이 삭제되었고, 지금은 TLS의 Client Certificate를 사용하는 방식으로 바뀌었다.&lt;/p&gt;
&lt;h1&gt;Client &amp;amp; Server Certificates&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적인 웹에서는 TLS 연결 시 클라이언트가 서버 인증서를 검증하지, 그 역으로는 잘 안 한다. (아무래도 접속할 때마다 사용자에게 인증서를 고르라고 하는 것은 UX가 별로이기 때문에)&lt;br /&gt;하지만 클라이언트 인증서 검증은 엄연히 TLS 스펙상에 존재하는 방식이고, 브라우저들에서도 구현을 하고 있으며, 실제로 일부 사이트들은 (업무용 사이트라든가?) 웹에서도 클라이언트 인증서 검증을 하기도 한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿠버네티스에서는 거의 모든 서비스와의 상호작용에 TLS 연결을 사용하고, 또 클라이언트 인증서 검증을 요구한다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 말은, 그만큼 연관되는 인증서가 많다는 뜻이다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관리자가 kubectl로 kube-apiserver에 접근하거나 kube-scheduler가 kube-apiserver에 접근하는 시나리오 모두에서 마찬가지로 클라/서버 쌍방 인증서 검증이 요구된다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;주의할 점은, 같은 엔티티가 상황에 따라 서버가 될 수도 있고, 클라이언트가 될 수도 있다는 점이다
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예를 들어 kube-apiserver는 kubectl 입장에서는 서버이지만, etcd에 접속할 때에는 kube-apiserver가 클라이언트이다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 때 두 용도 모두에 1개의 인증서-키 쌍을 이용하거나, 아니면 서버일 때 쓰는 인증서, 클라이언트일 때 쓰는 인증서를 나눠서 구성하는 것도 가능하다.&lt;/li&gt;
&lt;/ul&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Pasted image 20240504033502.png&quot; data-origin-width=&quot;2382&quot; data-origin-height=&quot;1232&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lRKo0/btsHruFBtiF/ZRgEnYzDdn0IwDwYJW90eK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lRKo0/btsHruFBtiF/ZRgEnYzDdn0IwDwYJW90eK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lRKo0/btsHruFBtiF/ZRgEnYzDdn0IwDwYJW90eK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlRKo0%2FbtsHruFBtiF%2FZRgEnYzDdn0IwDwYJW90eK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2382&quot; height=&quot;1232&quot; data-filename=&quot;Pasted image 20240504033502.png&quot; data-origin-width=&quot;2382&quot; data-origin-height=&quot;1232&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 이 인증서들은 전부 Self-signed certificate일 수는 없다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하나의 쿠버 클러스터에는 최소 1개의 CA가 필요하고, 저 인증서들은 모두 해당 CA에서 서명한 것이어야 한다
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ETCD를 담당하는 CA와 나머지를 담당하는 또 하나의 CA로 분리하여 2CA 구성을 하는 것도 가능하다
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 경우, etcd에 접근하기 위한 클라이언트 인증서는 etcd 담당 CA에서 서명한 것이어야 한다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;CA 인증서 생성&lt;/h1&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;CA용 RSA 2048bit Private Key를 생성&lt;br /&gt;&lt;code&gt;openssl genrsa -out ca.key 2048&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;CA 인증서 발행을 위한 CSR 생성&lt;br /&gt;&lt;code&gt;openssl req -new -key ca.key -subj &quot;/CN=CA-NAME&quot; -out ca.csr&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;CSR을 이용하여 Self-Signed CA Certificate 생성&lt;br /&gt;&lt;code&gt;openss x509 -req -in ca.csr -signkey -ca.key -out ca.crt&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Client Certificate 생성&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관리자용 Client Certificate를 생성한다고 가정하자&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;RSA 2048bit Private Key를 생성&lt;br /&gt;&lt;code&gt;openssl genrsa -out admin-name.key 2048&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;CA 인증서 발행을 위한 CSR 생성&lt;br /&gt;&lt;code&gt;openssl req -new -key admin-name.key -subj &quot;/CN=사용자-이름/O=system:masters&quot; -out admin-name.csr&lt;/code&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;system:masters&lt;/code&gt;: Admin Group&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;CSR을 이용하여 관리자용 Client Certificate 생성, CA의 인증서와 keypair로 서명&lt;br /&gt;&lt;code&gt;openss x509 -req -in admin-name.csr -CA ca.csr -CAKey ca.key -out admin-name.crt&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비슷한 과정을 kube-scheduler, kube-controller-manager, kube-proxy 등에 대해서도 진행한다&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;주의사항&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CA의 인증서는 모든 클라이언트와 서버에 배포되어 있어야 한다&lt;/p&gt;
&lt;h1&gt;etcd에서의 인증서&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;etcd-server&lt;/code&gt;이름으로 생성&lt;br /&gt;HA 구성에서는 etcd가 여러 개 있을 수도 있다, 이 경우 여러 peer certificate이 필요&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구성의 상상도:&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Pasted image 20240504042045.png&quot; data-origin-width=&quot;1054&quot; data-origin-height=&quot;1014&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lpahi/btsHsQtTgot/rGyeEcUo5ZQpv63ENvGpNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lpahi/btsHsQtTgot/rGyeEcUo5ZQpv63ENvGpNK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lpahi/btsHsQtTgot/rGyeEcUo5ZQpv63ENvGpNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Flpahi%2FbtsHsQtTgot%2FrGyeEcUo5ZQpv63ENvGpNK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1054&quot; height=&quot;1014&quot; data-filename=&quot;Pasted image 20240504042045.png&quot; data-origin-width=&quot;1054&quot; data-origin-height=&quot;1014&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 etcd.yaml을 다음과 같이 설정하여주어야한다.&lt;/p&gt;
&lt;pre class=&quot;haml&quot;&gt;&lt;code&gt;- etcd
...
    - --key-file=/path/to/etcdserver.key
    - --cert-file=/path/to/etcdserver.pem
    - --peer-cert-file=/path/to/etcdpeer1.pem
    - --peer-client-cert-auth=true
    - --peer-key-file=/etc/kubernetes/pki/etcd/peer.key
    - --peer-trusted-ca-file/etc/kubernetes/pki/etcd/ca.crt
    - --trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt
...&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;kube-apiserver에서의 인증서&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kube-apiserver는 쿠버에 있어서 매우 중요한 컴포넌트이고, 이 때문에 이명도 많다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;kubernetes&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kubernetes.default&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kubernetes.default.svc&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kubernetes.default.svc.cluster.local&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;클러스터 IP 주소&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 모든 것이 인증서에 SAN(Subect Alternative Name)으로 박혀있어야한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OpenSSL 1.1.1 출시 전까지는 SAN을 넣으려면 우선 OpenSSL conf 파일을 만들고, 이것을 파라미터로 &lt;code&gt;openssl req -new -key kubeapiserver.key -subj &quot;/CN=kube-apiserver&quot; -out apiserver.csr -config config.cnf&lt;/code&gt; 처럼 넘겨줘야 했다&lt;/p&gt;
&lt;pre class=&quot;makefile&quot;&gt;&lt;code&gt;[req]
req_extensions = v3_req
[v3_req]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation,
subjectAltName = @alt_names
[alt_names]
DNS.1 = kubernetes
DNS.2 = kubernetes.default
...
IP.1 = 10.96.0.1
...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OpenSSL 1.1.1부터는, 다음처럼 그냥 파라미터로 넘겨줄 수 있다&lt;br /&gt;&lt;code&gt;openssl req -new -key apiserver.key -subj=&quot;/CN=kube-apiserver&quot; -out apiserver.csr -addext -extension 'subjectAltName = DNS:kubernetes, DNS:kubernetes.default, IP:10.96.0.1&lt;/code&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무튼, 이렇게 CSR 파일을 만들었고, 이제 CA 인증서로 새 인증서를 서명하여 발급했다고 해 보자&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;적용하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;systemd service로 구동 중인 경우,&lt;/p&gt;
&lt;pre class=&quot;haml&quot;&gt;&lt;code&gt;ExecStart=/usr/local/bin/kube-apiserver \\
...
  --client-ca-file=/var/lib/kubernetes/ca.pem \\
  --tls-cert-file=/var/lib/kubernetes/apiserver.crt \\
  --tls-private-key=/var/lib/kubernetes/apiserver.key \\
...
  --etcd-cafile=/var/lib/kubernetes/ca.pem \\
  --etcd-certfile=/var/lib/kubernetes/apiserver-etcd-client.crt
  --etcd-keyfile=/var/lib/kubernetes/apiserver-etcd-client.key
...
  --kubelet-certificate-authority=/var/lib/kubernetes/ca.pem
  --kubelet-client-certificate=/var/lib/kubernetes/apiserver-kubelet-client.crt
  --kubelet-cient-key=/var/lib/kubernetes/apiserver-kubelet-client.key
...&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;kube-apiserver가 kubelet에 접속하는 경우에 사용하는 client cert/keypair도 존재
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;kube-apiserve는 노드 모니터링, pod 스케줄링 정보 전달 등을 위해 kubelet에 접속하는 일이 있음 (outbound)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Kubelet에서의 인증서&lt;/h1&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Kubelet의 서버 인증서&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름이 &lt;code&gt;kubelet&lt;/code&gt;이 아니라 &lt;code&gt;노드이름&lt;/code&gt;이어야 한다&lt;br /&gt;만들어진 인증서는 kubelet config file에 넣어준다&lt;/p&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;kind:KubeletConfiguration
apiVersion: kubelet.config.k8s.io/v1beta1
authentication:
  x509:
     clientCAFile: &quot;/var/lib/kubernetes/ca.pem&quot;
...
tlsCertFile: &quot;/var/lib/kubelet/kubelet-node01.crt&quot;
tlsPrivateKeyFile: &quot;/var/lib/kubelet/kubelet-node01.key&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Kubelet의 클라이언트 인증서&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kube-scheduler가 그렇듯 노드는 시스템 컴포넌트이므로, 클라이언트 인증서들은 &lt;code&gt;system:node:노드이름&lt;/code&gt;의 포맷을 따라야한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, kube-apiserver가 kubelet에 적절한 권한을 부여할 수 있도록, Organisation이 &lt;code&gt;system:nodes&lt;/code&gt;로 설정되어야 한다&lt;/p&gt;</description>
      <category>콤퓨우터/필기: KodeKloud CKA 강의</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/90</guid>
      <comments>https://pscr.tistory.com/90#entry90comment</comments>
      <pubDate>Fri, 17 May 2024 00:30:16 +0900</pubDate>
    </item>
    <item>
      <title>131. Backup and Restore</title>
      <link>https://pscr.tistory.com/89</link>
      <description>&lt;h1&gt;무엇을 백업할 것인가&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;방법 1: YAML object configuration file을 백업&lt;/li&gt;
&lt;li&gt;방법 2: ETCD를 통째로 백업&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;두 방법 모두 마운트해 준 Persistant Volume은 따로 백업해주어야 할 것이다&lt;/p&gt;
&lt;h1&gt;YAML Object Configuration File 백업&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;YAML 설정 디렉토리째로 백업하면 되지 않나요?&lt;ul&gt;
&lt;li&gt;이 경우 SCM (Git같은)에 소스코드와 함께 보관하는 것도 좋다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;문제점: Declarative Approach가 권장되는 방법이기는 하지만, 팀에서 누군가가 Imperative하게 Object를 생성/수정해 놓고서 문서화도 안하고 튀었을 수도 있다.&lt;/p&gt;
&lt;p&gt;해결책: kube-apiserver에 쿼리하여 현재 사용 중인 리소스 설정을 전부 YAML 형태로 내보내기한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;kubectl get all --all-namespaces -o yaml &amp;gt; backup.yaml&lt;/code&gt;&lt;ul&gt;
&lt;li&gt;하지만 일부 리소스 그룹은 이것으로 백업이 되지 않는다고 한다&lt;/li&gt;
&lt;li&gt;Velero와 같은 백업전용도구를 사용하는 것도 검토할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;ETCD 백업&lt;/h1&gt;
&lt;p&gt;일부 Managed Kubernetes 환경에서는 etcd 클러스터에 접근이 아예 불가능할 수도 있다. 그런 케이스에서는 이런 방법은 사용할 수 없을 것이다&lt;/p&gt;
&lt;h2&gt;ETCD 데이터 디렉토리째로 백업&lt;/h2&gt;
&lt;p&gt;etcd는 마스터노드에 위치한다. 만약 etcd의 systemd service 파일이 다음과 같다면,&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ExecStart=/usr/local/bin/etcd
 --data-dir=/var/lib/etcd&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;그냥 &lt;code&gt;/var/lib/etcd&lt;/code&gt;를 통째로 복사하면 아무튼 백업이 되는 것이다.&lt;/p&gt;
&lt;h2&gt;ETCD의 스냅샷 기능을 사용&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;스냅샷 박제: &lt;code&gt;ETDCTL_API=3 etcdctl snapshot save backup.db&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;스냅샷 확인: &lt;code&gt;ETCDTL_API=3 etcdctl snapshot status backup.db&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;스냅샷 복원&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;kube-apiserver&lt;/code&gt;를 정지한다&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;kube-apiserver가 의존하는 etcd 클러스터를 재시작해야 하기 때문)&lt;br&gt;&lt;code&gt;service kube-apiserver stop&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Snapshot Restore 명령어로 복구한다&lt;br&gt;(--data-dir 파라미터로 복원 데이터디렉토리를 지정해야 한다)&lt;br&gt;&lt;code&gt;ETDCTL_API=3 etcdctl snapshot restore backup.db --data-dir /var/lib/etcd-restored&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;이러면 &lt;strong&gt;&lt;em&gt;새로운 클러스터 설정&lt;/em&gt;&lt;/strong&gt;으로 복원이 된다&lt;br&gt;When etcd restores from a backup, it initializes a new cluster configuration and configures the members of etcd as new members to a new cluster. This is to prevent a new member from accidentally joining an existing cluster.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ETCD Configuration 파일 (쿠버를 구성한 방법에 따라 Pod definition file 또는 systemd service 파일이 될 수 있음)의 &lt;code&gt;--data-dir=&lt;/code&gt; 파라미터를 수정한다&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Pod Definition File:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;  volumes:
  - hostPath:
      path: /etc/kubernetes/pki/etcd # 이 부분이 아님
      type: DirectoryOrCreate
    name: etcd-certs
  - hostPath:
      path: /var/lib/etcd-new # 이 부분!
      type: DirectoryOrCreate
    name: etcd-data&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Systemd service file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Service]
User=etcd
Type=notify
ExecStart=/usr/local/bin/etcd \
  --name etcd-server \
  --data-dir=/var/lib/etcd-data-new \&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;systemd service file을 사용할 경우 디렉토리 권한에 주의할 것&lt;/p&gt;
&lt;p&gt;주의 사항: 실제로는 &lt;code&gt;etcdctl&lt;/code&gt;의 각 명령어에 &lt;code&gt;--endpoints=https://127.0.0.1:2379 --cacert=/etc/etcd/ca.crt --cert=/etc/etcd/etcd-server.crt --key=/etc/etcd/etcd-server.key&lt;/code&gt; 같이 etcd 엔드포인트, 인증서 등의 옵션을 명시하여야한다&lt;/p&gt;
&lt;h3&gt;ETCD member 체크하기&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;ETCDCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379 --cacert=/etc/etcd/pki/ca.pem --cert=/etc/etcd/pki/etcd.pem --key=/etc/etcd/pki/etcd-key.pem member list
882326955ca7477d, started, etcd-server, https://192.8.185.12:2380, https://192.8.185.12:2379, false&lt;/code&gt;&lt;/pre&gt;</description>
      <category>콤퓨우터/필기: KodeKloud CKA 강의</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/89</guid>
      <comments>https://pscr.tistory.com/89#entry89comment</comments>
      <pubDate>Fri, 17 May 2024 00:29:15 +0900</pubDate>
    </item>
    <item>
      <title>122-127. OS Upgrades, Kubernetes Software Versions, Cluster Upgrade Process</title>
      <link>https://pscr.tistory.com/88</link>
      <description>&lt;p&gt;기본적으로 업데이트를 하기 전에, ReplicaSet (이나 Deployment)를 잘 짜서, 한 서버를 내려버리더라도 다른 노드에서 필요한 Pod들이 잘 돌도록 구성할 필요가 있다.&lt;/p&gt;
&lt;p&gt;어떤 노드가 죽으면, 마스터노드가 죽은 노드에 있던 Pod들의 사망판정을 내리기까지 5분의 유예시간이 존재한다. 이것은 &lt;code&gt;kube-controller-manager --pod-eviction-timeout=5m0s&lt;/code&gt; 명령어로 수정할 수 있다.&lt;/p&gt;
&lt;h1&gt;Drain하기&lt;/h1&gt;
&lt;p&gt;노드를 drain하면, 해당 노드에 대한 스케줄링은 멈추고 노드에 있던 모든 Pod들은 종료된다. ReplicaSet같은 게 제대로 설정되어 있다면, 꺼진 Pod들은 다른 노드로 옮겨 갈 것이다. Pod들이 옮겨간 뒤에, 업데이트를 하든 뭘 하든 지지고볶으면 된다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;kubectl drain node-name&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;하고 싶었던 일을 다 끝내고 Drain했던 노드를 다시 올렸다면, uncordon을 진행해서 스케줄러를 원래대로 돌려놓아야 한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;drain: 노드에 새 Pod이 스케줄링되는 것을 차단하고, 모든 Pod들을 죽임&lt;/li&gt;
&lt;li&gt;cordon: 노드에 새 Pod이 스케줄링되는 것만 차단함&lt;/li&gt;
&lt;li&gt;uncordon: drain이나 cordon 상태를 해제함&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Drain이 안 될 때&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;controlplane ~ ➜  kubectl drain node01 --ignore-daemonsets
node/node01 cordoned
error: unable to drain node &amp;quot;node01&amp;quot; due to error:cannot delete Pods declare no controller (use --force to override): default/hr-app, continuing command...
There are pending nodes to be drained:
 node01
cannot delete Pods declare no controller (use --force to override): default/hr-app
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Pod이 ReplicaSet에 포함되어 있지 않은 경우 기본적으로 오류가 발생한다 (강제로 죽일 수는 있다)&lt;/p&gt;
&lt;h1&gt;버전&lt;/h1&gt;
&lt;p&gt;쿠버의 버전넘버는 여느 소프트웨어처럼 major-minor-patch 구성이다.&lt;br&gt;쿠버네티스는 여러 구성요소로 구성되지만, 이 모든 구성요소의 버전이 같아야 하는 것은 아니다.&lt;/p&gt;
&lt;p&gt;아래는 Kubernetes 프로젝트에서 관리하여 같은 versoning scheme을 가지고 같이 배포되는 구성요소이다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;kube-apiserver&lt;/li&gt;
&lt;li&gt;controller-manager&lt;/li&gt;
&lt;li&gt;kube-scheduler&lt;/li&gt;
&lt;li&gt;kubelet&lt;/li&gt;
&lt;li&gt;kube-proxy&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;하지만 etcd, CoreDNS 등은 외부 프로젝트에서 관리하므로 쿠버 버전을 따라가지 않는다.&lt;/p&gt;
&lt;p&gt;쿠버를 업데이트할 때에는 먼저 kube-apiserver부터 업데이트한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;kubectl을 제외한 다른 모든 컴포넌트들의 버전은 kube-apiserver의 버전보다 낮거나 같아야 한다.&lt;ul&gt;
&lt;li&gt;controller-manager와 scheduler는 kube-apiserver보다 1 마이너 버전만큼 낮을 수 있다. (예를 들어 kube-apiserver 버전이 1.10이라면, scheduler는 1.9로 사용가능)&lt;/li&gt;
&lt;li&gt;kubelet와 kube-proxy는 kube-apiserver보다 2 마이너 버전만큼 낮을 수 있다. (예를 들어 kube-apiserver 버전이 1.10이라면, kubelet은 1.8까지 사용가능)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;kube-apiserver 버전이 1.10이라면 kubectl은 1.9 ~ 1.11까지 사용 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;쿠버는 업데이트 시 마이너 버전을 1씩만 올릴 수 있도록 되어 있다. 예를 들어 1.10에서 1.13으로 바로 올라갈 수 없고, 1.10 -&amp;gt; 1.11 -&amp;gt; 1.12 -&amp;gt; 1.13 으로 순차적으로 업데이트해 주어야 한다.&lt;/p&gt;
&lt;h1&gt;업데이트하기&lt;/h1&gt;
&lt;p&gt;GCP의 GKE같은 Managed Kubernetes를 사용하고 있으면 딸깍 한번으로 알아서 해주겠지만, 쿠버를 직접 디플로이했다면?&lt;/p&gt;
&lt;p&gt;Kubeadm으로 구성한 쿠버 클러스터를 업데이트하는 경우를 살펴보자.&lt;/p&gt;
&lt;h3&gt;마스터 노드 업데이트&lt;/h3&gt;
&lt;p&gt;마스터 노드에서는 기본적으로 (관리용을 제외한) Pod들이 구동되지 않으며, 마스터 노드가 내려가더라도 worker node에서 돌아가던 Pod들은 계속 일을 한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;물론 Kubectl과 쿠버 API는 먹통이 될 것이고 관리기능은 멈추겠지만, 아무튼 지금 돌아가고 있는 Pod 자체는 마스터노드가 내려가더라도 계속 돌아갈 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;아무튼 마스터 노드를 내리고 쿠버를 업데이트한다.&lt;br&gt;&lt;code&gt;kubeadm upgrade plan&lt;/code&gt; 명령어로 유용한 정보들을 볼 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;주의사항: kubeadm은 kubelet를 설치하지도 업데이트해주지도 않는다&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;apt-get upgrade kubeadm=1.12.0-00&lt;/code&gt; 으로 kubeadm을 업데이트한다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kubeadm upgrade apply v1.12.0&lt;/code&gt;으로 kubeadm 업그레이드를 적용한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;이러면 kube-apiserver, controller-manager, kube-scheduler, kubelet, kube-proxy가 몽땅 업데이트된다.&lt;/p&gt;
&lt;p&gt;하지만 kubelet은 업데이트되지 않았다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;kubeadm 구성에서는 컨트롤 플레인 컴포넌트들을 Pod 형태로 구동시키기 위해, 마스터 노드에 kubelet을 설치하도록 되어 있다.&lt;ul&gt;
&lt;li&gt;쿠버를 수동 구성하는 경우 마스터 노드에는 kubelet이 없을 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이제 kubelet을 업데이트한다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;apt-get upgrade kubelet=1.12.0-00&lt;/code&gt;으로 kubelet을 업데이트한다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;systemctl restart kubelet&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kubectl get nodes&lt;/code&gt; 의 결과, VERSION이 업데이트되어 보일 것이다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;워커 노드 업데이트&lt;/h3&gt;
&lt;p&gt;위에서도 언급되었듯이, 먼저 하나씩 노드를 Drain해서 그 노드에 있던 Pod들을 다른 노드로 배치한다. &lt;/p&gt;
&lt;p&gt;그 다음 노드를 업데이트한다. &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;클라우드 등의 가상화 환경인 경우, 신버전의 쿠버 노드 인스턴스를 생성하여 클러스터에 물린 뒤, 기존 인스턴스는 terminate할 수도 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;kubectl drain node-1&lt;/code&gt;&lt;br&gt;&lt;code&gt;apt-get upgrade -y kubeadm=1.12.0-00&lt;/code&gt;&lt;br&gt;&lt;code&gt;apt-get upgrade -y kubelet=1.12.0-00&lt;/code&gt;&lt;br&gt;&lt;code&gt;kubeadm upgrade node config --kubelet-version v1.12.0&lt;/code&gt;&lt;br&gt;&lt;code&gt;systemctl restart kubelet&lt;/code&gt;&lt;br&gt;&lt;code&gt;kubelet uncordon node-1&lt;/code&gt;&lt;/p&gt;</description>
      <category>콤퓨우터/필기: KodeKloud CKA 강의</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/88</guid>
      <comments>https://pscr.tistory.com/88#entry88comment</comments>
      <pubDate>Fri, 17 May 2024 00:28:17 +0900</pubDate>
    </item>
    <item>
      <title>100-104. Environment Variables and Configure Secrets in Application</title>
      <link>https://pscr.tistory.com/87</link>
      <description>&lt;p&gt;환경변수를 줄 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;spec:
  containers:
  - name: simple-webapp
    image: simple-webapp
  env:
  - name: APP_COLOR
    value: pink
  - name: JAVA_HOME
    value: /usr/&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;ConfigMaps&lt;/h1&gt;
&lt;p&gt;하지만 Pod 설정파일에 모든 환경변수를 때려박는다는것은 별로 가독성에 좋지 않을 수 있다.&lt;/p&gt;
&lt;p&gt;ConfigMaps는 쿠버에서 K-V 페어의 설정데이터를 저장하는 오브젝트이다(아마).&lt;/p&gt;
&lt;h2&gt;Imperative 방식 생성&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;kubectl create configmap conf-map-name --from-literal=APP_COLOR=pink --from-literal=JAVA_HOME=/usr/&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;혹은 그냥 다음과 같은 파일을 만들고, &lt;code&gt;kubectl create configmap conf-map-name --from-file=config-file-name.properties&lt;/code&gt; 해주는 편이 빠를 수도 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;APP_COLOR: pink
JAVA_HOME: /usr/&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Declarative 방식 생성&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;apiVersion: v1
kind: ConfigMap
metadata:
  name: conf-map-name
data:
  APP_COLOR: pink
  JAVA_HOME: /usr/&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;한 뒤에 &lt;code&gt;kubectl create -f&lt;/code&gt; 하면 된다.&lt;/p&gt;
&lt;h2&gt;Pod Definition에 ConfigMap으로 환경변수 주기&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;spec:
  containers:
  - name: simple-webapp
    image: simple-webapp
  envFrom:
  - configMapRef:
    name: conf-map-name&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Secret&lt;/h1&gt;
&lt;p&gt;기본값으로는 그냥 Base64된 텍스트를 저장하는 것이기 때문에, 이름과는 달리 사실 별로 Secret하지는 않다.&lt;/p&gt;
&lt;p&gt;Etcd에도 그냥 Base64된 텍스트 형태로 그대로 저장되고, 암호화가 안 된다! encryption at rest configuration을 따로 해 줘야 암호화가 된다.&lt;/p&gt;
&lt;p&gt;생성하는 방법은 ConfigMap과 매우 비슷하다. 다만 실제로 사용할 때에는, SCM(Git) 등에 Secret 설정 파일을 올리지 않도록 주의하여야 한다.&lt;/p&gt;
&lt;h2&gt;Imperative 방식 생성&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;kubectl create secret secret-name --from-literal=DB_Host=localhost --from-literal=DB_Password=1q2w3e4r!&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;혹은 그냥 다음과 같은 파일을 만들고, &lt;code&gt;kubectl create secret secret-name --from-file=config-file-name.properties&lt;/code&gt; 해주는 편이 빠를 수도 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DB_Host: localhost
DB_Password: 1q2w3e4r!&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Declarative 방식 생성&lt;/h2&gt;
&lt;p&gt;우선 텍스트를 &lt;code&gt;echo -n &amp;#39;text&amp;#39; | base64&lt;/code&gt; 로 base64 인코딩한다.&lt;br&gt;그 다음&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;apiVersion: v1
kind: Secret
metadata:
  name: secret-name
data:
  DB_Host: bG9jYWxob3N0
  DB_Password: MXEydzNlNHIh&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;한 뒤에 &lt;code&gt;kubectl create -f&lt;/code&gt; 하면 된다.&lt;/p&gt;
&lt;h2&gt;Secret의 사용&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;kubectl get secrets&lt;/code&gt;&lt;br&gt;&lt;code&gt;kubectl describe secrets&lt;/code&gt;&lt;br&gt;&lt;code&gt;kubectl get secret secret-name -o yaml&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;Pod Definition에서 Secret 사용하기&lt;/h3&gt;
&lt;h4&gt;방법 1] Secret 전체를 Import&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;spec:
  containers:
  - name: simple-webapp
    image: simple-webapp
  envFrom:
  - secretRef:
    name: secret-name&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;방법 2] 특정 Secret variable만 가져오는 경우&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;spec:
  containers:
  - name: simple-webapp
    image: simple-webapp
  envFrom:
  - secretRef:
    name: secret-name
    key: DB_Password&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;방법 3] Volume Mount&lt;/h4&gt;
&lt;p&gt;각각의 Secret 키를 파일명으로 해서, Value를 내용으로 가진 가상의 텍스트 파일이 들어 있는 디렉토리를 마운트한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;spec:
  containers:
  - name: simple-webapp
    image: simple-webapp
volumes:
- name: app-secret-volume
  secret:
     secretName: secret-name&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;apiVersion: v1
kind: Pod
metadata:
  name: app
  namespace: elastic-stack
spec:
  volumes:
  - name: log-volume
    hostPath:
      path: /var/log/webapp
  containers:
  - name: sidecar
    image: kodekloud/filebeat-configured
    volumeMounts:
    - name: log-volume
      mountPath: /var/log/event-simulator/
  - name: app
    image: kodekloud/event-simulator
    volumeMounts:
    - name: log-volume
      mountPath: /log&lt;/code&gt;&lt;/pre&gt;</description>
      <category>콤퓨우터/필기: KodeKloud CKA 강의</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/87</guid>
      <comments>https://pscr.tistory.com/87#entry87comment</comments>
      <pubDate>Fri, 17 May 2024 00:27:13 +0900</pubDate>
    </item>
    <item>
      <title>96-97. Commands on Docker and Kubernetes</title>
      <link>https://pscr.tistory.com/86</link>
      <description>&lt;h1&gt;Docker에서 명령어&lt;/h1&gt;
&lt;p&gt;예를 들어, 도커에서 &lt;code&gt;docker run ubuntu&lt;/code&gt;로 우분투 이미지를 돌리면, 실행 즉시 종료되어 버린다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;docker ps&lt;/code&gt;에는 아무것도 보이지 않고, &lt;code&gt;docker ps -a&lt;/code&gt;를 해야 그나마 종료되었다는 사실만을 알 수 있을것이다.&lt;/li&gt;
&lt;li&gt;왜째서인가?&lt;ul&gt;
&lt;li&gt;Ubuntu의 Dockerfile을 보면, &lt;code&gt;CMD [&amp;quot;bash&amp;quot;]&lt;/code&gt;라고 되어 있다.&lt;/li&gt;
&lt;li&gt;bash는 터미널을 찾을 수 없으면 exit한다.&lt;/li&gt;
&lt;li&gt;CMD가 끝났기 때문에, 컨테이너도 끝난다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;docker run ubuntu 우분투에서-실행할-명령어&lt;/code&gt;를 하면, Dockerfile의 &lt;code&gt;CMD [&amp;quot;bash&amp;quot;]&lt;/code&gt;가 &lt;strong&gt;오버라이드(대체)&lt;/strong&gt; 된다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;혹은, 다음처럼 새로운 Dockerfile을 만들 수도 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;FROM ubuntu
CMD sleep 5&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;CMD는 다음과 같은 형식을 할 수 있다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;CMD command param1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CMD [&amp;quot;command&amp;quot;, &amp;quot;param1&amp;quot;]&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;주의:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;CMD [&amp;quot;command param1&amp;quot;]&lt;/code&gt;은 불가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Entrypoint&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;CMD&lt;/code&gt;가 아니라 &lt;code&gt;ENTRYPOINT&lt;/code&gt;를 사용하면-&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;FROM ubuntu
ENTRYPOINT [&amp;quot;sleep&amp;quot;]&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;docker run ubuntu-sleeper 10&lt;/code&gt;을 했을 때, &lt;code&gt;sleep 10&lt;/code&gt;이 실행되게 된다. (파라미터가 오버라이드되지 않고 append됨)&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ENTRYPOINT&lt;/code&gt;와 &lt;code&gt;CMD&lt;/code&gt;를 동시에 사용하면, CMD에 기본값을 넣는 식으로 응용할 수가 있다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;위의 예제는 별도 파라미터 없이 &lt;code&gt;docker run ubuntu-sleeper&lt;/code&gt;를 했을 때, 그냥 &lt;code&gt;sleep&lt;/code&gt;이 파라미터 없이 실행돼서 &lt;code&gt;sleep: missing operand&lt;/code&gt; 같은 오류를 뿜을 것이다.&lt;/li&gt;
&lt;li&gt;하지만, &lt;code&gt;ENTRYPOINT [&amp;quot;sleep&amp;quot;]&lt;/code&gt;로 하고, &lt;code&gt;CMD [&amp;quot;5&amp;quot;]&lt;/code&gt;로 지정한다면?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;엔트리포인트도 override가 가능하긴 하다 - &lt;code&gt;--entrypoint&lt;/code&gt; 옵션을 주면 된다&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;권장되는 것은 아님&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;쿠버에서 명령어&lt;/h1&gt;
&lt;p&gt;Docker 명령행에서 &lt;code&gt;docker run --name 컨테이너명 이미지명 파라미터&lt;/code&gt; 같은 식으로 들어갔는데, Pod에서는 이 파라미터를 어떻게 줄 수 있는가?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;spec.containers.args&lt;/code&gt;에 주면 된다.&lt;ul&gt;
&lt;li&gt;&lt;code&gt;args&lt;/code&gt;은, Dockerfile의 &lt;code&gt;CMD&lt;/code&gt;를 오버라이드한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;spec:
  containers:
  - name: ubuntu-sleeper
    image: ubuntu-sleeper
    args: [&amp;quot;10&amp;quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;만약 Entrypoint를 오버라이드하고 싶으면?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;spec.containers.command&lt;/code&gt;를 넣으면 된다.&lt;ul&gt;
&lt;li&gt;역시 권장되는 사항은 아니다.&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;spec:
containers:
- name: ubuntu-sleeper
image: ubuntu-sleeper
command: [&amp;quot;sleep2.0&amp;quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;쿠버의 command 와 Dockerfile의 CMD가 서로 덮어씌우는 관계에 있지 않다는 것에 유의!&lt;/p&gt;</description>
      <category>콤퓨우터/필기: KodeKloud CKA 강의</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/86</guid>
      <comments>https://pscr.tistory.com/86#entry86comment</comments>
      <pubDate>Fri, 17 May 2024 00:25:50 +0900</pubDate>
    </item>
    <item>
      <title>92. Rolling Updates and Rollbacks</title>
      <link>https://pscr.tistory.com/85</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Pasted image 20240429062025.png&quot; data-origin-width=&quot;1972&quot; data-origin-height=&quot;342&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6tKHu/btsHq5svHu6/3QHhrH2UHrm5CYjfnlRfIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6tKHu/btsHq5svHu6/3QHhrH2UHrm5CYjfnlRfIk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6tKHu/btsHq5svHu6/3QHhrH2UHrm5CYjfnlRfIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6tKHu%2FbtsHq5svHu6%2F3QHhrH2UHrm5CYjfnlRfIk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1972&quot; height=&quot;342&quot; data-filename=&quot;Pasted image 20240429062025.png&quot; data-origin-width=&quot;1972&quot; data-origin-height=&quot;342&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Deployment를 처음 생성하면 Rollout이 트리거된다&lt;br /&gt;새로운 롤아웃은 새로운 Deployment Revision을 만든다 - 예를 들어 Revision 1&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;나중에, 앱이 업그레이드되면 (즉, 컨테이너의 버전이 새로운 버전으로 올라가면)&lt;/li&gt;
&lt;li&gt;새로운 롤아웃이 트리거되고,&lt;/li&gt;
&lt;li&gt;새로운 디플로이먼트 리비전이 생성된다 - 예를 들어 Revision 2&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Rollout 상태 보기: &lt;code&gt;kubectl rollout status deployment/myapp-development&lt;/code&gt;&lt;br /&gt;Rollout 히스토리 보기: &lt;code&gt;kubectl rollout history deployment/myapp-development&lt;/code&gt;&lt;/p&gt;
&lt;h1&gt;Deployment Strategy&lt;/h1&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;있는 인스턴스를 다 날리고 새 인스턴스를 만든다 (&quot;Recreate&quot;)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;당연히 downtime이 발생함&lt;/li&gt;
&lt;li&gt;당연히 쿠버의 기본값은 아님 (쓸 수는 있음)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;인스턴스를 하나하나씩 업데이트함 (&quot;Rolling Update&quot;)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;downtime이 발생하지 않음&lt;/li&gt;
&lt;li&gt;기본값임&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Deployment를 어떻게 업데이트할것인가&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;업데이트의 종류가 무엇인가?&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컨테이너 이미지의 버전을 올리는 걸 말하는건가?&lt;/li&gt;
&lt;li&gt;label을 변경하는 걸 말하는건가?&lt;/li&gt;
&lt;li&gt;아니면 Replica의 수를 변경하는 걸 말하는건가?&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무튼 이미 Deployment definition file이 있으니까, 이러한 업데이트가 뭐든 간에 파일을 수정하고 나서 &lt;code&gt;kubectl apply&lt;/code&gt; 를 돌리면 되는것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 컨테이너 이미지의 버전을 올리려면 yaml 파일을 열어서&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;   spec:
     containers:
     - name: asdf
       image: nginx:1.7.1 =&amp;gt; nginx:latest&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 식으로 변경 후 저장한 뒤에, &lt;code&gt;kubectl apply -f deploy.yaml&lt;/code&gt;을 넣는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 자동으로 새로운 Rollout과 Deployment의 새 리비전이 생성된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(&lt;code&gt;kubectl set image deployment/deployment-name asdf=nginx:latest&lt;/code&gt;같이 Imperative하게 수정하는 것은 가능하지만, 앞에서 다뤘듯이 이러면 YAML 파일은 원본 상태 그대로 남아서 나중에 귀찮아질 수 있다)&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Recreate v. RollingUpdate&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;kubectl describe&lt;/code&gt;로 디플로이먼트의 상태를 보면,&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Recreate에서는 Replica Set의 수를 0으로 만들어버린 뒤에 다시 원본 숫자로 돌리는 데 반해,&lt;/li&gt;
&lt;li&gt;RollingUpdate에서는 기존 Replica Set의 수를 하나씩 줄이면서, 새로운 Replica Set의 수를 하나씩 올리는 식으로 대응하고 있음을 볼 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Pasted image 20240429063212.png&quot; data-origin-width=&quot;1992&quot; data-origin-height=&quot;804&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lsZ8A/btsHsKtJFsQ/UpksiKwR6jiJW3zoTEdWak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lsZ8A/btsHsKtJFsQ/UpksiKwR6jiJW3zoTEdWak/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lsZ8A/btsHsKtJFsQ/UpksiKwR6jiJW3zoTEdWak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlsZ8A%2FbtsHsKtJFsQ%2FUpksiKwR6jiJW3zoTEdWak%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1992&quot; height=&quot;804&quot; data-filename=&quot;Pasted image 20240429063212.png&quot; data-origin-width=&quot;1992&quot; data-origin-height=&quot;804&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h1&gt;Rollback&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;kubectl rollout undo deployment/dep-name&lt;/code&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;롤백을 하면 RollingUpdate의 역순으로, 그러니까 새로운 ReplicaSet의 레플리카 수를 하나씩 줄이면서 옛날 ReplicaSet을 하나씩 늘리는 방식으로 진행한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Pasted image 20240429063358.png&quot; data-origin-width=&quot;2052&quot; data-origin-height=&quot;190&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHvS83/btsHqLA51XU/oZKfMvYdwbsgVhld64MwkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHvS83/btsHqLA51XU/oZKfMvYdwbsgVhld64MwkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHvS83/btsHqLA51XU/oZKfMvYdwbsgVhld64MwkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHvS83%2FbtsHqLA51XU%2FoZKfMvYdwbsgVhld64MwkK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2052&quot; height=&quot;190&quot; data-filename=&quot;Pasted image 20240429063358.png&quot; data-origin-width=&quot;2052&quot; data-origin-height=&quot;190&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>콤퓨우터/필기: KodeKloud CKA 강의</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/85</guid>
      <comments>https://pscr.tistory.com/85#entry85comment</comments>
      <pubDate>Fri, 17 May 2024 00:22:43 +0900</pubDate>
    </item>
    <item>
      <title>84-87. Monitor Cluster Components, Managing Application Logs</title>
      <link>https://pscr.tistory.com/84</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;#&amp;nbsp;Monitor&amp;nbsp;Clutser&amp;nbsp;Components&lt;br /&gt;-&amp;nbsp;Heapster&amp;nbsp;(Deprecated)&lt;br /&gt;-&amp;nbsp;Metrics&amp;nbsp;Server&lt;br /&gt;-&amp;nbsp;쿠버&amp;nbsp;클러당&amp;nbsp;1개&lt;br /&gt;-&amp;nbsp;In-Memory&amp;nbsp;monitoring&amp;nbsp;solution&lt;br /&gt;-&amp;nbsp;Kubelet의&amp;nbsp;하위컴포넌트인&amp;nbsp;cAdvisor(Container&amp;nbsp;Advisor)가&amp;nbsp;Pod에서의&amp;nbsp;퍼포먼스&amp;nbsp;메트릭을&amp;nbsp;받아다&amp;nbsp;Kubelet&amp;nbsp;API에&amp;nbsp;노출함&lt;br /&gt;-&amp;nbsp;설치&amp;nbsp;방법:&lt;br /&gt;-&amp;nbsp;Minikube의&amp;nbsp;경우,&amp;nbsp;`minikube&amp;nbsp;addons&amp;nbsp;enable&amp;nbsp;metrics-server`&lt;br /&gt;-&amp;nbsp;기타&amp;nbsp;배포판의&amp;nbsp;경우,&amp;nbsp;Github&amp;nbsp;Repo를&amp;nbsp;클론한&amp;nbsp;뒤에&amp;nbsp;`kubectl&amp;nbsp;create&amp;nbsp;-f&amp;nbsp;deploy/1.8+/`&lt;br /&gt;-&amp;nbsp;설치가&amp;nbsp;완료되었으면&amp;nbsp;`kubectl&amp;nbsp;top&amp;nbsp;node`,&amp;nbsp;`kubectl&amp;nbsp;top&amp;nbsp;pod`&lt;br /&gt;&lt;br /&gt;In-memory&amp;nbsp;모니터링&amp;nbsp;솔루션이&amp;nbsp;아니라,&amp;nbsp;영구히&amp;nbsp;저장되는&amp;nbsp;시스템이&amp;nbsp;필요한&amp;nbsp;경우&amp;nbsp;Prometheus,&amp;nbsp;Elastic&amp;nbsp;Stack,&amp;nbsp;Datadog,&amp;nbsp;Dynatrace와&amp;nbsp;같은&amp;nbsp;서드파티&amp;nbsp;솔루션을&amp;nbsp;이용할&amp;nbsp;것&lt;br /&gt;&lt;br /&gt;#&amp;nbsp;Application&amp;nbsp;로그&amp;nbsp;보기&lt;br /&gt;`kubectl&amp;nbsp;logs&amp;nbsp;포드-이름&amp;nbsp;-f`을&amp;nbsp;하면,&amp;nbsp;`docker&amp;nbsp;logs&amp;nbsp;컨테이너아이디&amp;nbsp;-f`를&amp;nbsp;한&amp;nbsp;것처럼,&amp;nbsp;로그를&amp;nbsp;볼&amp;nbsp;수&amp;nbsp;있다&lt;br /&gt;-&amp;nbsp;`-f`:&amp;nbsp;로그를&amp;nbsp;stream&amp;nbsp;형태로&amp;nbsp;볼&amp;nbsp;수&amp;nbsp;있다&lt;br /&gt;&lt;br /&gt;만약&amp;nbsp;Pod이&amp;nbsp;여러&amp;nbsp;컨테이너로&amp;nbsp;구성되어있는&amp;nbsp;경우,&amp;nbsp;해당&amp;nbsp;컨테이너의&amp;nbsp;이름까지&amp;nbsp;넣어줘야&amp;nbsp;한다&lt;br /&gt;`kubectl&amp;nbsp;logs&amp;nbsp;포드-이름&amp;nbsp;컨테이너-이름&amp;nbsp;-f`&lt;/p&gt;</description>
      <category>콤퓨우터/필기: KodeKloud CKA 강의</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/84</guid>
      <comments>https://pscr.tistory.com/84#entry84comment</comments>
      <pubDate>Fri, 17 May 2024 00:22:17 +0900</pubDate>
    </item>
    <item>
      <title>80. Configuring Scheduler Profiles</title>
      <link>https://pscr.tistory.com/83</link>
      <description>&lt;p&gt;일단 Pod이 생성되면 Scheduling Queue에 들어가게 된다&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;그 다음 Pod에 선언된 &lt;code&gt;spec.priorityClassName&lt;/code&gt;에 의해 정렬된다.&lt;ul&gt;
&lt;li&gt;PrioritySort 플러그인에 의해 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;그 다음엔 필터링 단계에 들어가게 된다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pod을 구동할 수 없는 노드(Affinity, Tint, Resource 등의 제한)들은 튕겨나간다.&lt;ul&gt;
&lt;li&gt;NodeResourceFit, NodeName, NodeUnschedulable 플러그인 등에 의해 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;그 다음엔 스코어링 단계이다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;해당 Pod가 차지하는 공간을 제외하고 남는 free space의 크기에 따라 점수 부여&lt;ul&gt;
&lt;li&gt;남는 free space가 클수록 높은 점수가 나온다&lt;/li&gt;
&lt;li&gt;NodeResourcesFit, ImageLocality 플러그인에 의해 처리&lt;ul&gt;
&lt;li&gt;ImageLocality: 컨테이너이미지를 이미 갖고 있는 노드에 가점 부여&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;지금은 필터링이 끝난 단계이므로, 노드들의 점수가 형편없더라도 아무튼 배치는 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;그런 뒤 가장 높은 점수를 가진 노드에 Binding되게 된다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;DefaultBinder 플러그인에 의해 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Scheduling Extension의 사용자화&lt;/h1&gt;
&lt;p&gt;Extension Point라는 것이 있다&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;queueSort, preFilter, filter, postFilter, preScore, score, reserve, permit, preBind, bind, postBind... &lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Scheduler Profile&lt;/h1&gt;
&lt;p&gt;쿠버 1.18에서 추가된 기능&lt;br&gt;기존에는, 여러 스케줄러가 동시에 Pod를 배치하려다가 Race Condition에 걸린다든가 하는 문제가 있었다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;이에, 하나의 스케줄러에서 여러 가지의 &amp;quot;프로파일&amp;quot;을 가지도록 한 것&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeschedulerConfiguration
profiles:
- schedulerName: my-scheduler-2
  plugins:
    score:
    disabled:
    - name: TaintToleration
    enabled:
    - name: MyCustomPluginA
    - name: MyCustomPluginB

- schedulerName: my-scheduler-3
  plugins:
    preScore:
    disabled:
    - name: &amp;#39;*&amp;#39;
&lt;/code&gt;&lt;/pre&gt;</description>
      <category>콤퓨우터/필기: KodeKloud CKA 강의</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/83</guid>
      <comments>https://pscr.tistory.com/83#entry83comment</comments>
      <pubDate>Fri, 17 May 2024 00:21:43 +0900</pubDate>
    </item>
    <item>
      <title>74. Static Pods</title>
      <link>https://pscr.tistory.com/82</link>
      <description>&lt;h1&gt;쿠버의 아키텍처 돌아보기&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;마스터 노드&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;kube-apiserver&lt;/li&gt;
&lt;li&gt;etcd cluster&lt;/li&gt;
&lt;li&gt;Controller Manager&lt;/li&gt;
&lt;li&gt;kube-scheduler&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;워커 노드&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Kubelet&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;워커노드의 Kublet은 Pod을 어떻게 배치할지에 대해 마스터노드의 Kube-apiserver에 의존&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;이 결정은 Kube-scheduler에서 내림&lt;ul&gt;
&lt;li&gt;이것은 etcd에 저장됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;만약 마스터노드가 없다면?&lt;/h1&gt;
&lt;p&gt;워커노드 혼자서 떠있다면?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Kubelet 혼자서 노드를 독립적으로 관리하는 것은 가능하다!&lt;/p&gt;
&lt;p&gt;이런 상황에서 Pod을 만드려고 한다면, kube-apiserver 없이 kublet에 어떻게 Pod definition file을 넣을것인가?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;kubelet이 특정 디렉토리에서 설정파일을 읽도록 설정할 수 있음&lt;ul&gt;
&lt;li&gt;이렇게 설정하면, Kubelet이 설정파일을 읽은 뒤에 Pod 스펙에 맞게 노드에 Pod을 생성하고, 유지한다&lt;/li&gt;
&lt;li&gt;이것을 Static Pod 이라고 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;근본적으로, Kubelet은 오직 Pod만 아는 친구이다&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;따라서 Static하게 ReplicaSet, Deployment, Service 등을 생성하는 것은 불가능 - 오직 Pod만 이 방식으로 생성할 수 있다&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;그 디렉토리는 어떻게 설정하는가?&lt;/h1&gt;
&lt;p&gt;Kubelet의 systemd 서비스에서,&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ExecStart=/usr/local/bin/kubelet \\
  ...
  --pod-manifest-path=/etc/Kubernetes/manifests
  또는
  --config=/path/to/config-file.yaml
  ...&lt;/code&gt;&lt;/pre&gt;&lt;ol&gt;
&lt;li&gt;&lt;code&gt;--pod-manifest-path&lt;/code&gt;을 바꿔주면 된다.&lt;/li&gt;
&lt;li&gt;또는, &lt;code&gt;--config=/path/to/config-file.yaml&lt;/code&gt; 같은 식으로 설정파일의 경로를 주고, 해당 설정파일에서 &lt;code&gt;staticPodPath: /path/to/definition-file/&lt;/code&gt; 같은 식으로 선언할 수도 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;kubeadmintool로 클러스터를 설정하는 경우 이 방식으로 설정됨&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;controlplane ~ ➜  ps -ef | grep kubelet
root        4312       1  0 20:00 ?        00:00:22 /usr/bin/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf --config=/var/lib/kubelet/config.yaml --container-runtime-endpoint=unix:///var/run/containerd/containerd.sock --pod-infra-container-image=registry.k8s.io/pause:3.9&lt;/code&gt;&lt;/pre&gt;&lt;h1&gt;이렇게 만들어진 Static Pod를 어떻게 확인하는가&lt;/h1&gt;
&lt;p&gt;당연히 지금은 kube-apiserver가 없기 때문에, &lt;code&gt;kubectl&lt;/code&gt;이 작동하지 않는다&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;쿠버가 사용하는 컨테이너 런타임 (CRI-O, Containerd, Docker)의 컨테이너 조회 명령어를 직접 입력하여 확인&lt;ul&gt;
&lt;li&gt;CRI-O: &lt;code&gt;crictl ps&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;ContainerD: &lt;code&gt;nerdctl ps&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Docker: &lt;code&gt;docker ps&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Static Pod와 Kube-Apiserver 관할의 Pod의 공존&lt;/h1&gt;
&lt;p&gt;Kubelet은 기본적으로&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;먼저 Static Pods 설정파일 폴더를 보고, 그 다음에&lt;/li&gt;
&lt;li&gt;HTTP API 엔드포인트를 통해 Pod 입력을 받는다.&lt;ul&gt;
&lt;li&gt;Kube-apiserver는 이 API를 통해 Pod을 생성한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;따라서 이 둘은 공존할 수 있다.&lt;/p&gt;
&lt;p&gt;그렇다면 Kube-apiserver는 Static Pod을 알고 있는가?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ㅇㅇ (Worker가 Master에 연결된 경우)&lt;/li&gt;
&lt;li&gt;어떻게?&lt;ul&gt;
&lt;li&gt;Worker가 Cluster의 일원일 경우 Kublet은 kube-apiserver에 Static Pod의 mirror object를 생성하기 때문이다&lt;ul&gt;
&lt;li&gt;Read-only mirror or pod&lt;/li&gt;
&lt;li&gt;kube-apiserver에서는 상태만 볼 수 있고, 편집 또는 삭제는 불가&lt;ul&gt;
&lt;li&gt;삭제하려면 직접 Worker 노드의 설정파일을 날려야함&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;pre&gt;&lt;code&gt;# kubectl get pods -A -o wide
NAMESPACE      NAME                                   READY   STATUS    RESTARTS   AGE   IP             NODE           NOMINATED NODE   READINESS GATES
kube-flannel   kube-flannel-ds-868vm                  1/1     Running   0          18m   192.30.156.6   node01         &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
kube-flannel   kube-flannel-ds-rzqmb                  1/1     Running   0          18m   192.30.156.3   controlplane   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
kube-system    coredns-69f9c977-44dph                 1/1     Running   0          18m   10.244.0.2     controlplane   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
kube-system    coredns-69f9c977-9csqs                 1/1     Running   0          18m   10.244.0.3     controlplane   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
kube-system    etcd-controlplane                      1/1     Running   0          18m   192.30.156.3   controlplane   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
kube-system    kube-apiserver-controlplane            1/1     Running   0          18m   192.30.156.3   controlplane   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
kube-system    kube-controller-manager-controlplane   1/1     Running   0          18m   192.30.156.3   controlplane   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
kube-system    kube-proxy-gj98n                       1/1     Running   0          18m   192.30.156.3   controlplane   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
kube-system    kube-proxy-tcpd4                       1/1     Running   0          18m   192.30.156.6   node01         &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
kube-system    kube-scheduler-controlplane            1/1     Running   0          18m   192.30.156.3   controlplane   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h1&gt;그래서 이걸 엊다 쓰는가&lt;/h1&gt;
&lt;p&gt;Control Plane 컴포넌트를 노드에 Pod 형태로 디플로이하기 위해 Static Pod를 사용할 수 있다&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;우선 마스터 노드에 Kubelet을 깐다&lt;/li&gt;
&lt;li&gt;매니페스트 디렉토리에 쿠버 마스터노드의 각 구성요소 - kube-apiserver, controller-manager, etcd 를 Pod화한 yaml파일을 넣는다&lt;/li&gt;
&lt;li&gt;???&lt;/li&gt;
&lt;li&gt;PROFIT!!!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;kubeadm은 바로 이 방식을 통해 쿠버네티스 클러스터를 구성한다&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;kubectl get pods -n kube-system&lt;/code&gt; 해보면 알 수 있다&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>콤퓨우터/필기: KodeKloud CKA 강의</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/82</guid>
      <comments>https://pscr.tistory.com/82#entry82comment</comments>
      <pubDate>Fri, 17 May 2024 00:20:09 +0900</pubDate>
    </item>
    <item>
      <title>71. DaemonSet</title>
      <link>https://pscr.tistory.com/81</link>
      <description>&lt;p&gt;하나의 Pod가 모든 노드에서 하나씩 Replicate되도록 해 줌&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;새 Node가 추가되면 자동으로 Pod의 Replica가 해당 노드에 추가됨&lt;/li&gt;
&lt;li&gt;새 노드가 삭제되면 자동으로 Pod도 삭제됨&lt;/li&gt;
&lt;li&gt;로그 뷰어라든지, 모니터링 agent 같은 데에 쓰면 좋다&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;클러스터의 모든 Worker Node에는 Kube-Proxy가 존재&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;사실 이것도 DaemonSet로 Replicated된 거거든요&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;생성방법&lt;/h2&gt;
&lt;p&gt;생긴 것은 ReplicaSet과 비슷하다&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;apiVersion: apps/v1  // apps/v1임에 주의
kind: DaemonSet
metadata:
  name: monitoring-daemon
spec: 
  template:
    metadata:
      labels:
        app: monitoring-agent
    spec:
      containers:
        - name: monitoring-agent
          image: monitoring-agent
  selector:
    matchLabels:
      type: monitoring-agent&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;생성법 확인법 모두 일반적인 쿠버 오브젝트랑 똑같다&lt;br&gt;(&lt;code&gt;kubectl create -f asdf.yml&lt;/code&gt;, &lt;code&gt;kubectl get daemonset&lt;/code&gt;, ...)&lt;/p&gt;
&lt;h1&gt;이게 어떻게 구현되어 있는가&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;1.12버전 이전까지는, 그냥 nodeName이 없는 Pod형태로 만들어서 스케줄러의 작동을 회피하고, Pod을 수동으로 배치했다&lt;/li&gt;
&lt;li&gt;최신 버전에서는, Affinity Rule을 사용하여 구현하고 있다&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>콤퓨우터/필기: KodeKloud CKA 강의</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/81</guid>
      <comments>https://pscr.tistory.com/81#entry81comment</comments>
      <pubDate>Fri, 17 May 2024 00:19:19 +0900</pubDate>
    </item>
    <item>
      <title>67. Resource Requests and Limits</title>
      <link>https://pscr.tistory.com/80</link>
      <description>&lt;p&gt;&amp;quot;Resources&amp;quot; - CPU, Memory, ...&lt;br&gt;특징: 각 컨테이너에 대해 할당되는 값이다. 하나의 Pod에 여러 컨테이너가 있다면, 각각의 컨테이너는 다른 Resource Limit을 가진다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;spec:
    containers:
    - name: asdf
        resources:
            requests:
                memory: &amp;quot;4Gi&amp;quot;
                cpu: 2
            limits:
                memory: &amp;quot;8Gi&amp;quot;
                cpu: 4&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;메모리야 4GiB라고 하지만 이 CPU 숫자는 무엇인가?&lt;/p&gt;
&lt;h1&gt;CPU count&lt;/h1&gt;
&lt;p&gt;1 CPU = 1 vCPU Core를 가리킨다 (SMT 시스템의 경우 1 SMT 쓰레드)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;0.1 CPU = 100m (100 microseconds)&lt;/li&gt;
&lt;li&gt;최소 0.001 = 1m (1 microsecond) 까지 지정 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Memory Count&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;SI 표기법을 따른다&lt;/li&gt;
&lt;li&gt;1KiB = 1024 Bytes, 1KB = 1000 Bytes&lt;/li&gt;
&lt;li&gt;각각 1Ki, 1K로 나타낼수있다&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Requests와 Limits&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Requests: 리소스를 이만큼은 줘라&lt;/li&gt;
&lt;li&gt;Limits: 리소스를 이 이상은 주지마라&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Limit을 넘으면?&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;CPU의 경우, CPU 스케줄링을 통해 그 이상의 CPU자원을 못 쓰도록 막는다&lt;/li&gt;
&lt;li&gt;메모리는, 해당 메모리 사용량에 도달하면 OOM (Out-of-Memory)에러를 내면서 Pod이 죽는다&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;기본값과 이상적인 설정값&lt;/h1&gt;
&lt;p&gt;기본 상태에서는 각 Pod에 대해 어떤 requests도, limits도 걸려 있지 않다&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;CPU와 RAM을 꽉 찰때까지 무제한으로 쓸 수 있다&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CPU를 Limit할 필요는 별로 없다&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;어차피 CPU 리소스가 남아나고 있다면 안쓸 이유가 있나?&lt;/li&gt;
&lt;li&gt;최소를 Request만 걸고 Limit은 걸지말자&lt;ul&gt;
&lt;li&gt;다만 이렇게 하려면 모든 Pod이 최소 Request 설정값을 갖고 있어야, 다른 Pod이 모든 리소스를 다써버리는 일을 막을 수 있다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;LimitRange&lt;/h1&gt;
&lt;p&gt;그럼 모든 Pod이 최소 Request 설정값을 갖고 있다는 보장을 어떻게 할 수 있는가?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;LimitRange (type: Object)&lt;/li&gt;
&lt;li&gt;Pod(안에 있는 Container)에 설정될 리소스 설정값의 기본값을 정함&lt;ul&gt;
&lt;li&gt;namespace level&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;apiVersion: v1
kind: LimitRange
metadata:
    name: cpu-resource-constraint
spec:
    limits:
    - default:
        cpu: 500m  // Limit
      defaultRequest:
        cpu: 500m  // Request
    max:
        cpu: &amp;quot;1&amp;quot;   // Maximum Limit
    min:
        cpu: 100m  // Minimum Request
    type: Container&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;LimitRange를 생성하더라도, 기존에 만들어진 Pod에는 적용되지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;ResourceQuota&lt;/h1&gt;
&lt;p&gt;ResourceQuota를 이용하여 &lt;strong&gt;모든 Pod를 다 합쳤을 때&lt;/strong&gt;의 리소스 수준 제한을 걸 수 있다&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;apiVersion: v1
kind: ResourceQuota
metadata:
    name: my-resource-quota
spec:
    hard:
        requests.cpu: 4
        requests.memory: 4Gi
        limits.cpu: 10
        limits.memory: 10Gi&lt;/code&gt;&lt;/pre&gt;</description>
      <category>콤퓨우터/필기: KodeKloud CKA 강의</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/80</guid>
      <comments>https://pscr.tistory.com/80#entry80comment</comments>
      <pubDate>Tue, 14 May 2024 22:31:46 +0900</pubDate>
    </item>
    <item>
      <title>59-63. Taints, Tolerations, Node Selectors, Affinity</title>
      <link>https://pscr.tistory.com/79</link>
      <description>&lt;h1&gt;Taints, Tolerations&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;특정 &amp;quot;Taint&amp;quot;가 씌워진 노드에는 Toleration이 없는 Pod가 배치될 수 없다&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;강의에서는 &amp;quot;모기기피제를 뿌린 사람과 내성 없는 벌레&amp;quot;라는 비유를 쓴&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;하지만, 만약 특정 Taint에 대한 Toleration이 있는 Pod라면 해당 Taint가 씌워진 노드에 배치될 수 있다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;다만, 어떤 Pod이 특정 Taint에 대한 Toleration을 가지고 있다고 해서, Taint가 일치하는 노드에만 배치된다는 것은 아님&lt;ul&gt;
&lt;li&gt;스케줄러의 마음에 따라서는, 그냥 Taint 없는 다른 노드에 갈 수도 있음&lt;ul&gt;
&lt;li&gt;이것은 &amp;quot;특정 노드가 어떤 Pod을 받아들일것인가&amp;quot;에 대한 문제이기 때문에, &amp;quot;특정 Pod을 어떤 노드에 지정하고 싶다&amp;quot;라는 경우 Node Selector를 이용하여야 함&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;p&gt;즉 Taint는 노드에, Toleration은 Pod에 부여되는 것&lt;/p&gt;
&lt;h2&gt;실제&lt;/h2&gt;
&lt;h3&gt;Taint&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;kubectl taint nodes 노드명 key=value:taint-effect&lt;/code&gt; 형태&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;key=value 쌍이라는 Taint를 노드에 부여&lt;/li&gt;
&lt;li&gt;&lt;code&gt;taint-effect&lt;/code&gt;: 적절한 Toleration이 없는 Pod에게 무엇을 할 것인가?&lt;ul&gt;
&lt;li&gt;NoSchedule: Toleartion 없는 Pod를 배치하지 않음&lt;/li&gt;
&lt;li&gt;PreferNoSchedule: 되도록 배치하지 않음&lt;/li&gt;
&lt;li&gt;NoExecute: Toleartion 없는 Pod을 배치하지 않고, 이미 들어가 있는 Pod도 쫓아냄&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;예를 들어, &lt;code&gt;kubectl taint nodes node01 app=blue:NoSchedule&lt;/code&gt; 같은 형식이 된다&lt;/p&gt;
&lt;p&gt;fun fact) 컨트롤 노드에 사용자의 Pod이 배치되지 않는 이유는, 쿠버 설치 시에 기본값으로 Taint가 설정되기 때문이다.&lt;/p&gt;
&lt;h3&gt;삭제&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;kubectl taint nodes 노드명 key=value:taint-effect-&lt;/code&gt; (맨 뒤에 &lt;code&gt;-&lt;/code&gt;가 붙음) 으로 삭제 가능 &lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Events:
  Type     Reason            Age   From               Message
  ----     ------            ----  ----               -------
  Warning  FailedScheduling  15s   default-scheduler  0/2 nodes are available: 1 node(s) had untolerated taint {node-role.kubernetes.io/control-plane: }, 1 node(s) had untolerated taint {spray: mortein}. preemption: 0/2 nodes are available: 2 Preemption is not helpful for scheduling.&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Tolerations&lt;/h3&gt;
&lt;p&gt;Pod Definiton file에 설정 적용&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
spec:
  containers:
  - name: nginx-container  // -는 YAML에서 리스트의 첫 항목임을 가리킴
    image: nginx
  tolerations: //app=blue:NoSchedule이라면
  - key: &amp;quot;app&amp;quot;
    operator: &amp;quot;Equal&amp;quot;
    value: &amp;quot;blue&amp;quot;
    effect: &amp;quot;NoSchedule&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Node Selector&lt;/h1&gt;
&lt;p&gt;&amp;quot;특정 Pod을 어떤 노드에 지정하고 싶다&amp;quot;라는 경우 Node Selector를 이용하여야 함&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
spec:
  containers:
  - name: nginx-container
    image: nginx
  nodeSelector:
    size: Large // 선택할 노드의 label!&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;그럼 노드를 어떻게 라벨링하는가&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;kubectl label nodes 노드명 lavel-key=lavel-value&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;이 경우에는, &lt;code&gt;kubectl label nodes node-1 size=Large&lt;/code&gt; 같은 식이 될 것&lt;/p&gt;
&lt;h2&gt;Node Selector의 문제점&lt;/h2&gt;
&lt;p&gt;만약에 특정 Pod을 size=Large이거나 size=Medium인 노드에 배치하고 싶다면? (OR)&lt;br&gt;혹은, size=Large가 아닌 Pod에 배치하고 싶다면? (NOT)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Node Selector로는 달성 불가&lt;/li&gt;
&lt;li&gt;Node Affinity와 Anti-Affinity를 사용하여야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Node Affinity&lt;/h1&gt;
&lt;p&gt;&amp;quot;Great Power comes with Great Complexity&amp;quot;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: blue
  labels:
    name: blue
spec:
  selector:
    matchLabels:
      name: blue
  template:
    metadata:
      name: blue-pod
      labels:
        name: blue
    spec:
      containers:
      - name: blue-nginx
        image: nginx
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: color
                operator: In
                values:
                - blue
                - green
  replicas: 3&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;if (values.in(key)) 같은 느낌&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;operator 종류: In, NotIn, Exists, ...&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Affinity의 종류&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;requiredDuringSchedulingIgnoredDuringExecution&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;During Scheduling (Pod이 존재하지 않다가 처음 생성되는 때)&lt;ul&gt;
&lt;li&gt;만약 규칙에 match되는 노드가 없으면 그냥 그 Pod은 스케줄링이 안된다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;During Execution (Pod이 실행 중인 상태. Affinity 룰이 새롭게 들어갔을 경우, 노드의 label이 바뀌었을 경우 ...)&lt;ul&gt;
&lt;li&gt;Ignored (지금 실행중인 경우에는 Affinity가 무시됨)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;preferredDuringSchedulingIgonredDuringExecution&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;During Scheduling (Pod이 존재하지 않다가 처음 생성되는 때)&lt;ul&gt;
&lt;li&gt;만약 규칙에 match되는 노드가 없으면 대충 아무 노드에 넣는다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;정리&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Taint &amp;amp; Toleration은, &amp;quot;특정 노드&amp;quot;에 Toleration을 가진 Pod만 들어갈 수 있게 하는 역할을 한다&lt;/li&gt;
&lt;li&gt;Node Selector &amp;amp; Node Affinity는, &amp;quot;특정 Pod&amp;quot;이 어느 노드에 삽입될 수 있는지를 결정한다&lt;/li&gt;
&lt;li&gt;이 둘을 동시에 사용하면, 특정 노드에 특정 Pod만, 또 특정 Pod에 특정 노드만 들어가게 할 수가 있다&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>콤퓨우터/필기: KodeKloud CKA 강의</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/79</guid>
      <comments>https://pscr.tistory.com/79#entry79comment</comments>
      <pubDate>Tue, 14 May 2024 22:29:28 +0900</pubDate>
    </item>
    <item>
      <title>44. Imperative v. Declarative</title>
      <link>https://pscr.tistory.com/78</link>
      <description>&lt;h1&gt;Imperative&lt;/h1&gt;
&lt;p&gt;어떠한 목표를 달성하기 위한 자세한 instruction을 작성함&lt;br&gt;(중간에 절차가 멈추고 뻗는다든가 했을 때에 resume하기가 귀찮아진다)&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&amp;#39;web-server&amp;#39;라는 이름으로 VM 생성&lt;/li&gt;
&lt;li&gt;Nginx 설치&lt;/li&gt;
&lt;li&gt;Nginx 설정파일 변경: 포트 8080 사용&lt;/li&gt;
&lt;li&gt;Nginx 설정파일 변경: 웹 경로 /var/www/nginx 사용&lt;/li&gt;
&lt;li&gt;Git Repo X에서 /var/www/nginx 경로에 pull&lt;/li&gt;
&lt;li&gt;nginx 시작&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Kubernetes에서의 imperative way&lt;/h2&gt;
&lt;p&gt;장점:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;시험 볼 때같이 간단한 환경을 잠깐 쓸 때에는 좋음&lt;br&gt;단점: &lt;/li&gt;
&lt;li&gt;특정 Session에서 실행했을 때 해당 Session에서만 유효함.&lt;/li&gt;
&lt;li&gt;기능이 제약되어 있음 (multi-container pod deployment 등은 불가)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Imperative command 이용 (yaml 파일을 건드리지 않는다)&lt;/h3&gt;
&lt;h4&gt;Object 생성&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;kubectl run --image=nginx nginx&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kubectl create deployment --image=nginx nginx&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kubectl expose deployment nginx --port 80&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Object 수정&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;kubectl edit deployment nginx&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;이 명령어의 경우, Kubernetes 메모리상에 있는 Definition file을 연다.&lt;ul&gt;
&lt;li&gt;이것은 &lt;code&gt;kubectl create&lt;/code&gt;에 썼던 yaml 파일과 비슷하지만 다른 파일으로, 예를 들어 &lt;code&gt;status&lt;/code&gt; 필드같은 게 존재함을 볼 수 있다.&lt;/li&gt;
&lt;li&gt;이 파일에 수정하고 저장하면 살아있는 오브젝트에는 변경사항이 적용되지만, &lt;strong&gt;실제 local file로 저장되어있는 설정 파일에는 적용되지 않는다&lt;/strong&gt;.&lt;ul&gt;
&lt;li&gt;나중에 유지보수할 때 매우 골치가 아파질 수 있다!!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;따라서 &lt;code&gt;kubectl edit&lt;/code&gt;을 쓰는 것보다는, 그냥 로컬 yaml 파일을 수정한 뒤 &lt;code&gt;kubectl replace -f asdf.yaml&lt;/code&gt;를 사용하는 것이 권장된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;kubectl scale deployment nginx --replicas=5&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;kubectl set image deployment nginx nginx=nginx:1.18&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;kubectl create -f nginx.yaml&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kubectl replace -f nginx.yaml&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kubect delete -f nginx.yaml&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;하지만, 결국 이것들도 Imperative way인 것은 마찬가지이다 - 예를 들어 kubectl create로 Pod을 만들고자 하는 경우, 관리자는 그 Pod이 이미 존재하는지 등등을 미리 파악하고 있어야 한다.&lt;/p&gt;
&lt;h1&gt;Declarative&lt;/h1&gt;
&lt;p&gt;목표만 작성함, 실제 어떻게 수행할지는 시스템에 의해 결정됨 - Ansible, Puppet, Chef, Terraform 등&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;VM-name: web-server&lt;/li&gt;
&lt;li&gt;Package: nginx&lt;/li&gt;
&lt;li&gt;Port: 8080&lt;/li&gt;
&lt;li&gt;Path: /var/www/nginx&lt;/li&gt;
&lt;li&gt;Code: Git repo X&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Kubernentes에서의 Declarative way&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;kubectl apply -f nginx.yaml&lt;/code&gt;로 알아서 confinuration을 읽고, 모든 것을 적용&lt;ul&gt;
&lt;li&gt;예를 들어 Pod 설정파일일 경우, 해당 Pod이 이미 있으면 생성하지 않고 없으면 생성함&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-f 디렉토리&lt;/code&gt;로 경로를 주는 경우, 해당 디렉토리 아래의 모든 설정파일이 일괄 적용&lt;/li&gt;
&lt;li&gt;설정파일이 변경되었다고 해도, 같은 명령어로 update적용가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Kubectl Apply 명령어&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;쿠버는 내부적으로 live 상태의 객체에 대한 Live object configuration을 가지고 있다&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;관리자가 만든 YAML 파일 형태의 로컬 설정파일 (&lt;code&gt;-f 파일명&lt;/code&gt;을 해서 불러올)도 존재할것이다&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;하지만, 만약 kubectl apply를 하게 되면, &amp;quot;마지막으로 적용된 설정&amp;quot;이 하나 추가적으로 보관되게 된다&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;JSON 포맷으로 저장됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;예를 들어, 로컬 설정파일에서 spec &amp;gt; image를 nginx:latest에서 nginx:1.19로 바꾼 뒤에 &lt;code&gt;kubectl apply -f&lt;/code&gt;을 했다고 해 보자&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;그러면 일단 Live Object Configuration이 바뀌고&lt;/li&gt;
&lt;li&gt;그 다음 Last Applied Configuration이 바뀐다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;하지만 로컬 설정파일에서 필드를 삭제한 뒤에 &lt;code&gt;kubectl apply&lt;/code&gt;했다면, Last Applied Configuration과 비교해서 해당 필드가 사라졌음을 확인하고, Live Configuration에서 날린다&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://kubernetes.io/docs/tasks/manage-kubernetes-objects/declarative-config/#merging-changes-to-map-fields&quot;&gt;https://kubernetes.io/docs/tasks/manage-kubernetes-objects/declarative-config/#merging-changes-to-map-fields&lt;/a&gt; 참조&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&amp;quot;마지막으로 적용된 설정&amp;quot;은 사실 Live Object Configuration의 Metadata칸에 저장된다&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;kubectl apply&lt;/code&gt; 시에만 생성되는 필드&lt;/li&gt;
&lt;li&gt;따라서 &lt;code&gt;kubectl create&lt;/code&gt; / &lt;code&gt;kubectl replace&lt;/code&gt; 명령어와 &lt;code&gt;kubetl apply&lt;/code&gt;를 섞어서 쓰면 안 된다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;시험 팁&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--dry-run=client&lt;/code&gt; 옵션을 주면 해당 리소스가 실제로 생성되는것이 아니라, 명령어의 문법이 맞는지, 생성이 가능할지만을 검증해줌&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-o yaml&lt;/code&gt;: Resource Definition을 YAML 형식으로 출력함&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>콤퓨우터/필기: KodeKloud CKA 강의</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/78</guid>
      <comments>https://pscr.tistory.com/78#entry78comment</comments>
      <pubDate>Tue, 14 May 2024 22:29:00 +0900</pubDate>
    </item>
    <item>
      <title>41. Namespaces</title>
      <link>https://pscr.tistory.com/77</link>
      <description>&lt;p&gt;지금까지는 Default 네임서페이스를 사용하고있었다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;쿠버 내부에서 사용하는 Pod, Service에 대해서는, (DNS, 네트워킹 등) kube-system 네임서비스를 사용한다&lt;/li&gt;
&lt;li&gt;모든 사용자들이 사용할 수 있는 리소스는 kube-public으로 지정된다&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;클러스터가 작으면 default 네임스페이스로 상관없지만, 엔터프라이즈/프로덕션 환경에서는 namespace로 나눠 쓰는 편이 좋다&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;예를 들어, 개발환경과 프로덕션환경에서 똑같은 클러스터를 사용하면서도 리소스는 isolate하고 싶은 경우, Dev와 Prod 네임스페이스를 따로 만들어 사용할수있을것이다&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;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;mysql.connect(&amp;quot;db-service&amp;quot;)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;하지만 다른 네임스페이스의 구성원에 접근할때에는 풀네임을 써줘야한다&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;mysql.connect(&amp;quot;db-service.dev.svc.cluster.local&amp;quot;)&lt;/code&gt; - dev 네임스페이스의 db-service에 접속 시&lt;ul&gt;
&lt;li&gt;서비스가 생성되면 이러한 포맷으로 자동으로 DNS엔트리가 추가되기때문&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cluster.local&lt;/code&gt; - 쿠버 클러스트의 도메인&lt;/li&gt;
&lt;li&gt;&lt;code&gt;svc&lt;/code&gt; 서비스에 대한 서브도메인&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dev&lt;/code&gt; - 네임스페이스명&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;kubectl get pods&lt;/code&gt; 명령어에 파라미터를 안넣으면 default 네임스페이스의 pods만 보여준다&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--namespace=네임스페이스-명&lt;/code&gt; 파라미터를 넣어야 함 &lt;/li&gt;
&lt;li&gt;혹은, &lt;code&gt;--all-namespace&lt;/code&gt; 파라미터를 주면 모든 네임스페이스를 전부 보여준다&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;특정 네임스페이스에 오브젝트(Pod같은)걸 만들려면&lt;br&gt;&lt;code&gt;kubectl create -f asdf.yml&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;이러면 default 네임스페이스로 들어감&lt;/li&gt;
&lt;li&gt;다른 곳에 넣으려면 &lt;code&gt;--namespace=네임스페이스-명&lt;/code&gt; 파라미터를 넣어야&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;혹은 Pod Definition file의 metadata칸에&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;metadata:
  namespace: dev&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;옵션을 주어야함&lt;/p&gt;
&lt;h1&gt;네임스페이스의 생성&lt;/h1&gt;
&lt;h2&gt;yaml 설정파일으로&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;apiVersion: v1
kind: namespace
metadata:
  name: 이름&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;를 만든 뒤에 &lt;code&gt;kubectl create -f asdf.yml&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;그냥 명령어로&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;kubectl create namespace 이름&lt;/code&gt;&lt;/p&gt;
&lt;h1&gt;Default 네임스페이스를 다른 걸로 바꾸기&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;kubectl config set-context $(kubectl config current-context) --namespace=이름&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;context&lt;/code&gt; 개념에 대해서는 다음에 알아볼것이다&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;각 네임스페이스에 대한 리소스 요청/제한&lt;/h1&gt;
&lt;p&gt;resource quota를 생성하면된다&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;apiVersion: v1
kind: ResourceQuota
metadata:
    name: compute-quota
    namespace: dev
    # 이제 여기에 제한할 resource들을 넣으면 된다
    requests.cpu: &amp;quot;4&amp;quot;
    requests.memory: 5Gi
    limits.cpu: &amp;quot;10&amp;quot;
    limits.memory: 10Gi&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;kubectl create -f compute-quota.yaml&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl get --help | grep namespace
 Prints a table of the most important information about the specified resources. You can filter the list using a label selector and the --selector flag. If the desired resource type is namespaced you will only see results in your current namespace unless you pass --all-namespaces.
    -A, --all-namespaces=false:
        If present, list the requested object(s) across all namespaces. Namespace in current context is ignored even if specified with --namespace.&lt;/code&gt;&lt;/pre&gt;</description>
      <category>콤퓨우터/필기: KodeKloud CKA 강의</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/77</guid>
      <comments>https://pscr.tistory.com/77#entry77comment</comments>
      <pubDate>Tue, 14 May 2024 22:26:20 +0900</pubDate>
    </item>
    <item>
      <title>36. Services</title>
      <link>https://pscr.tistory.com/76</link>
      <description>&lt;ul&gt;
&lt;li&gt;앱 외부와 내부의 컴포넌트 간의 연결을 가능하게 함&lt;ul&gt;
&lt;li&gt;프론트와 백엔드 Pod group 간의 연결&lt;/li&gt;
&lt;li&gt;end user와의 연결 &lt;/li&gt;
&lt;li&gt;DB와의 연결&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;서비스란, 노드상에 떠 있는 일종의 가상-서버같은 역할을 한다&lt;/p&gt;
&lt;p&gt;192.168.1.2라는 IP를 가진 Node 위에 있는 Pod의 네트워크 범위가 10.244.0.0/24 라고 하고, Pod의 IP가 10.0.244.2라고 하자.&lt;/p&gt;
&lt;h1&gt;NodePort&lt;/h1&gt;
&lt;p&gt;NodePort 서비스는 노드에서 외부 IP로 들어오는 특정 포트에 대해 listen하고 있다가, 해당 포트로 들어오는 연결을 Pod의 포트로 포워딩하는 역할을 한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TargetPort: Pod에서 Listen하고 있는 포트&lt;/li&gt;
&lt;li&gt;Port: NodePort 서비스의 포트&lt;/li&gt;
&lt;li&gt;ClusterIP: NodePort 서비스의 내부 IP&lt;/li&gt;
&lt;li&gt;NodePort: 실제 노드가 listen하는 포트 (기본값: 30000-32767)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;apiVersion: v1
kind: service
metadata:
  name: myapp-svc
  //optional: labels
spec:
  type: NodePort
  ports:
    - targetPort: 80
      port: 80
      nodePort: 30008
  selector: # 어떤 Pod에 대해 포워딩 서비스를 제공할지 선택
    app: myapp
    type: frontend&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;만약 같은 label (app, type)을 가진 여러 Pod이 존재한다면 (예: 여러 개 떠 있는 웹 서버), 해당 Pod들 중에 하나가 랜덤으로 선택됨&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;일종의 로드밸런서 역할을 하게 되는&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pod가 여러 노드에 걸쳐 분산되어있을 경우:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;하나의 서비스를 만들면 해당 노드들에 자동으로 같은 nodePort를 listen하는 service가 배포됨&lt;/li&gt;
&lt;li&gt;따라서 같은 포트, 다른 IP로 접속하면 같은 종류의, 다른 노드에 분산되어 있는 Pod에 접속하는 것이 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;주:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;targetPort를 지정하지 않는 경우 port와 동일한 값이 사용됨&lt;/li&gt;
&lt;li&gt;nodePort를 지정하지 않는 경우 남는 포트가 자동 지정됨&lt;/li&gt;
&lt;li&gt;여러 개의 port mapping이 있을 수 있음, 예를 들어&lt;pre&gt;&lt;code&gt;spec:
type: NodePort
ports:
  - targetPort: 80
    port: 80
    nodePort: 30008
  - targetPort: 443
    port: 443
    nodePort: 30443&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;ClusterIP&lt;/h1&gt;
&lt;p&gt;클러스터 내부에 가상 IP 주소를 만들어서 다른 서비스 간 (프론트와 백 등) 통신을 가능하게 한다.&lt;/p&gt;
&lt;p&gt;Pod들에는 IP가 있다 - 하지만 이 IP들은 static IP가 아니다 (새로운 Pod가 생성되고 기존 Pod는 죽을 수 있음)&lt;/p&gt;
&lt;p&gt;서비스를 통해 Pod를 그룹으로 묶고, 해당 그룹에 접근할 수 있는 단일 인터페이스를 제공할 수 있다 (예를 들어 backend 그룹, ...)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;apiVersion: v1
kind: service
metadata:
  name: myapp-svc
  //optional: labels
spec:
  type: ClusterIP
  ports:
    - targetPort: 80
      port: 80
  selector:
    app: myapp
    type: back-end&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;targetPort: 백엔드가 노출될 포트&lt;/li&gt;
&lt;li&gt;port: 서비스가 노출될 포트&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이렇게 하면, 단일 cluster IP나 서비스의 이름을 통해, 여러 Pod 그룹에 접근할 수 있다&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;NAME     TYPE       CLUSTER-IP
backend  ClusterIP  10.96.0.1&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Imperative Way&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;kubectl expose pod 포드명 --port=포트명 --name myapp-svc --type=ClusterIP&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;이 방법을 쓰면 Pods Label을 Selector로 사용한다. 또 6379:6379이다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;apiVersion: v1
kind: Service
metadata:
  labels:
    tier: db
  name: myapp-svc
spec:
  ports:
  - port: 6379
    protocol: TCP
    targetPort: 6379
  selector:
    tier: db
  type: ClusterIP&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;또는 &lt;code&gt;kubectl create service ClusterIP myapp --tcp=6379:6379&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;이 방법을 쓰면 Pods Label을 Selector로 사용할 수 없고, 자동으로 &lt;code&gt;app=myapp&lt;/code&gt; 셀렉터가 지정된다.&lt;/li&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;LoadBalancer&lt;/h1&gt;
&lt;p&gt;지원되는 클라우드 프로바이더에서 사용할 수 있는 로드 밸런싱 뭐시기&lt;br&gt;CKA는 벤더 뉴트럴한 시험이므로 이것은 출제되지 않는다&lt;/p&gt;</description>
      <category>콤퓨우터/필기: KodeKloud CKA 강의</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/76</guid>
      <comments>https://pscr.tistory.com/76#entry76comment</comments>
      <pubDate>Tue, 14 May 2024 22:25:42 +0900</pubDate>
    </item>
    <item>
      <title>29-32. ReplicaSet과 Deployment</title>
      <link>https://pscr.tistory.com/75</link>
      <description>&lt;p&gt;ReplicationController는 구세대 기술로 ReplicaSet으로 대체되고있다&lt;/p&gt;
&lt;h1&gt;ReplicationController&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;ReplicationController/ReplicaSet은 쿠버네티스 클러스터 상에서 하나의 Pod에 대한 인스턴스 여려 개를 구동할 수 있게 하여 HA(High Availability)를 제공&lt;/li&gt;
&lt;li&gt;하나의 Pod만 존재하는 상황에서도 ReplicationController는 Pod 하나가 죽더라도 자동으로 Pod를 새로 만들어주므로, 쓸모가 있음&lt;/li&gt;
&lt;li&gt;단일 ReplicationController 아래에 여러 노드의 Pod이 있을 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;apiVersion: v1
kind: ReplicationController
metadata:
  name: myapp-rc
  labels:
    app: myapp
    type: front-end

spec: 
  template:
    # 여기에 탬플릿 - 즉 Replicated될 Pod의 definition 대부분을 복붙하면 된다
    metadata:
      name: myapp-pod
      labels:
        app: myapp
        type: frontend
    spec:
      containers:
        - name: nginx-container
          image: nginx

  replicas: 3 # 레플리카의 수&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;똑같이 kubectl create / kubectl apply로 적용, &lt;code&gt;kubectl get replicationcontroller&lt;/code&gt;로 확인&lt;br&gt;ReplicationController에 의해 돌아가고있는 레플리카 Pod들을 보려면 &lt;code&gt;kubectl get pods&lt;/code&gt;로 확인 - 3개의 Pod가 있는 것을 확인가능&lt;/p&gt;
&lt;h1&gt;ReplicaSet&lt;/h1&gt;
&lt;p&gt;우선 Object definition 설정파일을 보자.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;apiVersion: apps/v1  # apps/v1임에 주의
kind: ReplicaSet
metadata:
  name: myapp-rs
  labels:
    app: myapp
    type: front-end

spec: 
  template:
    # 여기에 탬플릿 - 즉 Replicated될 Pod의 definition 대부분을 복붙하면 된다
    metadata:
      name: myapp-pod
      labels:
        app: myapp
        type: frontend
    spec:
      containers:
        - name: nginx-container
          image: nginx

  replicas: 3 # 레플리카의 수, 여기까지는 거의 똑같음
  selector: # ReplicaSet에 의해 생성되지 않은 Pod에 대해서도 관리하려면 여기에서 label 매칭 필요
    matchedLabels:
      type: frontend &lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;spec.selector&lt;/code&gt; 섹션의 존재가 ReplicationContainer와의 차이점 중 하나 - 어떤 Pod이 ReplicaSet 아래에 존재할것인가를 지정하는 섹션&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;하지만 왜 존재하는가? &lt;code&gt;spec.template&lt;/code&gt; 에 이미 Pod specification을 적어놨는데?&lt;ul&gt;
&lt;li&gt;ReplicaSet은 그 외의 Pod도 관리하기때문이다&lt;/li&gt;
&lt;li&gt;만약 &lt;strong&gt;ReplicaSet의 생성전에 생성되었던 Pod의 label이 selector와 일치한다면, ReplicaSet은 그 Pod들도 Replica 생성시에 고려&lt;/strong&gt;한다&lt;ul&gt;
&lt;li&gt;이 경우 matchedLabels 아래에 &lt;code&gt;type: frontend&lt;/code&gt;가 있으므로 해당 type을 label 메타데이터로 가지고있는 Pod들이 해당&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ReplicaSet의 역할은 Pod를 모니터하고, 이 중 하나가 fail하면 새로운 Pod를 Deploy하는 데에 있음&lt;br&gt;메타데이터 label 필터를 통해 해당 ReplicaSet이 모니터링해야 할 Pod를 선택&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;하지만 그렇다고 ReplicaSet 설정의 spec &amp;gt; template: 부분을 날려버리면 안됨&lt;ul&gt;
&lt;li&gt;기존에 수동으로 올린 Pod은 언젠가 죽을 텐데, 이 경우 살려내야 할 것이기 때문&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;ReplicaSet의 설정을 바꾸려면?&lt;/h3&gt;
&lt;p&gt;예를들어 &lt;code&gt;replicas: 6&lt;/code&gt;으로 바꾼다고 하면&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;kubectl replace -f 뭐시기.yml&lt;/code&gt; 하면 된다&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kubectl scale --replicas=6 -f 뭐시기.yml&lt;/code&gt;&lt;ul&gt;
&lt;li&gt;이 경우에는 설정파일의 replicas 옵션이 업데이트되지 않는다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;# kubectl scale --replicas=5 replicaset new-replica-set
replicaset.apps/new-replica-set scaled&lt;/code&gt;&lt;/pre&gt;&lt;h4&gt;Replica의 수를 줄이면&lt;/h4&gt;
&lt;p&gt;필요없는 만큼 알아서 죽는다&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# kubectl scale --replicas=2 replicaset new-replica-set
replicaset.apps/new-replica-set scaled

# kubectl get pods
NAME                    READY   STATUS        RESTARTS   AGE
new-replica-set-cnckh   1/1     Running       0          109s
new-replica-set-j8757   1/1     Running       0          102s
new-replica-set-w6ctk   1/1     Terminating   0          39s
new-replica-set-49cht   1/1     Terminating   0          90s
new-replica-set-sddl8   1/1     Terminating   0          116s&lt;/code&gt;&lt;/pre&gt;&lt;h1&gt;실습&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;controlplane ~ ➜  kubectl get replicasets
NAME              DESIRED   CURRENT   READY   AGE
new-replica-set   4         4         0       69s&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;이러면 이름이 new-replica-set인 ReplicaSet이 1개 있는것이다&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;해당 ReplicaSet은 4개의 Pod으로 구성&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;controlplane ~ ➜  kubectl describe replicasets
Name:         new-replica-set
Namespace:    default
Selector:     name=busybox-pod
Labels:       &amp;lt;none&amp;gt;
Annotations:  &amp;lt;none&amp;gt;
Replicas:     4 current / 4 desired
Pods Status:  0 Running / 4 Waiting / 0 Succeeded / 0 Failed
Pod Template:
  Labels:  name=busybox-pod
  Containers:
   busybox-container:
    Image:      busybox777
    Port:       &amp;lt;none&amp;gt;
    Host Port:  &amp;lt;none&amp;gt;
    Command:
      sh
      -c
      echo Hello Kubernetes! &amp;amp;&amp;amp; sleep 3600
    Environment:  &amp;lt;none&amp;gt;
    Mounts:       &amp;lt;none&amp;gt;
  Volumes:        &amp;lt;none&amp;gt;
Events:
  Type    Reason            Age    From                   Message
  ----    ------            ----   ----                   -------
  Normal  SuccessfulCreate  2m55s  replicaset-controller  Created pod: new-replica-set-c86nb
  Normal  SuccessfulCreate  2m55s  replicaset-controller  Created pod: new-replica-set-gtk68
  Normal  SuccessfulCreate  2m55s  replicaset-controller  Created pod: new-replica-set-jdzqn
  Normal  SuccessfulCreate  2m55s  replicaset-controller  Created pod: new-replica-set-zqsbv&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;이 ReplicaSet은 READY되고 있지 않는데...&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;controlplane ~ ➜  kubectl get pods
NAME                    READY   STATUS             RESTARTS   AGE
new-replica-set-c86nb   0/1     ImagePullBackOff   0          3m41s
new-replica-set-gtk68   0/1     ImagePullBackOff   0          3m41s
new-replica-set-jdzqn   0/1     ImagePullBackOff   0          3m41s
new-replica-set-zqsbv   0/1     ImagePullBackOff   0          3m41s&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;그 이유는 busybox777이라는 이름의 image가 없기때문이다&lt;/p&gt;
&lt;h2&gt;Pod 중 하나를 삭제해보기&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;controlplane ~ ✖ kubectl delete pod new-replica-set-c86nb
pod &amp;quot;new-replica-set-c86nb&amp;quot; deleted&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;controlplane ~ ➜  kubectl get pods
NAME                    READY   STATUS             RESTARTS   AGE
new-replica-set-gtk68   0/1     ImagePullBackOff   0          5m49s
new-replica-set-jdzqn   0/1     ImagePullBackOff   0          5m49s
new-replica-set-zqsbv   0/1     ImagePullBackOff   0          5m49s
new-replica-set-ncsgr   0/1     ImagePullBackOff   0          27s&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;없애자마자 ReplicaSet에서 새 Pod을 만들어냈다 (27s ago)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;controlplane ~ ➜  kubectl create -f /root/replicaset-definition-2.yaml 
The ReplicaSet &amp;quot;replicaset-2&amp;quot; is invalid: spec.template.metadata.labels: Invalid value: map[string]string{&amp;quot;tier&amp;quot;:&amp;quot;nginx&amp;quot;}: `selector` does not match template `labels`&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;이유:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: replicaset-2
spec:
  replicas: 2
  selector:
    matchLabels:
      tier: frontend
  template:
    metadata:
      labels:
        tier: frontend //여기가 잘못됐었음
    spec:
      containers:
      - name: nginx
        image: nginx&lt;/code&gt;&lt;/pre&gt;&lt;h1&gt;Deployment&lt;/h1&gt;
&lt;p&gt;ReplicaSet(와 그 아래에 있는 여러 Pod) 개념을 추상화하여놓은것&lt;/p&gt;
&lt;p&gt;Depolyment의 장점&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Rolling Updates (떠 있는 여러 포드를 순차 업데이트)&lt;/li&gt;
&lt;li&gt;Rollback&lt;/li&gt;
&lt;li&gt;pause / resume&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Deplyoment 설정 파일은 ReplicaSet 설정파일과 매우 비슷하다&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;apiVersion: apps/v1  # apps/v1임에 주의
kind: Deployment
metadata:
  name: myapp-dep
  labels:
    app: myapp
    type: front-end

spec: 
  template:
    metadata:
      name: myapp-pod
      labels:
        app: myapp
        type: frontend
    spec:
      containers:
      - name: nginx-container
        image: nginx

  replicas: 3
  selector:
    matchedLabels:
      type: frontend&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이러한 설정의 Deployment를 돌리면 다음과 같은 결과를 얻을수있다&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# kubectl create -f aaa.yml
deployment &amp;quot;myapp-dep&amp;quot; created

# kubectl get deployments
NAME       DESIRED ...
myapp-dep  3       ...

# kubectl get replicaset
NAME                       DESIRED ...
myapp-deployment-asdfbsdf  3       ...

# kubectl get pods
NAME                                 READY ...
myapp-deployment-asdfbsdf-csdfdsdf   1/1   ...
myapp-deployment-asdfbsdf-esdffsdf   1/1   ...
myapp-deployment-asdfbsdf-gsdfhsdf   1/1   ...&lt;/code&gt;&lt;/pre&gt;</description>
      <category>콤퓨우터/필기: KodeKloud CKA 강의</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/75</guid>
      <comments>https://pscr.tistory.com/75#entry75comment</comments>
      <pubDate>Tue, 14 May 2024 22:22:49 +0900</pubDate>
    </item>
    <item>
      <title>22. Pods with YAML</title>
      <link>https://pscr.tistory.com/74</link>
      <description>&lt;p&gt;쿠버의 Object를 생성하기 위한 YAML은, Pod, Deployment, Service, ReplicaSet, 뭐든 상관없이 대강 아래처럼 생겼으며, 아래의 3가지 root level properties를 꼭 가져야한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
    type: frontend
spec:
  containers:
  - name: nginx-container  # -는 YAML에서 리스트의 첫 항목임을 가리킴
    image: nginx
  - name: busybox
    image: busybox
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;apiVersion / kind&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Pod, Service: v1&lt;/li&gt;
&lt;li&gt;ReplicaSet, Deployment: apps/v1&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;metadata&lt;/h2&gt;
&lt;p&gt;오브젝트에 대한 정보&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Dictionary 구조의 child로 name, labels 등을 가짐&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;기본적으로 쿠버에서 정한 종류의 메타데이터만 추가할 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;label 차일드 아래에는 아무 종류의 k-v 페어나 넣을 수 있다&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;나중에 Selector를 이용해 오브젝트를 필터링할 때 사용한다.&lt;ul&gt;
&lt;li&gt;예시: &lt;code&gt;kubectl get pods --selector=&amp;#39;app=myapp&amp;#39;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;annotations 차일드 아래에도 아무 종류의 k-v 페어나 넣을 수 있다&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;이건 그냥 사람이 읽는 용도고 selector와는 상관없다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;spec&lt;/h2&gt;
&lt;p&gt;특정 오브젝트에 부수되는 객체를 가리킴&lt;br&gt;Pod에 대해서는 containers가 대표적이다.&lt;/p&gt;
&lt;p&gt;하나의 Pod은 컨테이너를 여러 개 가질 수 있다. 예를 들어 1개의 웹서버와 그 웹서버를 감시하는 로깅 데몬이 언제나 한 세트로 배포되어야 한다고 해 보자. 이런 상황에 이 2개의 컨테이너를 하나의 Pod에 담아서 배포하면 삶이 편해지는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;kubectl create -f filename.yml&lt;/code&gt; / &lt;code&gt;kubectl apply -f filename.yml&lt;/code&gt;&lt;/p&gt;
&lt;h1&gt;describe&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;kubectl describe pod webapp&lt;/code&gt;&lt;br&gt;정보를 보여준다&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;➜  kubectl describe pod webapp
Name:             webapp
Namespace:        default
Priority:         0
Service Account:  default
Node:             controlplane/192.22.35.9
Start Time:       Fri, 26 Apr 2024 12:50:11 +0000
Labels:           &amp;lt;none&amp;gt;
Annotations:      &amp;lt;none&amp;gt;
Status:           Pending
IP:               10.42.0.13
IPs:
  IP:  10.42.0.13
Containers:
  nginx:
    Container ID:   containerd://255e04a630afa086a3a0423133e534a1dee661b0f1e9298893694a144330a140
    Image:          nginx
    Image ID:       docker.io/library/nginx@sha256:ed6d2c43c8fbcd3eaa44c9dab6d94cb346234476230dc1681227aa72d07181ee
    Port:           &amp;lt;none&amp;gt;
    Host Port:      &amp;lt;none&amp;gt;
    State:          Running
      Started:      Fri, 26 Apr 2024 12:50:12 +0000
    Ready:          True
    Restart Count:  0
    Environment:    &amp;lt;none&amp;gt;
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-r6vxw (ro)
  agentx:
    Container ID:   
    Image:          agentx
    Image ID:       
    Port:           &amp;lt;none&amp;gt;
    Host Port:      &amp;lt;none&amp;gt;
    State:          Waiting
      Reason:       ImagePullBackOff
    Ready:          False
    Restart Count:  0
    Environment:    &amp;lt;none&amp;gt;
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-r6vxw (ro)
Conditions:
  Type                        Status
  PodReadyToStartContainers   True 
  Initialized                 True 
  Ready                       False 
  ContainersReady             False 
  PodScheduled                True 
Volumes:
  kube-api-access-r6vxw:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  3607
    ConfigMapName:           kube-root-ca.crt
    ConfigMapOptional:       &amp;lt;nil&amp;gt;
    DownwardAPI:             true
QoS Class:                   BestEffort
Node-Selectors:              &amp;lt;none&amp;gt;
Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                             node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type     Reason     Age                From               Message
  ----     ------     ----               ----               -------
  Normal   Scheduled  17s                default-scheduler  Successfully assigned default/webapp to controlplane
  Normal   Pulling    17s                kubelet            Pulling image &amp;quot;nginx&amp;quot;
  Normal   Pulled     16s                kubelet            Successfully pulled image &amp;quot;nginx&amp;quot; in 233ms (233ms including waiting)
  Normal   Created    16s                kubelet            Created container nginx
  Normal   Started    16s                kubelet            Started container nginx
  Normal   BackOff    14s (x2 over 15s)  kubelet            Back-off pulling image &amp;quot;agentx&amp;quot;
  Warning  Failed     14s (x2 over 15s)  kubelet            Error: ImagePullBackOff
  Normal   Pulling    1s (x2 over 16s)   kubelet            Pulling image &amp;quot;agentx&amp;quot;
  Warning  Failed     0s (x2 over 16s)   kubelet            Failed to pull image &amp;quot;agentx&amp;quot;: failed to pull and unpack image &amp;quot;docker.io/library/agentx:latest&amp;quot;: failed to resolve reference &amp;quot;docker.io/library/agentx:latest&amp;quot;: pull access denied, repository does not exist or may require authorization: server message: insufficient_scope: authorization failed
  Warning  Failed     0s (x2 over 16s)   kubelet            Error: ErrImagePull
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;위에서 &amp;quot;webapp&amp;quot; Pod을 구성하는 컨테이너 2개 중 1개가 뻑나있음을 알 수 있다.&lt;br&gt;(&lt;code&gt;kubectl get pods&lt;/code&gt; 를 하면, 다음과 같이 READY 상태가 &lt;code&gt;1/2&lt;/code&gt; 로 되어 있다)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;NAME            READY   STATUS         RESTARTS   AGE
nginx-pod       1/1     Running        0          6m1s
newpods-nl459   1/1     Running        0          5m48s
newpods-82w95   1/1     Running        0          5m48s
newpods-vmdm4   1/1     Running        0          5m48s
webapp          1/2     ErrImagePull   0          3m36s&lt;/code&gt;&lt;/pre&gt;&lt;h1&gt;Pod 날리기&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;kubectl delete pod webapp
pod &amp;quot;webapp&amp;quot; deleted&lt;/code&gt;&lt;/pre&gt;</description>
      <category>콤퓨우터/필기: KodeKloud CKA 강의</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/74</guid>
      <comments>https://pscr.tistory.com/74#entry74comment</comments>
      <pubDate>Tue, 14 May 2024 22:21:27 +0900</pubDate>
    </item>
    <item>
      <title>16-20. kube-apiserver, kube-controller-manager, kube-scheduler, kubelet, kube-proxy</title>
      <link>https://pscr.tistory.com/73</link>
      <description>&lt;h1&gt;kube-apiserver&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;API 요청을 authenticate하고, 검증하고, etcd 클러스터에서 데이터를 뽑아서 전달한다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;etcd와 상호작용하는 유일한 컴포넌트시스템 컴포넌트들의 상태를 주기적으로 확인하고, 문제가 있을 경우 해결을 시도한다&lt;br /&gt;다양한 컴포넌트를 체크하는 Controller들이 kube-controller-manager에 올인원으로 들어가 있다&lt;/li&gt;
&lt;li&gt;kube-controller-manager&lt;/li&gt;
&lt;li&gt;예 - Node Controller의 경우:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;5초에 한 번씩 kube-apiserver를 통해 워커노드의 kubelet을 호출, 상황을 확인함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;노드에서 heartbeat가 오지 않는 경우 40초 후에 unreachable 처리&lt;/li&gt;
&lt;li&gt;5분 후에도 복구되지 않은 경우 해당 노드에 할당된 Pod을 제거&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;예 - Replication Controller의 경우:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Replica 선언에 맞춰 필요한 수의 Pod이 사용 가능한지 체크
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ReplicaSet 하에 있는 Pod이 죽으면, 새로운 Pod을 생성(하도록 kube-apiserver에 요청)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;kube-scheduler&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kube-scheduler는 kube-apiserver로부터 노드가 할당되지 않은 Pod를 확인한 뒤, 스케줄링 알고리즘에 따라 해당 Pod을 노드에 배치하도록 kubelet에 명령을 내린다 (kube-apiserver를 통해)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실제로 Pod을 디플로이하는 것은 각 노드의 kubelet임&lt;/li&gt;
&lt;li&gt;모든 Pod에는 원래 &lt;code&gt;spec&lt;/code&gt; 아래에 &lt;code&gt;nodeName&lt;/code&gt; 필드가 있다&lt;/li&gt;
&lt;li&gt;스케줄러는 Pod 전체를 순회하면서 이 프로퍼티가 설정되지 않은 Pod을 찾는다
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이것이 스케줄링될 후보가 된다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;그 다음 스케줄링 알고리즘에 따라 그 Pod을 어느 노드에 놓을지를 찾는다&lt;/li&gt;
&lt;li&gt;괜찮은 노드를 찾았다면, Live Configuration의 nodeName: 필드를 찾은 노드 이름으로 채운다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 스케줄러가 없다면? 영원히 Pending 상태에 머물것&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하지만 Pod을 수동으로 node에 할당하는 것이 가능하다&lt;/li&gt;
&lt;li&gt;예를 들어, 그냥 yaml 파일에 nodeName을 수동으로 넣어줄 수 있다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만, 일단 Pod이 생성되었다면 그 다음에는 수동으로 nodeName을 건드릴 수가 없다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;대안: Pod의 Binding Object을 생성한 뒤에, Pod의 Binding API에 POST요청을 보낸다&amp;nbsp;&lt;/li&gt;
&lt;li class=&quot;php&quot; data-ke-language=&quot;php&quot;&gt;&lt;code&gt;apiVersion: v1
kind: Binding
metadata:
  name: nginx
target:
  apiVersion: v1
  kind: Node
  name: node02&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;curl --header &quot;Content-Type:application/json&quot; --request POST data '{&quot;apiVersion&quot;:&quot;v1&quot;, &quot;kind&quot;: &quot;binding&quot;, ...}' http://$SERVER/api/v1/namespaces/default/pods/$PODNAME/binding/&lt;/code&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;Kubelet&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Worker node의 대장 역할&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클러스터에 해당 노드를 register&lt;/li&gt;
&lt;li&gt;Heartbeat 요청 시 해당 노드 내부의 정보를 파악해서 돌려줌&lt;/li&gt;
&lt;li&gt;Pod가 할당되면 컨테이너 런타임(CRI-O, ContainerD, Docker)에 요청하여 이미지를 pull하고 컨테이너를 생성, 구동&lt;/li&gt;
&lt;li&gt;Pod의 상태를 확인하고 kube-apiserver에 보고&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kubeadm으로 클러스터를 구성한 경우에는, kubelet은 설치되지 않음&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;따로 설치해줘야 함&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>콤퓨우터/필기: KodeKloud CKA 강의</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/73</guid>
      <comments>https://pscr.tistory.com/73#entry73comment</comments>
      <pubDate>Tue, 14 May 2024 22:18:21 +0900</pubDate>
    </item>
    <item>
      <title>RHCSA 취득 후기 (할인정보, 응시방법, 비대면 시험)</title>
      <link>https://pscr.tistory.com/72</link>
      <description>&lt;h1&gt;시험 종류&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;레드햇은 Red Hat OpenShift, Kubernetes 등 여러 종류의 자격증 시험을 제공하지만, 그 중 가장 역사가 길고 잘 알려진 자격증 3가지는, 난이도 순서대로 RHCSA (Red Hat Certified System Administrator) - RHCE (Red Hat Certified Engineer) - RHCA (Red Hat Certified Architect)일 것입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;RHCSA는 Red Hat Enterprise Linux (RHEL) 서버에 대한 관리능력을 증명하는 자격증입니다. 레드햇 시험코드 EX200에 합격하면 받을 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;image-1.png&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/scSo6/btsGZ1bOwGW/1pHoxkXKyFb7hp2px0KLrk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/scSo6/btsGZ1bOwGW/1pHoxkXKyFb7hp2px0KLrk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/scSo6/btsGZ1bOwGW/1pHoxkXKyFb7hp2px0KLrk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FscSo6%2FbtsGZ1bOwGW%2F1pHoxkXKyFb7hp2px0KLrk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;600&quot; data-filename=&quot;image-1.png&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;RHCE는 원래 RHCSA의 강화판같은 느낌이었지만, 2020년부터 RHCE 취득을 위한 시험이 EX294로 바뀌면서 RHEL 관리능력을 보는 게 아니라 Ansible 자동화 관리 능력을 시험하는 시험으로 바뀌었습니다. RHCSA 없이도 EX294 시험을 볼 수는 있지만, 이 경우엔 합격하더라도 RHCE 자격증이 나오지는 않습니다. 이 경우엔 나중에 추가적으로 EX200 시험을 봐야 RHCE가 나옵니다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;RHCA는 RHCE나 RHCEMD, RHCCD가 있으면서 &quot;Red Hat Certified Specialist&quot; 로 시작하는 여러 종류의 시험 중 5개에 합격해야 주어지는 최고 등급의 자격증입니다. 이들 시험에 추가로 6개 더 합격하면 RHCA Level II가 됩니다. 이걸 갖고있는 사람은 세계에도 얼마 없을겁니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 중에 이 글에서는 첫 단계인 RHCSA에 대해 다룹니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;공부&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;레드햇은 EX200 시험을 치기 전 다음의 강의를 들을 것을 권장합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Red Hat Enterprise Linux 9.0 (RH124) - Red Hat System Administration I&lt;/li&gt;
&lt;li&gt;Red Hat Enterprise Linux 9.0 (RH134) - Red Hat System Administration II&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이 강의를 전부 들으면 이백만원은 우습게 깨지기 때문에?&lt;br /&gt;여러분이 돈이 많거나, 아니면 좋은 회사에 다녀서 비용처리를 해 주는 게 아니라면, 그냥 인터넷에서 &quot;RH124/RH134 Student Workbook&quot; (ROLE, 레드햇 공식 강의에 쓰이는 교재)을 구하세요.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-04-27 오전 1.50.44.png&quot; data-origin-width=&quot;1053&quot; data-origin-height=&quot;574&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lVdrg/btsG0cKZT9h/hOPIMHVxAwbNFoSwqzX1kK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lVdrg/btsG0cKZT9h/hOPIMHVxAwbNFoSwqzX1kK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lVdrg/btsG0cKZT9h/hOPIMHVxAwbNFoSwqzX1kK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlVdrg%2FbtsG0cKZT9h%2FhOPIMHVxAwbNFoSwqzX1kK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1053&quot; height=&quot;574&quot; data-filename=&quot;스크린샷 2024-04-27 오전 1.50.44.png&quot; data-origin-width=&quot;1053&quot; data-origin-height=&quot;574&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 ROLE 교재의 맨 마지막 &quot;Comprehensive Review&quot; 부분은 실제 시험과 유사한 유형으로 구성되어 있기 때문에 반드시 읽어보실 것을 권합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RHEL 8을 이용한 시험은 단종되었고, 이제 RHEL 9로 시험을 보셔야 합니다. Rocky Linux 9를 쓰시면 거의 비슷한 환경에서 체험이 가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시험 내용은 NDA가 걸려있어서 정확히 말씀은 못 드립니다만은, 루트 비밀번호 모르는 상태에서 비번 리셋하는 방법은 꼭 알아두라고 말씀드리고 싶네요...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;할인 정보&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;레드햇 시험은 몇십만원씩 하는 게 기본인 사기업 시험이라는 걸 감안해도 상당히 비싸지만... 심지어 할인마저도 안 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 레드햇에서 RHCE 합격자나 직원에게 최대 3번 사용 가능한 할인코드를 뿌리는 모양인데, 이걸 잘 주워서 쓰는 방법이 거의 유일한 할인수단입니다. 이 코드를 적용하면 원래 55만원에서 15%가 할인되어 467,500원에 응시가 가능합니다.&lt;br /&gt;1개의 할인코드는 최대 3번 사용 가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://old.reddit.com/r/redhat/comments/mrgrv5/red_hat_certification_discount_code_share/&quot;&gt;https://old.reddit.com/r/redhat/comments/mrgrv5/red_hat_certification_discount_code_share/&lt;/a&gt;&lt;br /&gt;이 레딧 스레를 눈팅하고 있으면 한두 달에 한 번 정도는 코드가 뜹니다. 민첩하게 주워서 쓰면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 할인 코드는 공홈 LMS에서만 적용할 수 있는데, 레드햇 공홈에서는 카드결제가 안 되고 계좌이체만 가능합니다.&lt;br /&gt;현금영수증은 문의하면 끊어준다는 듯?&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Pasted image 20240212232147.png&quot; data-origin-width=&quot;1192&quot; data-origin-height=&quot;1306&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9GCgy/btsGY14XvnY/wQhGI5erVhK1OaH0vdlGzk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9GCgy/btsGY14XvnY/wQhGI5erVhK1OaH0vdlGzk/img.png&quot; data-alt=&quot;467500원 현금박치기!!!!!!!&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9GCgy/btsGY14XvnY/wQhGI5erVhK1OaH0vdlGzk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9GCgy%2FbtsGY14XvnY%2FwQhGI5erVhK1OaH0vdlGzk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1192&quot; height=&quot;1306&quot; data-filename=&quot;Pasted image 20240212232147.png&quot; data-origin-width=&quot;1192&quot; data-origin-height=&quot;1306&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;467500원 현금박치기!!!!!!!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공홈에서 구매하면 이렇게 메일이 옵니다. 계좌 정보가 같이 오는데 이 정보대로 입금하면 됩니다. 제가 구매했던 시점 기준 정보:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Standard Chartered Bank Korea (=SC제일은행)&lt;/li&gt;
&lt;li&gt;계좌번호: 471-16-114516961&lt;/li&gt;
&lt;li&gt;예금주: Redhat_jpm&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;꼼수?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;레드햇 시험은 국가별로 가격차이가 있습니다. 예를 들어 미국은 500USD, 일본은 50000엔 (소비세 10% 별도), 대만은 6815대만달러, 인도는 16500루피 (세금 18% 별도)&lt;/li&gt;
&lt;li&gt;따라서 응시권이 좀 싼 국가, 예를 들어 인도에서 시험 voucher를 산 뒤에 리모트로 응시하면 돈을 좀 아낄 수 있을지도 모릅니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하지만, 레드햇 정책에서는 현재 거주 중인 국가에서만 시험을 보도록 되어 있습니다. 저는 시도하지 않았지만 용기?가 넘치신다면 말리지는 않겠습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/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;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;시험 예약&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구매 후 1년 내에 &lt;a href=&quot;https://rhtapps.redhat.com/individualexamscheduler/&quot;&gt;시험 스케줄러&lt;/a&gt;에 접속해서 시험 일정을 잡아야 하는데, 이를 위해서는 정부에서 발행한 사진이 있는 신분증 (Government-Issued Photo ID)을 먼저 업로드해야 합니다. 저는 여권을 업로드했습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Pasted image 20240304021840.png&quot; data-origin-width=&quot;1852&quot; data-origin-height=&quot;988&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TzyaE/btsG0dwmVFg/Hd4NvDi98ZjePEOrajqK1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TzyaE/btsG0dwmVFg/Hd4NvDi98ZjePEOrajqK1K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TzyaE/btsG0dwmVFg/Hd4NvDi98ZjePEOrajqK1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTzyaE%2FbtsG0dwmVFg%2FHd4NvDi98ZjePEOrajqK1K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1852&quot; height=&quot;988&quot; data-filename=&quot;Pasted image 20240304021840.png&quot; data-origin-width=&quot;1852&quot; data-origin-height=&quot;988&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;레드햇 측에서 신분증을 검토하고 Pending Approval(승인대기) 상태에서 Approved(승인됨)상태로 넘어가기까지 시간이 좀 걸립니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;비대면 시험 보기&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요즘 대부분의 레드햇 시험은 Remote Exam(비대면 시험)과 Testing Center Exam(시험장 시험)을 고를 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 봤을 당시 시험장은 서울 강남구의 영우디지탈과 서울 서초구의 패스트레인 코리아 2곳밖에 없었습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2024-03-04 at 02-19-35 Red Hat Exam Scheduler.png&quot; data-origin-width=&quot;2470&quot; data-origin-height=&quot;1484&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwmSnr/btsGZMeSDmV/dHMOhxzUqJpmwkBKyIR8Dk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwmSnr/btsGZMeSDmV/dHMOhxzUqJpmwkBKyIR8Dk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwmSnr/btsGZMeSDmV/dHMOhxzUqJpmwkBKyIR8Dk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbwmSnr%2FbtsGZMeSDmV%2FdHMOhxzUqJpmwkBKyIR8Dk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2470&quot; height=&quot;1484&quot; data-filename=&quot;Screenshot 2024-03-04 at 02-19-35 Red Hat Exam Scheduler.png&quot; data-origin-width=&quot;2470&quot; data-origin-height=&quot;1484&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좀 멀기도 하고, 어차피 저기 가서 시험봐도 그냥 컴퓨터 있는 방에 넣어주고 리모트로 시험보는 거라고 하길래, 그냥 리모트로 보기로 했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;응시 방법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;참조: 최신 가이드는 &lt;a href=&quot;https://learn.redhat.com/t5/Certification-Resources/Getting-Ready-for-your-Red-Hat-Remote-Exam/ba-p/33528?attachment-id=127&quot;&gt;https://learn.redhat.com/t5/Certification-Resources/Getting-Ready-for-your-Red-Hat-Remote-Exam/ba-p/33528?attachment-id=127&lt;/a&gt; 에 있습니다.&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://red.ht/rhrex&quot;&gt;https://red.ht/rhrex&lt;/a&gt; 에서 시험 전용 배포판(Red Hat Remote Exam Environment; RHRE)을 다운로드받습니다.&lt;br /&gt;해당 배포판은 x86_64 아키텍처의 PC에서만 구동가능합니다. T2 칩이 탑재된 인텔맥에서는 호환성 문제가 있을 수 있고, Apple Silicon이 탑재된 Mac에서는 구동이 불가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 iso 파일을 USB나 DVD에 구워서 베어메탈로(BIOS나 UEFI에서 바로 저 배포판으로) 부팅해야 합니다. 가상머신을 사용해서는 안됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1m 이상의 케이블이 달린 USB 웹캠이 필요합니다. 시험 감독관의 지시에 따라 컨닝페이퍼가 없는지 방의 모습을 구석구석 보여줘야 하기 때문에, 노트북에 내장된 기본적으로 웹캠은 허용되지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마이크도 있어야 하는데, 보통 USB 웹캠에는 마이크도 내장되어 있기 마련이므로 그걸 쓰면 됩니다.&lt;/p&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/Me6Y12-sux8?si=NmQhF57Z7BvlIpzq&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 배포판은 페도라 기반으로 시험용으로 커스텀되어 있습니다. 부팅하면 먼저 설정 메뉴가 뜨는데, 여기에서 마이크 음량과 인터넷 연결(와이파이) 설정을 해줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설정 창을 닫으면 파이어폭스가 키오스크 모드(전체화면 상태)로 켜지고, 자동으로 시험 사이트에 접속됩니다. Alt-Tab같은 건 불가능합니다. 시스템 설정창으로 다시 진입하려면 재부팅을 해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시험 시간은 총 3시간입니다. 시험 20분 전부터 시험 사이트의 시험모드에 접속할 수 있습니다. 레드햇 ID와 시험 코드 (제 경우 EX200V9K)를 넣고 접속하면 접속이 가능하며, 이후 오른쪽 아래에 있는 채팅창을 열어 감독관에게 대화를 걸어야 합니다. (레드햇 계정 비밀번호는 입력하지 않아도 됨)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시험 시작 시간 15분이 지나서까지 감독관과 연락을 하지 않는 경우, &lt;b&gt;노쇼로 간주되어 여러분의 55만원이 사라지게 됩니다&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;시험이 시작되면 파이어폭스 상의 웹VNC를 통해 시험 환경에 접속됩니다. 시험 환경은 RHEL 9.0 (Plow)의 GNOME 40 기반 데스크톱 형태이며, 여기에 떠 있는 파이어폭스 브라우저를 통해 도큐멘테이션을 보거나 시험 문제, 남은 시간을 확인할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Inside a Red Hat Certification Exam： What you need to know [Me6Y12-sux8]-0001.png&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1080&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6vfPf/btsG0ICTKLz/bLW7BpIXkWMfESkwYBpkcK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6vfPf/btsG0ICTKLz/bLW7BpIXkWMfESkwYBpkcK/img.png&quot; data-alt=&quot;말하자면 리눅스위의파이어폭스위의웹VNC로띄운리눅스위의파이어폭스인 거죠.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6vfPf/btsG0ICTKLz/bLW7BpIXkWMfESkwYBpkcK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6vfPf%2FbtsG0ICTKLz%2FbLW7BpIXkWMfESkwYBpkcK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1920&quot; height=&quot;1080&quot; data-filename=&quot;Inside a Red Hat Certification Exam： What you need to know [Me6Y12-sux8]-0001.png&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;말하자면 리눅스위의파이어폭스위의웹VNC로띄운리눅스위의파이어폭스인 거죠.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왼쪽에 남은 시험 시간과 언어 선택 메뉴가 있으며, 한국어 옵션도 제공됩니다. 번역이 좀 미묘해서 전 그냥 영어로 놓고 풀긴 했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시험 환경에는 파이어폭스 말고도 실제 시험 채점에 사용되는 서버 VM 2개를 관리할 수 있는 프로그램(VM Control)가 제공됩니다. 서버 VM에도 역시 RHEL 9.0 (Plow)가 깔려 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VM Control은 처음 켜는 것 외에는 그리 쓸 일이 많은 도구는 아닙니다. 각 VM의 상태를 확인하거나 시작, 재부팅, 전원 끄기 등의 기능과 함께 콘솔 기능이 제공되는데, 콘솔은 그래픽 프레임버퍼 출력을 보여주고 키보드 입력을 받아 VM에 리다이렉트해줍니다. 이것은 초기 네트워크 설정이나, 초기 계정 설정 등에 사용하면 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Pasted image 20240318104812.png&quot; data-origin-width=&quot;352&quot; data-origin-height=&quot;554&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Arohk/btsGXRaYPtC/aGFPC0ebESz53eNoYKKNDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Arohk/btsGXRaYPtC/aGFPC0ebESz53eNoYKKNDK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Arohk/btsGXRaYPtC/aGFPC0ebESz53eNoYKKNDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FArohk%2FbtsGXRaYPtC%2FaGFPC0ebESz53eNoYKKNDK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;352&quot; height=&quot;554&quot; data-filename=&quot;Pasted image 20240318104812.png&quot; data-origin-width=&quot;352&quot; data-origin-height=&quot;554&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시험 문제의 지시에 따라 콘솔을 통해 네트워크 설정과 계정 설정 등을 잡아주었다면, 그 다음엔 시험 환경의 터미널을 켜서, VM에 SSH로 붙은 뒤 문제를 풀어나가면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 외에는 Rebuild 기능이 있습니다. Rebuild를 하면 해당 VM이 시험 초기 상태로 돌아가게 됩니다. 즉 지금까지 해당 VM에서 한 작업이 다 날아간다는 것이지요. fstab을 작살냈다든가 해서 VM이 뻗었는데 이걸 복구할 자신이 없을 경우에만 사용하세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;재수가 없다면 시험 중에 환경이 뻗어버리는 경우가 있을 수 있습니다. 시험 환경에 내장된 채팅 외에는 즉각적으로 시험 주최측에 연락할 수 있는 채널이 없기 때문에, 이런 경우에는 그냥 빠르게 재부팅을 하는 것이 최선입니다. 접속이 끊긴 것이 확인되면 감독관이 확인전화를 거니 국제전화가 오면 받으시고요, 나중에 재접속되면 시간을 조금 더 넣어줄겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시험이 다 끝나면 컴퓨터의 전원버튼을 5초 눌러 강제종료하면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;결과&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시험 결과는 공식적으로는 3영업일 내에 보내주는 것으로 되어있는데, 저는 시험 끝난 지 50분도 안 돼서 결과를 받았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과 이메일에서는 각 영역에서 몇 점을 맞았는지, 총점은 몇 점인지가 나오지만, 실제 자격증에는 점수는 기재되지 않습니다. 저는 전반적으로 괜찮은 점수를 받았는데... podman이 좀 망했네요&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-04-27 오전 2.18.20.png&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;1584&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bc45gr/btsGYAUapTn/kXoRQ96E3UvkaZRRsFDBO1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bc45gr/btsGYAUapTn/kXoRQ96E3UvkaZRRsFDBO1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bc45gr/btsGYAUapTn/kXoRQ96E3UvkaZRRsFDBO1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbc45gr%2FbtsGYAUapTn%2FkXoRQ96E3UvkaZRRsFDBO1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1400&quot; height=&quot;1584&quot; data-filename=&quot;스크린샷 2024-04-27 오전 2.18.20.png&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;1584&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과가 나오면 레드햇 계정에 연동하시면 되고, 몇 시간 정도 뒤에 Credly 계정에 연동하라는 메일이 옵니다. 그러면 뺏-지와 자격증 PDF를 받을 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Red_Hat_Certified_System_Administrator__RHCSA__Badge20240318-29-4svrcz.png&quot; data-origin-width=&quot;3295&quot; data-origin-height=&quot;2551&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TfgpS/btsGYcFZj2s/crqkHgHYDNKLNXsuKUjwGk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TfgpS/btsGYcFZj2s/crqkHgHYDNKLNXsuKUjwGk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TfgpS/btsGYcFZj2s/crqkHgHYDNKLNXsuKUjwGk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTfgpS%2FbtsGYcFZj2s%2FcrqkHgHYDNKLNXsuKUjwGk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3295&quot; height=&quot;2551&quot; data-filename=&quot;Red_Hat_Certified_System_Administrator__RHCSA__Badge20240318-29-4svrcz.png&quot; data-origin-width=&quot;3295&quot; data-origin-height=&quot;2551&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;h2 data-ke-size=&quot;size26&quot;&gt;그래서 돈값을 하나요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;55만원어치의 가치를 하는지는 사실 아직 잘 모르겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 &lt;i&gt;내가 누구? &quot;Red Hat&amp;reg; Certified System Administrator (RHCSA&amp;reg;) 오우너&quot;&lt;/i&gt; 라고 할 수 있는 것은 장점일 수도 있겠읍니다.&lt;/p&gt;</description>
      <category>콤퓨우터/Linux</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/72</guid>
      <comments>https://pscr.tistory.com/72#entry72comment</comments>
      <pubDate>Sat, 27 Apr 2024 09:45:31 +0900</pubDate>
    </item>
    <item>
      <title>Next.js Full Course 필기 (4)</title>
      <link>https://pscr.tistory.com/71</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Fireship.io의 &quot;&lt;a href=&quot;https://fireship.io/courses/nextjs/&quot;&gt;Next.js Full Course&lt;/a&gt;&quot; 강의를 듣고 필기했던 내용입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h1&gt;Follow 기능 만들기&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;데이터베이스 스키마 수정&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Follows 모델:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;followerId 피팔로우자의ID&lt;/li&gt;
&lt;li&gt;followingId 팔로우하는 자의 ID&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@@id([followerId, followingId])&lt;/code&gt;: userA_userB 같은 식으로 만들어지는 해당 팔로우에 대한 고유ID
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;  followedBy    Follows[] @relation(&quot;following&quot;)
  following     Follows[] @relation(&quot;follower&quot;)
}

model Follows {
  follower    User @relation(&quot;follower&quot;, fields: [followerId], references: [id])
  followerId  String
  following   User @relation(&quot;following&quot;, fields: [followingId], references: [id])
  followingId String

  @@id([followerId, followingId])
}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Follow API Route&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;POST(팔로우 시)와 DELETE(언팔로우 시) 함수를 export한다.&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;export async function POST(req:Request) {
    const session = await getServerSession(authOptions);
    const currentUserEmail = session?.user?.email!;
    const {targetUserId} = await req.json();

    //authOptions를 수정해서 jwt에 userId를 저장하게 하는 식으로 구현하면
    //이 부분의 쿼리를 절약할수있을수도있나? 다음기회에 알아보자
    const currentUserId = await prisma.user.findUnique({where:{email:currentUserEmail}})
        .then((user) =&amp;gt; user?.id!);

    const record = await prisma.follows.create({
        data: {
            followerId: currentUserId,
            followingId: targetUserId
        }
    });
    return NextResponse.json(record);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DELETE:&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;
export async function DELETE(req:NextRequest) {
    const session = await getServerSession(authOptions);
    const currentUserEmail = session?.user?.email!;
    const targetUserId = req.nextUrl.searchParams.get('targetUserId');

    const currentUserId = await prisma.user.findUnique({where:{email:currentUserEmail}})
        .then((user) =&amp;gt; user?.id!);

    const record = await prisma.follows.delete({
        where: {
            followerId_followingId: {
                followerId: currentUserId,
                followingId: targetUserId!
            }
        }
    });
    return NextResponse.json(record);
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;User Inteface 만들기&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;현재 사용자가 해당 사용자를 팔로우하는지 체크하여 팔로우/언팔로우 버튼을 표시&lt;/li&gt;
&lt;li&gt;버튼을 클릭하는 즉시 (서버의 응답을 기다리지 않고) 팔로우 버튼이 언팔로우 버튼으로 변경&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 컴포넌트는 /app/components가 아니라 /components에 왔어야 하는 건데 지금까지 잘못 쓰고 있었다&lt;br /&gt;뭐 일단 넘어갑시다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;/components/FollowButton/&lt;/code&gt; 하위에 FollowButton 서버 컴포넌트와 FollowClient 클라이언트 컴포넌트를 만든다&lt;br /&gt;현재 유저를 보고 해당 유저가 지금 보이는 유저를 팔로우하는지 확인하는 부분은 서버 컴포넌트로 구현합니다&lt;br /&gt;targetUserId를 Prop으로 받는 async 컴포넌트 FollowButton을 export하고&lt;br /&gt;팔로우 여부를 구한 뒤 Child Component인 FollowClient에 해당 데이터를 넘겨준다&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;interface Props {
    targetUserId: string;
}

export default async function FollowButton({targetUserId}: Props) {
    const session = await getServerSession(authOptions);    

    const currentUserId = await prisma.user
        .findFirst({where: {email: session?.user?.email!}})
        .then((user) =&amp;gt; user?.id!);

    const isFollowing = await prisma.follows.findFirst({
        where: {followerId: currentUserId, followingId: targetUserId}
    });

    return(&amp;lt;FollowClient targetUserId={targetUserId} isFollowing={!!isFollowing}) /&amp;gt;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;!!isFollowing을 하여 boolean타입으로 변환하는 효과를 준다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DELETE (언팔로우)도 비슷한 느낌이지만, 대신 이 친구는 API endpoint가 &lt;code&gt;DELETE /api/follow?targetuserId=targetUserId&lt;/code&gt; 같은 식으로 될 것이므로,&lt;/p&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;const targetUserId = req.nextUrl.searchParams.get('targetUserId');&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;를 이용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;/components/FollowButtons/FollowClient.tsx&lt;/code&gt;:&lt;br /&gt;간단하게 버튼을 구현하면 이렇게 된다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;&quot;use client&quot;;
interface Props{
    targetUserId: string,
    isFollowing: boolean
}

export default function FollowClient({targetUserId, isFollowing}: Props) {
    if(isFollowing) {
        return (
            &amp;lt;button onClick={unfollow}&amp;gt;
                {'Unfollow'}
            &amp;lt;/button&amp;gt;
        );
    } else {
        return (
            &amp;lt;button onClick={follow}&amp;gt;
                {'follow'}
            &amp;lt;/button&amp;gt;
        );
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이러면 눌렀을때 바로 버튼이 바뀌어야한다는 요구조건을 만족시키지 못한다.&lt;br /&gt;이것을 위해 Next Router와 React의 useTransition() 훅(로딩상태를 확인하는 훅)을 이용한다. 또 useState() 훅도 이용하여 서버에서 값을 받아오는 중인지도 저장하도록하자.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;useState() 훅 - useState() 훅을 사용하면 Stateful한 Value를 만들어, 변경될 때마다 여기에 의존하는 컴포넌트들이 자동으로 재렌더링되게할수있다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 배열의 첫 번째는 UI에서 사용할 실제 값으로, 두 번째는 함수로 구성&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;export default function FollowClient({targetUserId, isFollowing}: Props) {
    const router = useRouter();
    const [isPending, startTransition] = useTransition();
    const [isFetching, setIsFetching] = useState(false);
    const isMutating = isFetching || isPending;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자가 버튼을 클릭했을 때 사용되는 event handler를 만든다.&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;startTransition()&lt;/code&gt;을 이용하면 현재 있는 라우트를 위해 서버에 새로운 요청을 만들 수 있다. 타겟 사용자가 현재 사용자를 팔로우하고 있는지에 대해 확인하여 페이지의 상태를 변화시키지 않고서도 seamlessly하게.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;    const follow = async() =&amp;gt; {
        setIsFetching(true);
        const res = await fetch('/api/follow', {
            method: &quot;POST&quot;,
            body: JSON.stringify({targetUserId}),
            headers: {
                'Content-Type': 'application/json'
            }
        });
        setIsFetching(false);
        console.log(res);
        startTransition(() =&amp;gt; {
            router.refresh();
        });
    };&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;업데이트 중일 때에는 버튼 표시를 다음과 같이...&lt;/p&gt;
&lt;pre class=&quot;hsp&quot;&gt;&lt;code&gt;    if(isFollowing) {
        return (
            &amp;lt;button onClick={unfollow}&amp;gt;
                {!isMutating ? 'Unfollow' : '...'}
            &amp;lt;/button&amp;gt;
        );
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 이렇게 만든 버튼 컴포넌트를 &lt;code&gt;/app/users/[id]/page.tsx&lt;/code&gt; 같은 데 넣어주면 된다.&lt;/p&gt;
&lt;h1&gt;Next.js Server Actions&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트 컴포넌트에 서버에서 구동되는 하나의 함수를 만들 수 있는 기능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것을 사용하면, 굳이 form을 API 엔드포인트를 만들어서 처리하지 않아도, 마치 원시 고대 PHP처럼 한 파일에서 폼과 폼 처리용 코드가 같이 있게 만들 수 있다. &lt;/p&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;?php
    echo 'Hello, ' + $_POST['name'];
?&amp;gt;
&amp;lt;form method=&quot;post&quot;&amp;gt;
    &amp;lt;input type=&quot;text&quot; id=&quot;name&quot; name=&quot;name&quot;/&amp;gt;
    &amp;lt;input type=&quot;submit&quot; /&amp;gt;
&amp;lt;/form&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;(원시고대 PHP의 상상도, 요즘은 이렇게 안 합니다... 보통?)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 옛날 PHP와 다른 점은, Next.js의 Actions는 페이지를 새로고침하지 않고 그냥 페이지 재렌더링하기 때문에 페이지 이동이 발생하지 않아 UX상에서 큰 차이를 보인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예제를 보자.&lt;br /&gt;&lt;code&gt;/app/dogs/[id]/edit/page.tsx&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;xquery&quot;&gt;&lt;code&gt;export default async function EditPage({
    params,
}: {
    params: {id: string};
}) {
    const dog = await prisma.dog.findFirst({where: {id: params.id}});

    async function updateDog(formData: FormData) {
        &quot;use server&quot;; //Server-Side Endpoint
        await prisma.dog.update({where: {id: dog.id}, data: 
            {
                name: formData.get(&quot;title&quot;),
                breed: formData.get(&quot;breed&quot;)
            }
        });
        revalidatePath(`/dogs/${params.id}/edit`);
    }
    return (
        &amp;lt;div className={styles.card}&amp;gt;
            &amp;lt;div className={styles.cardBody}&amp;gt;
                &amp;lt;h2&amp;gt;Edit {dog?.name}&amp;lt;/h2&amp;gt;
                &amp;lt;form action={updateDog}&amp;gt;
                    &amp;lt;label&amp;gt;Name&amp;lt;/label&amp;gt;
                    &amp;lt;input name=&quot;title&quot; type=&quot;text&quot; defaultValue={dog?.name} /&amp;gt;
                    &amp;lt;label&amp;gt;Breed&amp;lt;/label&amp;gt;
                    &amp;lt;input name=&quot;breed&quot; type=&quot;text&quot; defaultValue={dog?.breed} /&amp;gt;
                    &amp;lt;button type=&quot;submit&quot;&amp;gt;save&amp;lt;/button&amp;gt;
                &amp;lt;/form&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
    );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 return 부분 JSX의 &quot;form&quot;을 보자.&lt;br /&gt;onClick 이벤트가 아니라 &lt;code&gt;&amp;lt;form action={updateDog}&amp;gt;&lt;/code&gt;을 쓰고 있는 것을 볼 수 있다. 이것은 해당 폼을 처리할 서버 사이드 함수의 이름이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 함수는 &quot;use server&quot; directive를 맨 처음에 선언한다. 그러면 이 함수는 자동적으로 서버측 엔드포인트가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;&amp;lt;form action={updateDog}&amp;gt;&lt;/code&gt;에서 보낸 폼은 자동으로 &lt;code&gt;/dogs/[id]/edit&lt;/code&gt;로 가는 &lt;code&gt;POST&lt;/code&gt; 요청이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 POST 요청을 받는 것이 &lt;code&gt;&quot;use server&quot;;&lt;/code&gt; 로 선언된 함수이다. 필요할 경우 이 함수에서 헤더, 쿠키 등에도 접근할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;qml&quot;&gt;&lt;code&gt;async function updateDog(formData: FormData) {
    &quot;use server&quot;; //Server-Side Endpoint
    await prisma.dog.update({where: {id: dog.id}, data: 
        {
            name: formData.get(&quot;title&quot;),
            breed: formData.get(&quot;breed&quot;)
        }
    });
    revalidatePath(`/dogs/${params.id}/edit`);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;prisma.dog.update()&lt;/code&gt; 를 통해 DB의 Dog 테이블을 업데이트해준 뒤, next-cache의 revalidatePath() 함수를 불러, 캐시를 버리고 (변경된 DB의 데이터를 이용해) 서버 컴포넌트를 재렌더링하도록 할 수 있다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;formAction&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JSX의 &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt;에 formAction 프로퍼티를 넣어서 아까와 다른 server function에서 해당 폼을 처리하도록 만들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 &quot;저장&quot; 버튼 옆에 &quot;저장하고 돌아가기&quot; 같은 버튼을 만든다고 해 보자.&lt;/p&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;button type=&quot;submit&quot;&amp;gt;save&amp;lt;/button&amp;gt;
&amp;lt;button formAction={updateDogAndBack}&amp;gt;save and go back&amp;lt;/button&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 새로운 서버 함수를 만들어준다.&lt;/p&gt;
&lt;pre class=&quot;qml&quot;&gt;&lt;code&gt;async function updateDogAndBack(formData: FormData) {
    &quot;use server&quot;; //Server-Side Endpoint
    await prisma.dog.update({where: {id: dog.id}, data: 
        {
            name: formData.get(&quot;title&quot;),
            breed: formData.get(&quot;breed&quot;)
        }
    });
    redirect(`/dogs/${params.id}`);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하면 &quot;save and go back&quot; 버튼을 눌렀을 때 폼을 updateDogAndBack() 함수에서 처리하고, 그 결과 폼의 값으로 DB를 업데이트한 후 사용자는 &lt;code&gt;/dogs/[id]&lt;/code&gt; 페이지로 이동된다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;외부에 있어도 된다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버 액션이 꼭 서버 컴포넌트 안에 있어야 하는 것은 아니다. 외부 파일로 빼서 export 해 줄 수도 있다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;클라이언트 컴포넌트에서 서버 액션 사용&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Actions 관련 프로퍼티는 폼 안에 있는 elements에서만 적용된다.&lt;br /&gt;하지만 클라이언트 컴포넌트에서 서버 액션을 트리거할 수 없는 것은 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어&lt;br /&gt;&lt;code&gt;/app/dogs/[id]/actions.ts&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;qml&quot;&gt;&lt;code&gt;&quot;use sever&quot;;

export async function like(dogid: string) {
    await prisma.update.likes({
        where: {id: dogid},
        data: {
            likes: {increment: 1}
        }
    });
    revalidatePath(`/dogs/${dogid}`);
}

export async function dislike(dogid: string) {
...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가 있다고 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고, 클라이언트 컴포넌트 &lt;code&gt;Likes.tsx&lt;/code&gt;은 useTransition() 훅을 이용해 블로킹 없이 상태 업데이트를 처리한다. 서버 액션을 실행한 뒤 next.js router가 서버 컴포넌트를 리로딩하고, 상태를 업데이트하는 모든 작업을 한번에 할 수 있다는 것이다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;&quot;use client&quot;;
import {like, dislike} from './actions';

export default function Likes({id}: any) {
    let [isPending, startTransition] = useTransition();

    return(
        &amp;lt;div&amp;gt;
            &amp;lt;button onClick={() =&amp;gt; startTransition(() =&amp;gt; like(id))}&amp;gt;like&amp;lt;/button&amp;gt;
            &amp;lt;button onClick={() =&amp;gt; startTransition(() =&amp;gt; dislike(id))}&amp;gt;dislike&amp;lt;/button&amp;gt;
        &amp;lt;/div&amp;gt;
    );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 이 버튼을 클릭하면 저 서버 액션 함수가 호출되는 것은 물론, 클라이언트 컴포넌트를 포함한 서버 컴포넌트까지 (이 경우 like 카운터) 전부 갱신되는 것을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구버전에서는 useEffect()로 삽질했어야 했을 것을 이제 서버 액션을 통해 거의 모두 해결할 수 있다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Optimistic Update&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 구현에서는 서버에서 값을 받아와야 비로소 카운터가 업데이트된다. Optimistic Update를 통해 일단 버튼을 누르면 카운터를 바꾸고, 서버에서 응답이 오면 그때 다시 카운터를 서버의 값으로 동기화하도록 해 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 위해 체-신 &lt;code&gt;useOptimistic()&lt;/code&gt; 훅을 이용한다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;&quot;use client&quot;;

&quot;use client&quot;;
import {like, dislike} from './actions';

export default function Likes({LikeCount, id}: any) {
    const [optimisticLikes, addOptimisticLike] = useOptimistic(
        {likeCount, sending: false},
        (state, newLikeCount) =&amp;gt; ({
            ...state,
            likeCount: newLikeCount,
            sending: true,
        })
    );

    return(
        &amp;lt;div&amp;gt;
            &amp;lt;div&amp;gt;
            OptimisticLikes: {optimisticLikes.likeCount}
            {optimisticLikes.sending? &quot;Sending&quot;: &quot;&quot;}
            &amp;lt;button onClick={async () =&amp;gt; addOptimisticLike(optimisticLikes.likeCount + 1)}&amp;gt;like&amp;lt;/button&amp;gt;
            &amp;lt;button onClick={async () =&amp;gt; addOptimisticLike(optimisticLikes.likeCount - 1)}&amp;gt;dislike&amp;lt;/button&amp;gt;
        &amp;lt;/div&amp;gt;
    );
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>콤퓨우터/프로그래밍</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/71</guid>
      <comments>https://pscr.tistory.com/71#entry71comment</comments>
      <pubDate>Sun, 17 Mar 2024 16:54:45 +0900</pubDate>
    </item>
    <item>
      <title>Next.js Full Course 필기 (3)</title>
      <link>https://pscr.tistory.com/70</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Fireship.io의&amp;nbsp;&quot;&lt;a href=&quot;https://fireship.io/courses/nextjs/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Next.js&amp;nbsp;Full&amp;nbsp;Course&lt;/a&gt;&quot;&amp;nbsp;강의를&amp;nbsp;듣고&amp;nbsp;필기했던&amp;nbsp;내용입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h1&gt;Protecting Routes from User&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 로그인하지 않은 사용자에게는 특정 라우트에 접근하지 못하게 하고 싶을 수 있다&lt;br /&gt;서버 컴포넌트에서 그렇게 하지 못 하게 하는 가장 좋은 방법은, &lt;code&gt;getSeverSession()&lt;/code&gt;을 쓰는 것이다 (로그인이 되어 있지 않다면 &lt;code&gt;NULL&lt;/code&gt;이 될 것이기 때문)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const session = await getServerSession();
if(!session) {
    // Option #1 - 'next/navigation'의 redirect 사용하여 로그인 페이지로 보내버리기
    redirect('/api/auth/signin');
    // Option #2
    return &amp;lt;p&amp;gt;You must sign in to see this content&amp;lt;/p&amp;gt;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Prisma&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ORM (Object Relation Mapper)이다&lt;br /&gt;설정을 마쳤다면 &lt;code&gt;/lib/prisma.ts&lt;/code&gt; 파일을 생성하여&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;import { PrismaClient } from &quot;@prisma/client&quot;;
export const prisma = new PrismaClient();&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Auth Datastore&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지는 유저 데이터를 저장을 안 했다&lt;br /&gt;이제는 &amp;gt;&amp;gt;&amp;gt;데이터베이스&amp;lt;&amp;lt;&amp;lt; 가 있기때문에 여기에 세션을 저장하고자 하였다&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;npm install @prisma/client @next-auth/prisma-adapter&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 &lt;code&gt;/app/api/auth/[...nextauth]/route.ts&lt;/code&gt;의 NextAuthOptions 부분에&lt;/p&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;export const authOptions: NextAuthOptions = {
    adapter: PrismaAdapter(prisma),
    providers:
    (...)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;를 추가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만!!!&lt;br /&gt;The CredentialsProvider is not compatible with Database Sessions. In order for credentials to work, you need to configure Next-Auth to use JWT sessions instead of Database sessions.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, next-auth에서 비밀번호 로그인 등을 구현하기 위해 Credentials Provider를 이용하였다면 jwt만 쓸 수 있다. 주의!!!!!!&lt;/p&gt;
&lt;h1&gt;DB의 데이터를 접근하는 API Route 만들어보기&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;/app/api/users/route.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;import { prisma } from '@/lib/prisma'
import { NextResponse } from 'next/server'

export async function GET(req: Request) {
    const users = await prisma.user.findMany();
    return NextResponse.json(users);
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Prisma ORM에 의해 &lt;code&gt;prisma.user&lt;/code&gt;를 통해 Users 테이블의 데이터를 객체지향-적으로 접근할 수 있음&lt;/li&gt;
&lt;li&gt;NextResponse.json()을 통해 JSON 형식으로 반환&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Server Component에서 DB 데이터 받아오기&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Next.js에서는, 굳이 API Route에 fetch()를 해서 데이터베이스의 데이터를 받아오지 않아도, 그냥 Server Component에서 Prisma를 통해 DB에 직접 접속할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;/app/users/page.tsx&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;import { prisma } from &quot;@/lib/prisma&quot;;
import styles from './page.module.css';
import UserCard from '@/app/components/UserCard';

export default async function Users() {
    const users = await prisma.user.findMany();
    return (
        &amp;lt;div className={styles.grid}&amp;gt;
            {users.map((user) =&amp;gt; {
                return &amp;lt;UserCard key={user.id} {...user} /&amp;gt;;
            })}
        &amp;lt;/div&amp;gt;
    );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주: UserCard 컴포넌트 (&lt;code&gt;/app/components/UserCard.tsx&lt;/code&gt;)&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;import Link from 'next/link';
import styles from './UserCard.module.css';

interface Props {
    id: string;
    name: string | null;
    age: number | null;
    image: string | null;
}

export default function UserCard({id, name, age, image}: Props) {
    return(
        &amp;lt;div className={styles.card}&amp;gt;
            &amp;lt;div className={styles.cardContent}&amp;gt;
                &amp;lt;h3&amp;gt;
                    &amp;lt;Link href={`/users/${id}`}&amp;gt;{name}&amp;lt;/Link&amp;gt;
                    &amp;lt;p&amp;gt;Age: {age}&amp;lt;/p&amp;gt;
                &amp;lt;/h3&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
    );
}&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Dynamic Route에서의 Data fetching&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버 컴포넌트 &lt;code&gt;/app/users/[id]/page.tsx&lt;/code&gt;를 만든다. 이것은 &lt;code&gt;url.com/users/1235&lt;/code&gt; 같은 식으로 매칭될것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 &lt;code&gt;Props&lt;/code&gt; 인터페이스를 만들어 { params } 의 타입으로 쓴다. 이 params는 URL 상의&lt;code&gt;[id]&lt;/code&gt;를 담는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 페이지는 Dynamic 하다 - 사용자가 언제 프로필을 바꿀지 예상할 수는 없는 노릇인 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또, generateMetadata() 함수를 선언하여 HTML &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; 부분의 &lt;code&gt;&amp;lt;meta&amp;gt;&lt;/code&gt; 태그나 &lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt; 또한 동적으로 생성한다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;import { prisma } from '@/lib/prisma';
import { Metadata } from 'next';

interface Props {
    params: {
        id: string
    };
}
export default async function UserProfile({params}: Props) {
    const user = await prisma.user.findUnique({
        where: {
            id: params.id
        }
    });
    const {name, bio, image} = user ?? {};
    return (
        &amp;lt;div&amp;gt;
            &amp;lt;h1&amp;gt;{name}&amp;lt;/h1&amp;gt;
            &amp;lt;h3&amp;gt;{bio}&amp;lt;/h3&amp;gt;
        &amp;lt;/div&amp;gt;
    );
}

export async function generateMetadata({params}: Props) : Promise&amp;lt;Metadata&amp;gt; {
    const user = await prisma.user.findUnique( {where: {id: params.id}} );
    return {title: `User profile page of {${user?.name}}`};
}&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;로딩 상태 UI&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Next.js 13에서는 매우 쉽게 로딩UI 처리를 구현할 수 있다. loading.tsx를 만들고 로딩 UI로 보여주고 싶은 컴포넌트를 export해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;/app/users/loading.tsx&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;export async default function LoadingUsers() {
    return &amp;lt;div&amp;gt;Loading user data&amp;lt;/div&amp;gt;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 이 로딩 화면 자식 컴포넌트에도 상속된다. 이게 싫다면 자식 컴포넌트의 경로에 &lt;code&gt;loading.tsx&lt;/code&gt;를 새로 만들어주면 된다.&lt;/p&gt;
&lt;h1&gt;에러 UI&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에러 UI는 클라이언트 컴포넌트로 선언되어야 한다. 또 &lt;code&gt;export default function Error()&lt;/code&gt;를 export한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 컴포넌트는 error와 reset이라는 두가지 prop을 받는다. error는 에러 객체이고, reset는 페이지 컴포넌트를 재렌더하기 위한 Next.js의 special function이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 에러를 &lt;code&gt;console.log()&lt;/code&gt;으로 찍으려면, 그냥 React의 useEffect 훅* 을 이용해주면 error 객체가 변경될 때마다 콘솔에 로그를 찍을수있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 엔드 유저에게 노출된 JSX에는 reset() 함수를 호출하는 버튼을 넣어줄 수 있다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;&quot;use client&quot;;

import { useEffect } from &quot;react&quot;;

export default function Error({error, reset}: {error: Error, reset: () =&amp;gt; void}) {
    useEffect(() =&amp;gt; {
        console.log(error);
    }, [error]);
    return (
        &amp;lt;div&amp;gt;
            &amp;lt;h2&amp;gt;Something went wrong&amp;lt;/h2&amp;gt;
            &amp;lt;button onClick={() =&amp;gt; reset()}&amp;gt;try again&amp;lt;/button&amp;gt;
        &amp;lt;/div&amp;gt;
    );
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;리액트의 useEffect() 훅 되짚고 넘어가기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1번째 arg는 function (구동할 함수) 이고, 2번째 arg는 언제 해당 함수를 구동할지에 대한 정보를 담은 Array임.&lt;br /&gt;=&amp;gt; 2번째 Arg인 array는 Data Dependencies를 담고 있음 (dependencies: 데이터 변경 시 함수 구동). 예를 들어,&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;const [count] = useState(0);
useEffect(() =&amp;gt; {console.log(&quot;asdf&quot;)}, [count]);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;을 하면 함수가 count가 바뀔 때마다 돌아감&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Array가 비어 있으면 컴포넌트가 initalise될 때에 함수가 구동됨 (= 해당 컴포넌트가 mount될 때에만 구동됨)&lt;/li&gt;
&lt;li&gt;Array에 Dependency를 추가하면 해당 데이터가 갱신될 때마다 함수가 구동됨 (= 매 Update 때마다 구동됨)&lt;/li&gt;
&lt;li&gt;useEffect() 내부의 함수에서 다른 함수를 Return하면, 컴포넌트가 Destroy될 때 Return된 함수가 구동됨&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;프로필 수정기능 실장&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2가지의 컴포넌트를 이용하여 자기 프로필을 수정하는페이지를 만들것이다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;/app/dashboard/ProfileForm.tsx&lt;/code&gt; - 클라이언트컴포넌트, Validation &amp;amp; Form Submission&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/app/dashboard/page.tsx&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;page.tsx&lt;/code&gt;:&lt;br /&gt;먼저 getServerSession()을 이용하여 로그인되지 않은 사용자가 접근하면 로그인 페이지로 보내버리자&lt;/p&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;const session = await getServerSession(authOptions);
if(!session) redirect('/api/auth/signin');&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음은 로그인된 유저의 현재 이메일을 가져와 해당 이메일과 일치하는 사용자 정보를 가져온다&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;const user = await prisma.user.findUnique({
    where: {
        email: session?.user?.email!
    }
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후 클라이언트 렌더링될 폼에 정보를 넘겨준다&lt;/p&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;return (&amp;lt;&amp;gt;
    &amp;lt;h1&amp;gt;Dashboard&amp;lt;/h1&amp;gt;
    &amp;lt;ProfileForm user={user} /&amp;gt;
&amp;lt;/&amp;gt;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;ProfileForm.tsx&lt;/code&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;form의 onSubmit을 통해 폼의 전송을 가로채고 updateUser 함수를 부른다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1710661911239&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    return(
        &amp;lt;div&amp;gt;
            &amp;lt;h2&amp;gt;Edit your profile&amp;lt;/h2&amp;gt;
            &amp;lt;form onSubmit={updateUser}&amp;gt;
                &amp;lt;label htmlFor=&quot;name&quot;&amp;gt;Name&amp;lt;/label&amp;gt;
                &amp;lt;input type=&quot;text&quot; name=&quot;name&quot; defaultValue={user?.name ?? ''} /&amp;gt;
	...&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;updateUser 함수:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;code&gt;e.preventDefault()&lt;/code&gt; 를 통해 페이지가 새로고침되는것을 방지한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; start=&quot;2&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;브라우저 Form상의 데이터를 가져온다.&lt;/li&gt;
&lt;/ol&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; start=&quot;3&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;백엔드 API로 데이터를 쏜다.
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;const updateUser = async(e: React.FormEvent&amp;lt;HTMLFormElement&amp;gt;) =&amp;gt; {
e.preventDefault();
const formData = new FormData(e.currentTarget);
const body = {
name: formData.get('name'),
...
};
const res = await fetch('/api/user', {
method: 'PUT',
body: JSON.stringify(body),
headers: {'Content-Type': 'application/json'}
});
});&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&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;h2 data-ke-size=&quot;size26&quot;&gt;프로필 API 구현&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;API 엔드포인트: &lt;code&gt;/api/user/route.ts&lt;/code&gt;&lt;br /&gt;HTTP &lt;code&gt;PUT&lt;/code&gt;에 해당되는 async function을 export한다.&lt;/li&gt;
&lt;li&gt;현재 세션의 이메일 주소를 쿼리한다. (클라이언트에서 요청을 변조하여 다른 사용자의 정보를 수정하는 것을 막는다.)&lt;/li&gt;
&lt;li&gt;또한, JSON에서 String이 되어버린 숫자를 다시 TS의 Number형으로 바꿔줘야한다.&lt;/li&gt;
&lt;li&gt;그냥 Prisma Update에 데이터를 그대로 때려박았다. 이렇게 하더라도 Prisma가 SQLi같은 것은 막아줄 테지만, 그래도 현실에서는 데이터 포맷에 어긋나지 않는지 검증하여야 할 필요가 있을것이다. 하지만 귀찮으니 여기서는 그냥 한다.&lt;/li&gt;
&lt;li&gt;그 후 Prisma update()의 리턴값을 던진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1710661741168&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export async function PUT(req: Request) {
    const session = await getServerSession(authOptions);
    const currentUserEmail = session?.user?.email!;

    const data = await req.json();
    data.age = Number(data.age);

    const user = await prisma.user.update({
        where: {
            email: currentUserEmail,
        },
        data
    });
    const {password:string, ...userWoPwd} = user;
    return NextResponse.json(userWoPwd);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>콤퓨우터/프로그래밍</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/70</guid>
      <comments>https://pscr.tistory.com/70#entry70comment</comments>
      <pubDate>Sun, 17 Mar 2024 16:49:39 +0900</pubDate>
    </item>
    <item>
      <title>Next.js Full Course 필기 (2)</title>
      <link>https://pscr.tistory.com/69</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Fireship.io의 &quot;&lt;a href=&quot;https://fireship.io/courses/nextjs/&quot;&gt;Next.js Full Course&lt;/a&gt;&quot; 강의를 듣고 필기했던 내용입니다.&lt;/p&gt;
&lt;h1&gt;Nav Menu&lt;/h1&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;UI 컴포넌트를 어디에 넣을것인가?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여러 페이지에 공유될 것 같은 컴포넌트는 /components에 넣는다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;내비게이션 바는 어디에서나 보이기는 하지만 실제로는 Root layout에만 들어가는 것이다.&lt;/li&gt;
&lt;li&gt;그러니까 루트 layout.tsx 파일과 함께 루트 디렉토리에 같이 놓기로(Colocation) 하자.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;서버 컴포넌트 or 클라이언트 컴포넌트?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기본적으로 Next.js의 모든 컴포넌트는 서버컴포넌트&lt;/li&gt;
&lt;li&gt;하지만 Sign In 버튼처럼 인터랙티브한 기능이 필요하다면 클라이언트 컴포넌트가 나을 수 있다
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;'use client';&lt;/code&gt;로&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;하지만 SEO를 위해 googlebot이 페이지에 접근했을 때에는, 링크를 따라갈 수 있도록 내비바가 있는 편이 나을 것이다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인터랙티브한 기능이 필요하지 않다면 되도록 서버 컴포넌트로 놔두는 것이 좋다&lt;/li&gt;
&lt;li&gt;하지만 인터랙티브 기능도 포기할 수 없다면?&lt;/li&gt;
&lt;li&gt;해답: NavMenu의 자식 컴포넌트를 클라이언트 컴포넌트로 만든다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Pasted image 20231114221943.png&quot; data-origin-width=&quot;1174&quot; data-origin-height=&quot;596&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAwePx/btsFRrQglq8/AjFKCie3qxt2rDxOpFdzK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAwePx/btsFRrQglq8/AjFKCie3qxt2rDxOpFdzK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAwePx/btsFRrQglq8/AjFKCie3qxt2rDxOpFdzK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAwePx%2FbtsFRrQglq8%2FAjFKCie3qxt2rDxOpFdzK0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1174&quot; height=&quot;596&quot; data-filename=&quot;Pasted image 20231114221943.png&quot; data-origin-width=&quot;1174&quot; data-origin-height=&quot;596&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CSS 모듈의 사용: CSS class를 직접 기입하지 않고 Styles object의 nav class를 통해 접근&lt;/li&gt;
&lt;li&gt;Link 모듈의 사용: &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; 태그를 대체, Client-Side Routing 사용&lt;/li&gt;
&lt;li&gt;Image 모듈의 사용: &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; 태그를 대체&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Style&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Flexbox를 이용해 모든 오브젝트를 중앙정렬, 이후 루트 레이아웃에서 컴포넌트를 추가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;정적 페이지&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;about 페이지는 정적 페이지이다.&lt;br /&gt;&lt;code&gt;/about/page.tsx&lt;/code&gt;를 만들어주자.&lt;/p&gt;
&lt;h1&gt;API Route&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;/api/content&lt;/code&gt;URL에서 서빙되는 가라-GET API를 만들기 위해 &lt;code&gt;/app/api/content/route.ts&lt;/code&gt; 파일을 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대충 배열에 더미 데이터를 생성한다.&lt;/p&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;const posts = [
  {
    title: 'Lorem Ipsum',
    slug: 'lorem-ipsum',
    content:
      'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero.',
  },
];&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 가라-&quot;API&quot;의 목적은 데이터를 JSON으로 뿌려주는것이다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;import { NextResponse } from 'next/server';

const posts = [];
export async function GET(req: Request) {
    return NextResponse.json(posts);
}&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Dynamic Route - SSR&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;/app/blog/[slug]/page.tsx&lt;/code&gt;를 생성하고 TypeScript interface Post를 생성해주자.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 Post는 실제 서버에서 fetching할 데이터의 구조를 하고 있으며 위의 &quot;API&quot;가 뿌려줄 데이터의 구조와 일치한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;code&gt;BlogPostPage()&lt;/code&gt; 컴포넌트를 만들 텐데, 이 컴포넌트는 Params를 Prop으로 가질것이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 강의 내에서는, props와 컴포넌트를 이용할 때 props라는 로컬 인터페이스를 만들 것이다.&lt;/li&gt;
&lt;li&gt;이 디렉토리 구조 특성에 따라 URL 파라미터로 slug를 가지는 Params Object가 된다.&lt;/li&gt;
&lt;li&gt;ts가 싫으면 그냥 &lt;code&gt;{params}: any&lt;/code&gt; 를 하면 되지만, 빅-애플리케이션을 만들 때에 이것은 별로 좋은 습관이 아니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Post[]&lt;/code&gt; 형식인 posts &lt;/p&gt;
&lt;p&gt;&lt;del&gt;변수&lt;/del&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상수를 선언하고 &lt;code&gt;await fetch()&lt;/code&gt; 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;주의할 점은 서버 컴포넌트에서 fetch()할 때에는 FQDN을 써야 한다는 것이다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fetch().then((res) =&amp;gt; res.json())&lt;/code&gt; 으로 fetch된 데이터를 JSON 형식으로 바꾸어 대입할 수 있다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Modern JS Wizardry&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 slug가 매칭되는 포스트를 찾는다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JS find() 메소드를 사용한다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;const post = posts.find((post) =&amp;gt; post.slug === params.slug)!;&lt;/code&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;마지막의 느낌표는 NOT 연산같은 게 아니라 TypeScript의 Non-null Assertion Operator이다.&lt;/li&gt;
&lt;li&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;h1&gt;Static Generation&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DB에 잘 변하지 않는 데이터가 (예를 들어, 블로그 포스트 같은 게) 잔뜩 있다고 해보자. 그러면 이 페이지들을 사전에 생성해두면 CDN 캐싱이 가능해지므로 로딩에 유리할것이다.&lt;br /&gt;하지만 예를 들어 블로그 게시글이 1만개쯤 있다고 한다면 이걸 어떻게 생성해서 캐싱할것인가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해답: 함수 &lt;code&gt;generateStaticParams()&lt;/code&gt;을 export&lt;br /&gt;이 함수의 목적은 미리 렌더링해고 싶은 파라미터가 담긴 오브젝트를 반환하는것이다. (이 경우에는, 포스트의 slug values들이 담겨 있는 object)&lt;br /&gt;이렇게 하여 Next가 동적인 데이터를 찾아 미리 렌더링하도록 할 수 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;revalidate 옵션을 넣는 것을 권장함&lt;/p&gt;
&lt;h1&gt;User Authentication&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Auth.js&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;npm i next-auth&lt;/code&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Catch-All API Route 생성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;/api/auth/[...nextauth]/route.ts&lt;/code&gt;&lt;br /&gt;이러면 네임스페이스가 생성되어 &lt;br /&gt;&lt;code&gt;GET /api/auth/signin&lt;/code&gt;, &lt;code&gt;POST /api/auth/signin/:provider&lt;/code&gt;, &lt;code&gt;GET /api/auth/signout&lt;/code&gt; 등을 자동으로 쓸 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NextAuth와 NextAuthOptions을 임포트해주고 GET, POST로 export&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;import NextAuth from &quot;next-auth&quot;;
import type { NextAuthOptions } from &quot;next-auth&quot;;
import GithubProvider from 'next-auth/providers/github';

export const authOptions: NextAuthOptions = {
    providers: [
        GithubProvider({
            clientId: process.env.GITHUB_ID!,
            clientSecret: process.env.GITHUB_SECRET!
        })
    ]
}

const handler = NextAuth(authOptions);
export {handler as GET, handler as POST};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;next.js에서 ENV Variable을생성하는방법:&lt;br /&gt;&lt;code&gt;/.env&lt;/code&gt; 파일을 생성한다. (실제 간단)&lt;/p&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;GITHUB_ID=
GITHUB_SECRET=
NEXTAUTH_SECRET=&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;NEXTAUTH_SECRET&lt;/code&gt; 토큰을 생성하기 위해,&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;openssl rand -base64 32&lt;/code&gt;&lt;/pre&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;애플리케이션의 Root에 session provider를 추가하여야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 여기에서는 Root에 직접 provider를 넣는 게 아니라 Client Component인 &lt;code&gt;/AuthProider.tsx&lt;/code&gt;을 추가하기로 한다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;'use client';

import { SessionProvider } from &quot;next-auth/react&quot;;
type Props = {
    children: React.ReactNode;
}

export default function AuthProvider({children}: Props) {
    return &amp;lt;SessionProvider&amp;gt;{children}&amp;lt;/SessionProvider&amp;gt;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;this will allow any client side components nested below to this to access the current user&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 이것을 Root layout.tsx에서 기존 jsx 전체를 wrapping하도록 해놓는다.&lt;/p&gt;
&lt;pre class=&quot;dust&quot;&gt;&lt;code&gt;  return (
    &amp;lt;AuthProvider&amp;gt;
      &amp;lt;html lang=&quot;en&quot;&amp;gt;
        &amp;lt;body className={inter.className}&amp;gt;
          &amp;lt;div className='container'&amp;gt;
            &amp;lt;NavMenu/&amp;gt;
            {children}
          &amp;lt;/div&amp;gt;
        &amp;lt;/body&amp;gt;
      &amp;lt;/html&amp;gt;
    &amp;lt;/AuthProvider&amp;gt;
  )&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SessionComponent를 layout에서 직접 사용하지 않는 이유:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;해당 컴포넌트는 client side features를 사용하므로 client라고 명기하지 않으면 오류가 발생함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무튼 이를 통해 우리는 현재 유저 정보를 클라이언트 사이드 전체에서 접근할 수 있도록 되었읍니다&lt;br /&gt;이것을 체크해보기 위해 AuthCheck 컴포넌트를 만들어보겠다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;next-auth에서 useSession 훅을 임포트한다 - 이 훅을 통해 현재 세션과 사용자 상태에 접근할 수 있다&lt;br /&gt;사용자 상태의 예시: authenticated, loading, unauthenticated&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이에 따라 UI 로직을 구현할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 로그인 상태에 따라 children을 보여주거나 아니면 please log in이라는 메시지를 보여주는 컴포넌트의 예시이다&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;'use client';

import { useSession } from &quot;next-auth/react&quot;;

export default function AuthCheck({children}: {children: React.ReactNode}) {
    const {data: session, status} = useSession();
    console.log(session, status);

    if(status === 'authenticated') {
        return &amp;lt;&amp;gt;{children}&amp;lt;/&amp;gt;;
    } else {
        return &amp;lt;&amp;gt;&amp;lt;p&amp;gt;Please log in&amp;lt;/p&amp;gt;&amp;lt;/&amp;gt;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;/components/buttons.tsx&lt;/code&gt;를 만들어 여러 가지의 컴포넌트를 export해보자&lt;br /&gt;&lt;br /&gt;(1컴포넌트당 1파일 원론주의자들도 존재하지만, 한 파일에 여러 컴포넌트를 넣으면 한 라인으로 컴포넌트를 익스포트해줄 수 있고, use client 같은 것도 한 번만 써 주면 된다는 장점이 있을수도 있고 없을수도 있다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그아웃 버튼은 매우 간단하게 만들 수 있다&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;'use client';
import { useSession, signIn, signOut } from &quot;next-auth/react&quot;;
export function SignOutButton() {
    return &amp;lt;button onClick={() =&amp;gt; signOut()}&amp;gt;Sign Out&amp;lt;/button&amp;gt;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그인 버튼은, 사용자가 로그인했을 때는 버튼을 보여주지 않고 사용자의 아바타를 보여주도록 구현해보자.&lt;br /&gt;이를 위해 useSession() 훅을 이용하여 session과 상태를 불러오도록 하자. 만약 status가 loading이라면 loading indicator를, status가 authenticated이면 대시보드로 가는 링크와 함께 사용자의 이미지 URL을 보여주도록해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주의 사항: next/image로 외부 이미지를 불러오려면 &lt;code&gt;next.config.js&lt;/code&gt;에 설정을 추가해주어야한다. 아니면 그냥 good ol' &lt;code&gt;&amp;lt;img src=&quot;&quot; /&amp;gt;&lt;/code&gt;를 쓰는 방법도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다 만들었다면 이 컴포넌트를 NavMenu에 추가해보자.&lt;br /&gt;NavMenu는 서버 컴포넌트이지만 클라이언트 컴포넌트인 SignInButton을 집어넣는것이 가능하다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;추천되는 패턴: 클라이언트 컴포넌트를 넣을 때에는 Component Tree의 잎(leaves)에 넣자&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>콤퓨우터/프로그래밍</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/69</guid>
      <comments>https://pscr.tistory.com/69#entry69comment</comments>
      <pubDate>Sun, 17 Mar 2024 16:43:54 +0900</pubDate>
    </item>
    <item>
      <title>Next.js Full Course 필기 (1)</title>
      <link>https://pscr.tistory.com/68</link>
      <description>&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube-nocookie.com/embed/__mSgDEOyv8?si=fensS6fdhpLEoA-H&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;옛날에 위의 영상을 보고 공부했던 내용을 개인 필기용으로 적어둔 것입니다&lt;/p&gt;
&lt;h1&gt;File System Routing&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;/app/about&lt;/code&gt; example.com/about&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Dynamic Route&lt;br /&gt;&lt;code&gt;/app/[slug]&lt;/code&gt; example.com/{slug}
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Catch-All Route&lt;br /&gt;&lt;code&gt;/app/[...id]&lt;/code&gt; example.com/&amp;hellip;id/&amp;hellip;id/&amp;hellip;id&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;()&lt;br /&gt;&lt;code&gt;/app/(group)&lt;/code&gt; - will be ignored by routing system&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;Reserved Filenames&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;page.tsx&lt;/code&gt; (in TS) or &lt;code&gt;page.js&lt;/code&gt;&lt;br /&gt;실제 UI를 정의하는 기본 React 컴포넌트를 export&lt;/li&gt;
&lt;li&gt;&lt;code&gt;layout.tsx&lt;/code&gt; (in TS) or &lt;code&gt;layout.js&lt;/code&gt;&lt;br /&gt;UI that surrounds the entire application&lt;/li&gt;
&lt;li&gt;&lt;code&gt;route.tsx&lt;/code&gt; (in TS) or &lt;code&gt;route.tsx&lt;/code&gt; - Route Handler
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JSON 등을 return하는 데에 사용할 수 있음, page와 같은 디렉토리에 사용할 수 없음&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;h2 data-ke-size=&quot;size26&quot;&gt;Route Handler&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTTP 메소드들(GET, POST, PUT...)와 같은 이름을 가지는 함수를 1개 이상 export 할 수 있음&lt;/li&gt;
&lt;li&gt;각 함수는 들어오는 request에 대한 정보를 제공하는 request parameter를 가짐&lt;/li&gt;
&lt;li&gt;해당 request를 처리하기 위해 함수에서 response를 return할 수 있음&lt;/li&gt;
&lt;li&gt;예시: POST로 form을 받아서 뭔가 한 뒤 Response Body 'we did it'을 반환&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Route Handler들은 언제나 서버사이드에서 실행되며 기본적으로 Node.js 런타임에서 실행
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;export const runtime&lt;/code&gt;으로 변경 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1710659874977&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export async function POST(request: Request) {
	const data = await request.json();
	//do-something
	return new Response('we did it');
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Request &amp;amp; Response API&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;있으면 삶이 편해지는 기능들을 제공&lt;/li&gt;
&lt;li&gt;예를 들어 Response로 JSON을 보내고 싶다든가 할 때에 유용하다&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1710660577545&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { NextRequest, NextResponse } from 'next/server';
export async function PATCH(request: NextRequest) {
	const url = request.nextUrl;
	return NextResponse.json({message: &quot;asdf&quot;});
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Layouts&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기본적으로 &lt;code&gt;/app/layout.tsx&lt;/code&gt;가 있어서, 전 애플리케이션에 있어서의 outer UI 루트 레이아웃을 정의함&lt;/li&gt;
&lt;li&gt;레이아웃은 페이지와 비슷하지만, 말하자면 자식들에게 상속되는 레이아웃임
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (&amp;lt;html&amp;gt;
      &amp;lt;body&amp;gt;
          {children}
      &amp;lt;/body&amp;gt;
  &amp;lt;/html&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;레이아웃은 Nest될 수 있음&lt;/li&gt;
&lt;li&gt;레이아웃에서도 fetch()로 FETCHING 이 가능&lt;/li&gt;
&lt;li&gt;layout group (괄호가 들어간 폴더)와 결합하여 쓸 수도 있음?&lt;/li&gt;
&lt;li&gt;레이아웃의 UI와 상태는 route 변화되더라도 계속 유지됨
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예를 들어, 레이아웃의 return값에 &lt;code&gt;&amp;lt;NavMenu/&amp;gt;&lt;/code&gt; 가 포함되어 있다면, 해당 레이아웃이 사용되는 모든 페이지에서 &lt;code&gt;&amp;lt;NavMenu/&amp;gt;&lt;/code&gt;는 재렌더링되지않음&lt;/li&gt;
&lt;li&gt;레이아웃 컴포넌트를 매 내비게이션 때마다 reinitalise하려면 &lt;code&gt;template.tsx&lt;/code&gt;를 이용할 수 있음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;which re-mounts on route change&lt;/li&gt;
&lt;/ul&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;h1&gt;Server Component&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Handle Server-Side Rendering for SEO&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;전통적으로, Next.js는 SSR, ISR, SSG와 같은 다양한 종류의 렌더링 기법들을 대응해왔음&lt;/li&gt;
&lt;li&gt;하지만 Next.js 13에서는, 모든 페이지는 Server Component이다
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버에서 렌더링된다 (클라에게 HTML을 쏜다)&lt;/li&gt;
&lt;li&gt;따라서, React의 &lt;code&gt;useEffect()&lt;/code&gt;와 같은 Client-Side 코드들을 그대로 쓸 수 없다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;최상단에 &lt;code&gt;'use client';&lt;/code&gt; 로 선언되는 클라이언트 컴포넌트를 쓰면 클라이언트 사이드 코드들을 쓸 수 있다
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;useEffect() 같은 걸 쓰고 싶으면 이쪽으로 옮겨야&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;자동으로 캐시된다&lt;/li&gt;
&lt;li&gt;보통 캐시 관련 옵션은 Next.js가 알아서 하지만 유저가 행동을 바꿔줄수도 있다
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;export const dynamic = '';&lt;/code&gt; 변수를 선언하여 behaviour를 변경할 수 있다
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;force-dynamic&lt;/code&gt; : SSR wo/ caching (매 호출시마다 서버에서 렌더링)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;force-static&lt;/code&gt;: SSG, 무조건 페이지를 캐시&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;export const revalidate = intval&lt;/code&gt; 을 선언하여 몇초 간 캐시된 내용을 썼다가 시간 경과 후 재렌더링되도록 할 수도 있다 (ISR-equiv)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;SEO 관련: &lt;code&gt;export const metadata = {}&lt;/code&gt; 를 선언하여 HTML &lt;code&gt;&amp;lt;meta&amp;gt;&lt;/code&gt; 태그의 내용을 넣을 수 있다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Data Fetching&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Next.js 13에서 모든 레이아웃과 페이지는 서버 컴포넌트이므로, 서버 사이드 리소스(Environment Variables 등)와 데이터베이스에 접근할 수 있다
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;구버전에서처럼 &lt;code&gt;getServerSideProps()&lt;/code&gt;, &lt;code&gt;getStaticProps()&lt;/code&gt; 써서 컴포넌트에 props를 넘겨주며 삽질할 필요가 없다&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버 사이드 컴포넌트는 &lt;code&gt;async await&lt;/code&gt;를 이용해 내부에서 직접적으로 data fetching을 할 수 있다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;primsa? async 컴포넌트 안에서 &lt;code&gt;await prisma.getMany();&lt;/code&gt; 같이 쓰면 된다.&lt;/li&gt;
&lt;li&gt;firebase? async 컴포넌트 안에서 &lt;code&gt;await firebase.getDoc();&lt;/code&gt; 처럼 쓰면 된다.&lt;/li&gt;
&lt;li&gt;JS fetch()? async 컴포넌트 안에서 &lt;code&gt;await fetch();&lt;/code&gt; 해 주면 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;개발이 편해지는 것은 물론, nested component 구조에서는 fetching에 대해 병렬 처리가 이루어지므로 종전 구조 대비 성능도 향상된다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사실 Next에서 쓰게 되는 &lt;code&gt;fetch()&lt;/code&gt;는 바닐라 JS의 그것이 아니라, React에서 확장해 놓은 &lt;code&gt;fetch()&lt;/code&gt;이다
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이것은 Automatic Request Deduping에 대응한다 (여러 컴포넌트에서 중복 Fetch 요청 시, 한 번 fetch해서 받은 데이터를 중복 요청한 곳에 다시 갖다줌)&lt;/li&gt;
&lt;li&gt;또한 &lt;code&gt;cache&lt;/code&gt; 프로퍼티를 이용해 캐시 동작을 정의해줄 수도 있다
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;static한 데이터라면 &lt;code&gt;{cache: 'force-cache'}&lt;/code&gt;로 캐시 강제&lt;/li&gt;
&lt;li&gt;항상 바뀌는 데이터라면 &lt;code&gt;{cache: 'no-store'}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;그 중간이라면 &lt;code&gt;revalidate&lt;/code&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;Fetching data from PocketBase&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 강의에서 사용한 PocketBase는 built-in REST API를 가지고 있는, 가제트 만능 단일 바이너리 데이터베이스이다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;async function getNotes() {
    const res = await fetch('http://127.0.0.1:8090/api/collections/notes/records?page=1&amp;amp;perPage=30', { cache: 'no-store' });
    //를 하면 notes 컬렉션(테이블)에서 30개 단위로 페이지네이션된 레코드를 던져준다.
    const data = await res.json();

    return data?.items as any[];
    //데이터베이스에 있는 데이터의 Array.
}

export default async function NotesPage() {
    const notes = await getNotes();&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;PocketBase REST API는 이런식으로 return한다:
&lt;pre class=&quot;json&quot;&gt;&lt;code&gt;{
  &quot;page&quot;: 1,
  &quot;perPage&quot;: 30,
  &quot;totalItems&quot;: 1,
  &quot;totalPages&quot;: 1,
  &quot;items&quot;: [
      {
          &quot;collectionId&quot;: &quot;n6nglbveywsg98j&quot;,
          &quot;collectionName&quot;: &quot;notes&quot;,
          &quot;content&quot;: &quot;hello&quot;,
          &quot;created&quot;: &quot;2023-11-10 05:18:34.497Z&quot;,
          &quot;id&quot;: &quot;r4ctus4mcew6cdg&quot;,
          &quot;title&quot;: &quot;hello world&quot;,
          &quot;updated&quot;: &quot;2023-11-10 05:18:34.497Z&quot;
      }
  ]
}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Server-Rendered이지만 이 Route는 자동으로 캐시된다, Route Segment가 Dynamic이 아니기 때문 (Static Page처럼 취급된다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;때문에 fetch에 &lt;code&gt;, { cache: 'no-store' }&lt;/code&gt;를 넣어줘야함&lt;br /&gt;이러면 매 Request마다 아이템을 refetch한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;Dynamic Route: 노트의 제목&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;http://127.0.0.1:3000/notes/r4ctus4mcew6cdg&lt;/code&gt; 와 같은 URL이 노트 상세페이지를 가리키게 하자&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;/app/notes/[id]/page.tsx&lt;/code&gt; 생성&lt;/li&gt;
&lt;li&gt;대충 위와 비슷한 소스를 생성한다&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;async function getNote(noteId: string) {
    const res = await fetch(`http://127.0.0.1:8090/api/collections/notes/records/${noteId}`, {next:{revalidate: 10}});
    const data = await res.json();
    return data;
}

export default async function NotePage({params}: any) {
    const note = await getNote(params.id);
    return(
        &amp;lt;div&amp;gt;
            &amp;lt;h1&amp;gt;notes&amp;lt;/h1&amp;gt;
            &amp;lt;div&amp;gt;
                &amp;lt;h3&amp;gt;{note.title}&amp;lt;/h3&amp;gt;
                &amp;lt;h5&amp;gt;{note.content}&amp;lt;/h5&amp;gt;
                &amp;lt;p&amp;gt;{note.created}&amp;lt;/p&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
    );
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;fetch()에서 &lt;code&gt;cache:'no-store'&lt;/code&gt;를 넣을 필요는 없는데, Dynamic Route이기 때문에 매 Request마다 fetch하는 것이 default이기 때문
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하지만, &lt;code&gt;next: {revalidate: 10}&lt;/code&gt;과 같은 옵션을 넣어, ISR (Incremental Static Regeneration) 을 구현할 수 있음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;캐싱된 페이지가 10초보다 낡았으면 페이지를 재생성&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;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;loading.tsx&lt;/code&gt; 파일 생성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&quot;Interactive&quot;한 CreateNote component&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;'use client';&lt;/code&gt; : 서버에서 렌더링하지 않고 브라우저에서 렌더링&lt;/li&gt;
&lt;li&gt;React의 &lt;code&gt;useState&lt;/code&gt; Hook을 이용해 title, content에 대한 field를 추가&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;잠깐 - 리액트 톺아보기:&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Hook: 리액트 프레임워크의 다양한 기능을 사용하기 위하여 컴포넌트의 TOP LEVEL에서 사용될 수 있는 함수&lt;/li&gt;
&lt;li&gt;useState() 훅을 사용하면 Stateful한 Value를 만들어, 변경될 때마다 여기에 의존하는 컴포넌트들이 자동으로 재렌더링되게할수있다.&lt;/li&gt;
&lt;li&gt;e.g., &lt;code&gt;const [title, setTitle] = useState('');&lt;/code&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기본값을 &lt;code&gt;''&lt;/code&gt;으로, 반환하는 것은 &lt;code&gt;[title, setTitle]&lt;/code&gt;로 구성된 Array&lt;/li&gt;
&lt;li&gt;배열의 첫 번째는 UI에서 사용할 실제 값으로, 두 번째는 함수로 구성한다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;onChange 때마다 setTitle(), setContent()를 각기 불러 state를 update&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;'use client';
import { useState } from &quot;react&quot;;
export default function CreateNote() {
    const [title, setTitle] = useState('');
    const [content, setContent] = useState('');

    const create = async() =&amp;gt; {
        await fetch('http://127.0.0.1:8090/api/collections/notes/records',
            {
                method: 'POST',
                headers: {'Content-Type': 'application/json'},
                body: JSON.stringify({title, content})
            }
        );
    }

    return(
        &amp;lt;form onSubmit={create}&amp;gt;
            &amp;lt;h3&amp;gt;create a new note&amp;lt;/h3&amp;gt;
            &amp;lt;input
                type=&quot;text&quot; placeholder=&quot;title&quot; value={title}
                onChange={(e) =&amp;gt; setTitle(e.target.value)}
            /&amp;gt;
            &amp;lt;textarea
                placeholder=&quot;content&quot; value={content}
                onChange={(e) =&amp;gt; setContent(e.target.value)}
            /&amp;gt;
            &amp;lt;button type=&quot;submit&quot;&amp;gt;create note&amp;lt;/button&amp;gt;
        &amp;lt;/form&amp;gt;
    );
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;create 내장-함수 만들기: 클라의 폼 내용을 PocketBase REST API에 fetch()&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로고침을 하지 않아도&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;import { useRouter } from &quot;next/navigation&quot;;

...
router.refresh();&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;Streaming&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일반적으로 Next 웹페이지 렌더링은 다음의 서순을 따른다&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;서버에서 데이터를 fetch한다&lt;/li&gt;
&lt;li&gt;React 컴포넌트를 서버에서 HTML로 렌더링한다&lt;/li&gt;
&lt;li&gt;서버는 HTML을 브라우저에 보낸다&lt;/li&gt;
&lt;li&gt;브라우저는 HTML/CSS를 렌더링한다 (Non-Interactive Page)&lt;/li&gt;
&lt;li&gt;브라우저에서 JS가 실행되어 Hydrated되며 Interactive한 페이지가 완성된다&lt;/li&gt;
&lt;/ol&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 과정은 순차적으로, 데이터를 많이 fetch해야 하는 큰 웹사이트에서는 많은 데이터를 로드해야할 수 있고 그러면 사이트가 느려진다&lt;/li&gt;
&lt;li&gt;Next.js 13에서는 페이지를 컴포넌트별로 조각조각 쪼개서 페이지를 프로그레시브하게 로드한다
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이것을 페이지 스트리밍이라고 하는데 사실 Next가 알아서 하는 부분이기는 한다&lt;/li&gt;
&lt;li&gt;하지만 &lt;code&gt;loading.tsx&lt;/code&gt;와 같은 파일을 라우트에 추가하여 UX를 향상시킬 수 있다
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이러면 다른 컴포넌트가 로딩되는 사이에 loading.tsx의 내용이 표시된다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;이 알잘딱의 비결은 Suspense이다&lt;/li&gt;
&lt;li&gt;React에서, Suspense는 suspense boundary를 생성하는 특수 컴포넌트이다
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터 fetching같이 async한 동작을 하는 컴포넌트를 감싸주고, async operation이 끝날 때까지 fallback UI를 표시한다&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;h1&gt;Auth.js를 통한 로그인&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기본적으로 jwt (JSON Web token) - 암호화된 토큰을 클라이언트 사이드에 저장
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터베이스에 저장할 수도 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;알아서 로그인 시나리오를 커버해주는 다양한 API Route를 생성&lt;/li&gt;
&lt;li&gt;이후 Application의 root에 &lt;code&gt;&amp;lt;SessionProvider&amp;gt;&lt;/code&gt;를 추가&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;export default function AuthProvider({children}: Props) {
    return &amp;lt;SessionProvider&amp;gt;{children}&amp;lt;/SessionProvider&amp;gt;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 자식들은 &lt;code&gt;useSession()&lt;/code&gt; Hook을 이용해 사용자에 대한 갱신사항을 리얼타임으로 들을수있음&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1710659769615&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;'use client';
import { useSession } from 'next-auth/react';
export default function AuthCheck({children} : {children: React.ReactNode}) {
	const {data: session, status} = useSession();
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;또한 로그인, 로그아웃을 위한 함수도 제공됨. &lt;code&gt;signIn()&lt;/code&gt; 의 경우 버튼에 바운드시켜주면 전용 페이지로 이동&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1710659797764&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export function SignOutButton() {
	return &amp;lt;button onClick{() =&amp;gt; signOut()}&amp;gt;Sign Out!&amp;lt;/button&amp;gt;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버 사이드에서는, &lt;code&gt;getServerSession()&lt;/code&gt; 훅을 이용해서 로그인 상태를 받을 수 있음&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>콤퓨우터/프로그래밍</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/68</guid>
      <comments>https://pscr.tistory.com/68#entry68comment</comments>
      <pubDate>Sun, 17 Mar 2024 16:14:23 +0900</pubDate>
    </item>
    <item>
      <title>macOS에서 OpenGL GLEW, GLUT을 사용한 프로그램의 컴파일</title>
      <link>https://pscr.tistory.com/67</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Apple은 2018년 발표된 macOS 10.14 (Mojave)부터 OpenGL 지원을 Deprecated 처리했습니다. 하지만, 아무리 하위호환의 무덤이라는 Apple이라도 십수 년간 사용되어 왔던 OpenGL의 유산들을 다 버리고 갈 수는 없었기 때문에, OpenGL 지원은 레거시 Intel (AMD64) Mac 플랫폼은 물론 Apple Silicon (M1, M2) Mac에서도 아직까지는 계속되고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 오늘은 Visual Studio로 작성된, cpp 코드 2개짜리 프로그램으로 GLEW, GLUT가 사용된 OpenGL 프로그램을 macOS + Xcode Command Line Tools 환경에서 (Xcode를 사용하지 않고) 컴파일해서 돌려보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;환경: M1 에어, macOS Ventura 13.6&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. GLEW 설치&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GLUT은 Mac OS X의 OpenGL에는 이미 포함되어 있기 때문에, 그냥 GLEW만 설치합니다. Homebrew가 설치된 Mac에서, brew install glew 명령어로 깔아줍니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. GLEW 설치경로 확인&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1697539510843&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;% brew info glew
==&amp;gt; glew: stable 2.2.0 (bottled), HEAD
OpenGL Extension Wrangler Library
https://glew.sourceforge.net/
/opt/homebrew/Cellar/glew/2.2.0_1 (38 files, 3.7MB) *
  Poured from bottle using the formulae.brew.sh API on 2023-10-17 at 14:26:55
From: https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/g/glew.rb
License: BSD-3-Clause
==&amp;gt; Dependencies
Build: cmake ✘
==&amp;gt; Options
--HEAD
	Install HEAD version
==&amp;gt; Analytics
install: 2,019 (30 days), 6,052 (90 days), 16,505 (365 days)
install-on-request: 772 (30 days), 2,586 (90 days), 6,215 (365 days)
build-error: 0 (30 days)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;/opt/homebrew/Cellar/glew/2.2.0_1 에 설치되었네요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. 헤더 바꿔주기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래 코드의 헤더는 다음과 같았는데요,&lt;/p&gt;
&lt;pre id=&quot;code_1697539621445&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &quot;GL/glew.h&quot;
#include &quot;GL/freeglut.h&quot;
#include &quot;GL/freeglut_ext.h&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 다음과 같이 바꿔줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1697539653062&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#ifdef __APPLE__ 
#define GL_SILENCE_DEPRECATION
#include &amp;lt;GL/glew.h&amp;gt;
#include &amp;lt;GLUT/glut.h&amp;gt;

#else
#include &quot;GL/glew.h&quot;
#include &quot;GL/freeglut.h&quot;
#include &quot;GL/freeglut_ext.h&quot;
#endif  // __APPLE__&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;#define GL_SILENCE_DEPRECATION은 선택사항으로 필수사항은 아니지만, 이걸 넣으면 컴파일러가 귀찮게 deprecation 워닝을 띄우지 않게 됩니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. 코드 바꿔주기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;macOS에 내장된 GLUT의 동작이 FreeGLUT과 조금 다르기 때문에 glutInit() 부분을 조금 바꿔줘야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원본 코드:&lt;/p&gt;
&lt;pre id=&quot;code_1697539898732&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;glutInit(&amp;amp;argc, argv);
glutInitWindowSize(512, 512);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
glutInitContextVersion(3, 2);
glutInitContextProfile(GLUT_CORE_PROFILE);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수정한 코드:&lt;/p&gt;
&lt;pre id=&quot;code_1697540097832&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;glutInit(&amp;amp;argc, argv);

#ifdef __APPLE__ 
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH | GLUT_3_2_CORE_PROFILE);	
#else
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
glutInitContextVersion(3, 2);
glutInitContextProfile(GLUT_CORE_PROFILE);
#endif
glutInitWindowSize(512, 512);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러면 OpenGL 3.2 Core Profile... 이 아니라 OpenGL 4.1 Core Profile으로 구동할 수 있게 됩니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;5. Makefile&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cpp 코드 2개짜리의 작은 프로그램이기 때문에 Makefile을 안 만들어도 충분히 컴파일하는데 문제는 없을 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;g++* 명령어:&lt;/b&gt; &lt;br /&gt;(소스 파일이 src/cube.cpp, src/InitShader.cpp 의 2개라고 가정할 때)&lt;/p&gt;
&lt;pre id=&quot;code_1697540605403&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;g++ -Wall -Wextra -std=c++11 -I/opt/homebrew/Cellar/glew/2.2.0_1/include -o cube src/cube.cpp src/InitShader.cpp -L/opt/homebrew/Cellar/glew/2.2.0_1/lib -framework GLUT -framework OpenGL -lGLEW&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;(* 사실은 진짜 g++이 아니라 Xcode의 Apple LLVM/Clang입니다)&lt;br /&gt;(** &quot;/opt/homebrew/Cellar/glew/2.2.0_1&quot; 부분에는 2번에서 찾은 경로를 써주세요)&lt;br /&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 기왕이니 Makefile을 만듭시다.&lt;/p&gt;
&lt;pre id=&quot;code_1697540750156&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;INCLUDES = -I/opt/homebrew/Cellar/glew/2.2.0_1/include
LIBPATHS = -L/opt/homebrew/Cellar/glew/2.2.0_1/lib
CC = g++
CFLAGS = -Wall -Wextra -std=c++11 $(INCLUDES)
LIBS = $(LIBPATHS) -framework GLUT -framework OpenGL -lGLEW

SRCS = src/cube.cpp src/InitShader.cpp

TARGET = cube

all: $(TARGET)

$(TARGET): $(SRCS)
	$(CC) $(CFLAGS) -o $(TARGET) $(SRCS) $(LIBS)

clean:
	rm -f $(TARGET)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 터미널에서 make를 해 주면 바이너리가 만들어집니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1080&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RQX3D/btsyHrpYRxn/tdWypeVtAIFgzgOp2PDr0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RQX3D/btsyHrpYRxn/tdWypeVtAIFgzgOp2PDr0K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RQX3D/btsyHrpYRxn/tdWypeVtAIFgzgOp2PDr0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRQX3D%2FbtsyHrpYRxn%2FtdWypeVtAIFgzgOp2PDr0K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;430&quot; height=&quot;454&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>콤퓨우터/Mac</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/67</guid>
      <comments>https://pscr.tistory.com/67#entry67comment</comments>
      <pubDate>Tue, 17 Oct 2023 21:54:58 +0900</pubDate>
    </item>
    <item>
      <title>카시오 fx-9750GIII / 9860GIII에 CAS 기능을 - khiCAS</title>
      <link>https://pscr.tistory.com/65</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;khiCAS(&amp;chi;CAS)는 프랑스 그르노블-알프스 대학교 푸리에 연구소(Institut Fourier, Universit&amp;eacute; Grenoble-Alpes) 소속 베르나르 파리스(Bernard Parisse) 교수가 개발한 공학용 계산기용 CAS 소프트웨어입니다. khiCAS와 khiCAS의 근간 소프트웨어인 Giac/Xcas는 GNU GPL로 공개되는 무료/자유 소프트웨어입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;khiCAS는 다음 카시오 계산기에 호환됩니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;풀 버전(khicas50): fx-CG50&lt;br /&gt;geometry 커맨드 등의 추가 Xcas 명령어, 3D 렌더링 엔진을 통한 3D/4D 그래프 plot, MicroPython 1.12 내장 등의 추가 기능이 제공됩니다.&lt;/li&gt;
&lt;li&gt;2MB 버전: fx-CG10, fx-CG20 (khicasen.g3a), fx-9750GIII, fx-9860GIII (&lt;a href=&quot;https://www-fourier.univ-grenoble-alpes.fr/~parisse/casio/khicasen.g1a&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;khicasen.g1a&lt;/a&gt;)&lt;br /&gt;해당 기종의 Addin App 용량 제한으로 위의 풀버전에서 일부 기능을 덜어낸 버전입니다. 있을 건 다 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글에서는 9750GIII용 khiCAS에 대해 설명합니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;9750G2/9860G2 기종은 메모리 용량 부족으로 이용이 불가능합니다&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;설치하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;USB Mini-B 케이블을 이용해 계산기와 PC를 연결합니다. (아마존 US 구매 fx-9750GIII 기준 케이블은 동봉되어 있지 않으므로 알아서 구하셔야 합니다)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;DispCap50.png&quot; data-origin-width=&quot;128&quot; data-origin-height=&quot;64&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfeaCe/btr9kiY0eOu/ebLYKtfV2Y5jONDfSRyU30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfeaCe/btr9kiY0eOu/ebLYKtfV2Y5jONDfSRyU30/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfeaCe/btr9kiY0eOu/ebLYKtfV2Y5jONDfSRyU30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfeaCe%2Fbtr9kiY0eOu%2FebLYKtfV2Y5jONDfSRyU30%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;384&quot; height=&quot;192&quot; data-filename=&quot;DispCap50.png&quot; data-origin-width=&quot;128&quot; data-origin-height=&quot;64&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계산기에 Select Connection Mode 메뉴가 출력되면 F1을 누릅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내 컴퓨터(Mac의 경우 Finder)를 보시면 이동식 드라이브 &quot;Untitled&quot;가 생겨 있을 겁니다. 해당 드라이브의 최상위 경로에 위에서 다운로드받은 khicasen.g1a를 넣어줍니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-04-09 오후 9.33.19.png&quot; data-origin-width=&quot;1840&quot; data-origin-height=&quot;872&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpd12v/btscUuN7WUf/R7NJEfTQ2hJn6u9N8D89Fk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpd12v/btscUuN7WUf/R7NJEfTQ2hJn6u9N8D89Fk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpd12v/btscUuN7WUf/R7NJEfTQ2hJn6u9N8D89Fk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbpd12v%2FbtscUuN7WUf%2FR7NJEfTQ2hJn6u9N8D89Fk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1840&quot; height=&quot;872&quot; data-filename=&quot;스크린샷 2023-04-09 오후 9.33.19.png&quot; data-origin-width=&quot;1840&quot; data-origin-height=&quot;872&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;기본적인 조작 방법&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;DispCap1.png&quot; data-origin-width=&quot;128&quot; data-origin-height=&quot;64&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cpU72o/btr8T3VlJGQ/kH6VDxMBpcaxi3XrYnYRv1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cpU72o/btr8T3VlJGQ/kH6VDxMBpcaxi3XrYnYRv1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cpU72o/btr8T3VlJGQ/kH6VDxMBpcaxi3XrYnYRv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcpU72o%2Fbtr8T3VlJGQ%2FkH6VDxMBpcaxi3XrYnYRv1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;384&quot; height=&quot;192&quot; data-filename=&quot;DispCap1.png&quot; data-origin-width=&quot;128&quot; data-origin-height=&quot;64&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메인 메뉴의 마지막에 khiCAS 메뉴가 생성된 것을 볼 수 있습니다. EXE 버튼을 눌러 실행합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;DispCap2.png&quot; data-origin-width=&quot;128&quot; data-origin-height=&quot;64&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eAX1Cz/btr8PYzP26L/lvFG8bodtzyhgTR4xj3Zx0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eAX1Cz/btr8PYzP26L/lvFG8bodtzyhgTR4xj3Zx0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eAX1Cz/btr8PYzP26L/lvFG8bodtzyhgTR4xj3Zx0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeAX1Cz%2Fbtr8PYzP26L%2FlvFG8bodtzyhgTR4xj3Zx0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;384&quot; height=&quot;192&quot; data-filename=&quot;DispCap2.png&quot; data-origin-width=&quot;128&quot; data-origin-height=&quot;64&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;XCas 문법(대입에 :=가 사용됨) 또는 Python 문법(대입에 = 사용됨)을 고를 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;DispCap5.png&quot; data-origin-width=&quot;128&quot; data-origin-height=&quot;64&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3m5VK/btr8OV4qMO4/GYIVOaB4BPtVe25vwwyEbK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3m5VK/btr8OV4qMO4/GYIVOaB4BPtVe25vwwyEbK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3m5VK/btr8OV4qMO4/GYIVOaB4BPtVe25vwwyEbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3m5VK%2Fbtr8OV4qMO4%2FGYIVOaB4BPtVe25vwwyEbK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;384&quot; height=&quot;192&quot; data-filename=&quot;DispCap5.png&quot; data-origin-width=&quot;128&quot; data-origin-height=&quot;64&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;F1~F3까지의 버튼을 누르면 각 카테고리(Algb, Calc, Plot)에 해당되는 주요 함수 바로가기 메뉴가 출력됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dbnWQ4/btr8LKJbU7z/ng9cCdr6aKzhRQtUt6g9YK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dbnWQ4/btr8LKJbU7z/ng9cCdr6aKzhRQtUt6g9YK/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;128&quot; data-origin-height=&quot;64&quot; data-filename=&quot;algb.png&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot; width=&quot;384&quot; height=&quot;192&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dbnWQ4/btr8LKJbU7z/ng9cCdr6aKzhRQtUt6g9YK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdbnWQ4%2Fbtr8LKJbU7z%2Fng9cCdr6aKzhRQtUt6g9YK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;128&quot; height=&quot;64&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXO6y8/btr8PYzQayD/MYNcWiwOH9rP8P6VDwbVAK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXO6y8/btr8PYzQayD/MYNcWiwOH9rP8P6VDwbVAK/img.png&quot; data-origin-width=&quot;128&quot; data-origin-height=&quot;64&quot; data-is-animation=&quot;false&quot; data-filename=&quot;calc.png&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot; width=&quot;384&quot; height=&quot;192&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXO6y8/btr8PYzQayD/MYNcWiwOH9rP8P6VDwbVAK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXO6y8%2Fbtr8PYzQayD%2FMYNcWiwOH9rP8P6VDwbVAK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;128&quot; height=&quot;64&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/w9eEl/btr8NdEd7Zj/jBpV4L4mHFBzvs5UDLXk7K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/w9eEl/btr8NdEd7Zj/jBpV4L4mHFBzvs5UDLXk7K/img.png&quot; data-origin-width=&quot;128&quot; data-origin-height=&quot;64&quot; data-is-animation=&quot;false&quot; data-filename=&quot;plot.png&quot; style=&quot;width: 32.5581%;&quot; data-widthpercent=&quot;33.34&quot; width=&quot;384&quot; height=&quot;192&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/w9eEl/btr8NdEd7Zj/jBpV4L4mHFBzvs5UDLXk7K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fw9eEl%2Fbtr8NdEd7Zj%2FjBpV4L4mHFBzvs5UDLXk7K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;128&quot; height=&quot;64&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&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-filename=&quot;commands.png&quot; data-origin-width=&quot;128&quot; data-origin-height=&quot;64&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2eJnS/btr9eALbgnW/ih9bRB8SB5KAfkTvOGKCP0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2eJnS/btr9eALbgnW/ih9bRB8SB5KAfkTvOGKCP0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2eJnS/btr9eALbgnW/ih9bRB8SB5KAfkTvOGKCP0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2eJnS%2Fbtr9eALbgnW%2Fih9bRB8SB5KAfkTvOGKCP0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;384&quot; height=&quot;192&quot; data-filename=&quot;commands.png&quot; data-origin-width=&quot;128&quot; data-origin-height=&quot;64&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;F4 버튼을 누르면 함수 전체 목록을 볼 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;입력하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ALPHA 버튼을 누르면 대문자 1글자를 누를 수 있습니다. &lt;br /&gt;(배열은 주홍색 라벨을 따라갑니다. 예를 들어 N을 입력하라면 [8] 버튼을 누르면 됩니다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ALPHA가 눌린 상태에서 F5 버튼을 누르면 소문자 1글자를 입력할 수 있습니다. 예를 들어, [ALPHA] - [F5] - [8] - [8] - [8] 을 입력하면 화면에는 n88이 입력됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ALPHA가 눌리지 않은 상태에서 F5 (A&amp;lt;&amp;gt;a) 버튼을 누르면 연속 소문자 입력 상태로 진입합니다. 예를 들어, [F5] - [8] - [8] - [8] 을 입력하면 화면에는 nnn이 입력됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 상태에서 [F5] (A&amp;lt;&amp;gt;a) 버튼을 한 번 더 누르면 연속 대문자 입력 상태로 진입합니다. 예를 들어, [F5] - [F5] - [8] - [8] - [8] 을 입력하면 화면에는 NNN이 입력됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연속 문자 입력 상태에서 나가려면 ALPHA를 누르세요. 예를 들어, [F5] - [8] - [8] - [8] - [ALPHA] - [8] - [8] - [8]을 누르면&amp;nbsp; nnn888이 입력됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;캡처 2.PNG&quot; data-origin-width=&quot;490&quot; data-origin-height=&quot;671&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nMHdf/btr88smqt8g/T2aeSKG770RXR2wgfA4y3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nMHdf/btr88smqt8g/T2aeSKG770RXR2wgfA4y3k/img.png&quot; data-alt=&quot;참고용: 키패드 배열&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nMHdf/btr88smqt8g/T2aeSKG770RXR2wgfA4y3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnMHdf%2Fbtr88smqt8g%2FT2aeSKG770RXR2wgfA4y3k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;490&quot; height=&quot;671&quot; data-filename=&quot;캡처 2.PNG&quot; data-origin-width=&quot;490&quot; data-origin-height=&quot;671&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;참고용: 키패드 배열&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;문자표&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;chartable.png&quot; data-origin-width=&quot;128&quot; data-origin-height=&quot;64&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BH9bZ/btr8UWPhLrV/W1qiNIZuINIiXtFqGqZco1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BH9bZ/btr8UWPhLrV/W1qiNIZuINIiXtFqGqZco1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BH9bZ/btr8UWPhLrV/W1qiNIZuINIiXtFqGqZco1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBH9bZ%2Fbtr8UWPhLrV%2FW1qiNIZuINIiXtFqGqZco1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;384&quot; height=&quot;192&quot; data-filename=&quot;chartable.png&quot; data-origin-width=&quot;128&quot; data-origin-height=&quot;64&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본 키패드에 없는 문자는 [SHIFT] - [INS]를 눌러 문자표를 호출해 입력할 수 있습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;사용 예시&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;부정적분 풀기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;int;x&amp;sup2;dx 를 계산해 봅시다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;DispCap12.png&quot; data-origin-width=&quot;128&quot; data-origin-height=&quot;64&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/boKUi4/btr8OVwy8tN/6pSjka4jZLdK5A0SmQbozk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/boKUi4/btr8OVwy8tN/6pSjka4jZLdK5A0SmQbozk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/boKUi4/btr8OVwy8tN/6pSjka4jZLdK5A0SmQbozk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FboKUi4%2Fbtr8OVwy8tN%2F6pSjka4jZLdK5A0SmQbozk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;384&quot; height=&quot;192&quot; data-filename=&quot;DispCap12.png&quot; data-origin-width=&quot;128&quot; data-origin-height=&quot;64&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[F2](algb, algebra입니다) - [3] 을 눌러 &quot;integrate(&quot;를 입력하고, [X,&amp;theta;,T] 버튼과 x&amp;sup2; 버튼, 괄호 버튼을 눌러 식을 완성한 뒤 [EXE] 버튼을 눌러 계산합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;int(x2).png&quot; data-origin-width=&quot;128&quot; data-origin-height=&quot;64&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bntGOZ/btr8XzsViB9/oBR7CfYrprjcmG9rrLwOek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bntGOZ/btr8XzsViB9/oBR7CfYrprjcmG9rrLwOek/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bntGOZ/btr8XzsViB9/oBR7CfYrprjcmG9rrLwOek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbntGOZ%2Fbtr8XzsViB9%2FoBR7CfYrprjcmG9rrLwOek%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;384&quot; height=&quot;192&quot; data-filename=&quot;int(x2).png&quot; data-origin-width=&quot;128&quot; data-origin-height=&quot;64&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;답이 &quot;2D Editor&quot;에 출력되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 상태에서 [EXE]나 [EXIT] 버튼을 누르면 원래 화면(명령어 입력 창)으로 돌아갑니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;행렬/벡터 입력하기&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;-1_&amp;amp;amp;amp;amp;amp;amp;_2_2_&amp;amp;amp;amp;amp;amp;amp;_2.png&quot; data-origin-width=&quot;246&quot; data-origin-height=&quot;218&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cEf9x1/btr9mip315z/M3Sluyk5WU1W2lN7CM4tkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cEf9x1/btr9mip315z/M3Sluyk5WU1W2lN7CM4tkk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cEf9x1/btr9mip315z/M3Sluyk5WU1W2lN7CM4tkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcEf9x1%2Fbtr9mip315z%2FM3Sluyk5WU1W2lN7CM4tkk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;50&quot; height=&quot;218&quot; data-filename=&quot;-1_&amp;amp;amp;amp;amp;amp;_2_2_&amp;amp;amp;amp;amp;amp;_2.png&quot; data-origin-width=&quot;246&quot; data-origin-height=&quot;218&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;행렬과 벡터를 입력하는 방법을 알아보기 위해, 다음 벡터의 고유값(Eigenvalue)와 고유벡터(Eigenvector)를 구해봅시다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;Xcas/KhiCAS에서는 벡터를 나타내는 자료형이 따로 존재하지 않고, 행렬과 같이 list 자료형으로 처리합니다.&lt;/blockquote&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A=[[-1, 2], [2,2]]를 입력하여 A 변수에 값을 대입합니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;Python 모드가 아니라 Xcas 모드라면 A&lt;b&gt;:=&lt;/b&gt;[[-1, 2], [2,2]] 를 입력해야 합니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dQygKM/btscPaYud78/fxNEfoOJKL7LaNQTV41lEk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dQygKM/btscPaYud78/fxNEfoOJKL7LaNQTV41lEk/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;128&quot; data-origin-height=&quot;64&quot; data-filename=&quot;linalg.png&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dQygKM/btscPaYud78/fxNEfoOJKL7LaNQTV41lEk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdQygKM%2FbtscPaYud78%2FfxNEfoOJKL7LaNQTV41lEk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;128&quot; height=&quot;64&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btK6MA/btscSD5NmU2/itdHA1CkQK3Zh0RO3k04Nk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btK6MA/btscSD5NmU2/itdHA1CkQK3Zh0RO3k04Nk/img.png&quot; data-origin-width=&quot;128&quot; data-origin-height=&quot;64&quot; data-is-animation=&quot;false&quot; data-filename=&quot;eigenvalsa.png&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btK6MA/btscSD5NmU2/itdHA1CkQK3Zh0RO3k04Nk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbtK6MA%2FbtscSD5NmU2%2FitdHA1CkQK3Zh0RO3k04Nk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;128&quot; height=&quot;64&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음 [F4] (cmds) - [3] (Linear algebra) - [6] (eigenvals(A)) 를 눌러 &quot;eigenvals(&quot;를 입력합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;eigenvals(A)라고 입력한 뒤 [EXE] 버튼을 누릅니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;eigenvalues.png&quot; data-origin-width=&quot;128&quot; data-origin-height=&quot;64&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cawblG/btscRLJTasH/A9bezK7XKDzPqH2XlEKyw1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cawblG/btscRLJTasH/A9bezK7XKDzPqH2XlEKyw1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cawblG/btscRLJTasH/A9bezK7XKDzPqH2XlEKyw1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcawblG%2FbtscRLJTasH%2FA9bezK7XKDzPqH2XlEKyw1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;256&quot; height=&quot;128&quot; data-filename=&quot;eigenvalues.png&quot; data-origin-width=&quot;128&quot; data-origin-height=&quot;64&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 벡터의 고유값 3과 -2가 &quot;2D Editor&quot;에 출력되었습니다. 이 화면에서 [EXE] 또는 [EXIT]버튼을 눌러 명령행 인터페이스로 돌아갈 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 고유벡터(Eigenvector)를 구하려면 어떻게 해야 하는지 감이 잡히실 겁니다. [F4] (cmds) - [3] (Linear Algebra) - [7] (eigenvects(A))를 눌러 &quot;eigenvects(&quot;를 입력한 뒤, &quot;eigenvects(A)&quot;까지 입력해 함수를 완성해 주고 EXE 버튼을 누릅니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;DispCap15.png&quot; data-origin-width=&quot;128&quot; data-origin-height=&quot;64&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/O4nzu/btscSEjjMBi/MmKjjKBsJEF4zzAQi0yGkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/O4nzu/btscSEjjMBi/MmKjjKBsJEF4zzAQi0yGkk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/O4nzu/btscSEjjMBi/MmKjjKBsJEF4zzAQi0yGkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FO4nzu%2FbtscSEjjMBi%2FMmKjjKBsJEF4zzAQi0yGkk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;256&quot; height=&quot;128&quot; data-filename=&quot;DispCap15.png&quot; data-origin-width=&quot;128&quot; data-origin-height=&quot;64&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과값이 &quot;2D Editor&quot;에 출력되었습니다. 이 출력결과는 고유벡터가 2&amp;times;2 행렬이라는 것을 의미하는 게 아니라, [-1, 2]와 [2, 2]라는 것입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;식 간략화하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 다음 식을 단순화한다고 해 봅시다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;sin(x)_over_1+_c.png&quot; data-origin-width=&quot;740&quot; data-origin-height=&quot;174&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mUr9v/btscPcPwG7n/Ak1FiCNCknYqdW9WH4FRik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mUr9v/btscPcPwG7n/Ak1FiCNCknYqdW9WH4FRik/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mUr9v/btscPcPwG7n/Ak1FiCNCknYqdW9WH4FRik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmUr9v%2FbtscPcPwG7n%2FAk1FiCNCknYqdW9WH4FRik%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;200&quot; height=&quot;47&quot; data-filename=&quot;sin(x)_over_1+_c.png&quot; data-origin-width=&quot;740&quot; data-origin-height=&quot;174&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 [F1] - [1]을 눌러 simplify(를 입력한 뒤, &quot;simplify(sin(x)/(1+cos(x)) + (1+cos(x))/sin(x))&quot;라고 입력하면, 위의 식이 이렇게 간략화되어 나옵니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;DispCap100.png&quot; data-origin-width=&quot;128&quot; data-origin-height=&quot;64&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cxvnqC/btscQWdO2BE/qP3FAFF6aN0I2feGHzlMcK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cxvnqC/btscQWdO2BE/qP3FAFF6aN0I2feGHzlMcK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cxvnqC/btscQWdO2BE/qP3FAFF6aN0I2feGHzlMcK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcxvnqC%2FbtscQWdO2BE%2FqP3FAFF6aN0I2feGHzlMcK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;384&quot; height=&quot;192&quot; data-filename=&quot;DispCap100.png&quot; data-origin-width=&quot;128&quot; data-origin-height=&quot;64&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혹은, sin(x)/(1+cos(x)) + (1+cos(x))/sin(x) 까지 입력한 뒤, [&amp;rarr;] [&amp;divide;] 버튼을 누르면 (화면상에는 =&amp;gt;/ 로 표시됩니다) 같은 결과를 보실 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;position: absolute;&quot; 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;이렇게 KhiCAS의 기능 일부를 겉핥기로 알아보았습니다. 하지만 KhiCAS는 이외에도 수많은 기능들을 지원합니다. 더 자세히 알아보시려면 &lt;a href=&quot;https://www-fourier.ujf-grenoble.fr/~parisse/casio/khicasioen.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;KhiCAS 매뉴얼 (영문)&lt;/a&gt;을 참조하시기 바랍니다.&lt;/p&gt;</description>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/65</guid>
      <comments>https://pscr.tistory.com/65#entry65comment</comments>
      <pubDate>Fri, 28 Jul 2023 09:27:38 +0900</pubDate>
    </item>
    <item>
      <title>해외 지갑 분실, 신속해외송금제도 사용후기</title>
      <link>https://pscr.tistory.com/66</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;해외 여행 중 지갑이나 카드, 현금을 잃어버리거나 도난당하면 몹시 곤란한 상황이 찾아옵니다. 한국 계좌에 돈이 있어도 지갑에 든 카드가 없으니 돈을 뽑을 수도 없고요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 상황에 대응하기 위해, 대한민국 외교부는 &quot;신속해외송금제도&quot;를 운영하고 있습니다. 이것은 &lt;b&gt;한국 국민이 외교부 계좌로 한국 원화를 입금한 뒤, 해외 각국의 대한민국 외교공관(대사관, 총영사관)에서 외화현금을 수령&lt;/b&gt;할 수 있도록 하는 영사 조력 제도입니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;제19조(경비의&amp;nbsp;부담&amp;nbsp;등)&lt;/b&gt;&amp;nbsp;②&amp;nbsp;재외공관의&amp;nbsp;장은&amp;nbsp;분실,&amp;nbsp;도난&amp;nbsp;등으로&amp;nbsp;긴급한&amp;nbsp;상황에&amp;nbsp;처한&amp;nbsp;재외국민이&amp;nbsp;가족&amp;nbsp;등&amp;nbsp;연고자로부터&amp;nbsp;신속하게&amp;nbsp;도움을&amp;nbsp;받을&amp;nbsp;수&amp;nbsp;있도록&amp;nbsp;연고자로부터의&amp;nbsp;해외송금을&amp;nbsp;지원할&amp;nbsp;수&amp;nbsp;있다.&lt;br /&gt;- &amp;lt;재외국민보호를 위한 영사조력법&amp;gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 주의하실 사항이 몇 가지 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1회에 최대 &lt;b&gt;미화 3천불 (약 380만원)&lt;/b&gt; 또는 이에 상당하는 외화까지만 지급 가능합니다.&lt;/li&gt;
&lt;li&gt;수수료가 부과됩니다. 주오사카대한민국총영사관 기준으로 1회 송금당 수수료가 &lt;b&gt;3만원&lt;/b&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;현금이 많이 필요하지 않은 경우라면 그냥 지나가는 한국인 한명 붙잡아서, (지금 시기에 오사카 총영사관이 위치한 난바 근처의 번화가라면 아무리 늦어도 3분 내로 한국말로 대화하는 사람 볼 수 있음), 한국 계좌로 만원 송금해드릴테니 엔화 현금 천엔만 주실 수 있냐고 물어보는 편이 나을 수도 있습니다.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;1690463043416.jpg&quot; data-origin-width=&quot;3472&quot; data-origin-height=&quot;4624&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/md5J1/btspg1sURyt/CG9yKAbONr4o4cVVUypBt0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/md5J1/btspg1sURyt/CG9yKAbONr4o4cVVUypBt0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/md5J1/btspg1sURyt/CG9yKAbONr4o4cVVUypBt0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fmd5J1%2Fbtspg1sURyt%2FCG9yKAbONr4o4cVVUypBt0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3472&quot; height=&quot;4624&quot; data-filename=&quot;1690463043416.jpg&quot; data-origin-width=&quot;3472&quot; data-origin-height=&quot;4624&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;깔끔한 새 건물로 이사한 오사카 영사관의 전경입니다. 건물 1층에는 엑스레이 탐지기 및 금속탐지기가 설치되어 있으며 이곳을 통과해야 영사관 시설이 있는 윗층으로 올라갈 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;검사를 마친 뒤 2층에 올라가서, 창구 직원분께 &quot;신속해외송금서비스&quot;를 요청하면 됩니다. (이분들은 대부분 한국인 공무원이나 행정직원이므로 그냥 한국어로 말 걸면 됩니다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자주 있는 업무가 아니기 때문인지 담당자분이 다른 업무를 하고 계실 수도 있는데, 이러면 좀 기다려야 할 수도 있습니다. 저는 한 10분 정도 대기의자에 앉아서 기다렸습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;담당자분이 서류를 갖고 오시면 해당 서류에 지급받을 금액(외화)와, 해당 외화 지급의 대가로 외교부에 원화를 보내 줄 사람을 기입합니다. (가족, 친구, 친척 등. 현지에서 스마트폰뱅킹 등으로 원화 송금이 가능한 경우라면, 본인이 해도 상관없습니다).&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;1690463043420.jpg&quot; data-origin-width=&quot;3472&quot; data-origin-height=&quot;4624&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/23m8l/btso8AwXASF/m3T5dZWkNxLe2hfumb3WIK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/23m8l/btso8AwXASF/m3T5dZWkNxLe2hfumb3WIK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/23m8l/btso8AwXASF/m3T5dZWkNxLe2hfumb3WIK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F23m8l%2Fbtso8AwXASF%2Fm3T5dZWkNxLe2hfumb3WIK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3472&quot; height=&quot;4624&quot; data-filename=&quot;1690463043420.jpg&quot; data-origin-width=&quot;3472&quot; data-origin-height=&quot;4624&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;그러면 담당자분이 필요한 서류를 파티스(외교부 내부망 전산)를 통해 영사콜센터에 전송합니다. 전산 처리가 완료될 때까지 약 10분 정도 기다린 뒤, 영사콜센터에 전화를 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영사콜센터 전화번호는 02-3210-0404 이며, 로밍이나 국제전화 앱을 사용하는 경우 +82-2-3210-0404 로 걸면 됩니다. &lt;a href=&quot;https://icc.contact04.mofa.go.kr/m/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;영사콜센터 앱&lt;/a&gt;을 사용하면 공짜로 전화가 가능하다고 하는데, 저는 일단 남는 스카이프 크레딧이 있어서 스카이프를 썼습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;1690463043413.jpg&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;755&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cURKK3/btso6TjuM59/fLO3idNf9M8ZXQOmib02u0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cURKK3/btso6TjuM59/fLO3idNf9M8ZXQOmib02u0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cURKK3/btso6TjuM59/fLO3idNf9M8ZXQOmib02u0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcURKK3%2Fbtso6TjuM59%2FfLO3idNf9M8ZXQOmib02u0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1080&quot; height=&quot;755&quot; data-filename=&quot;1690463043413.jpg&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;755&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무 버튼도 누르지 않고 가만히 기다리면 상담관에게 연결되는데, 상담관께 &amp;lt;〇〇 해외공관을 통해 외화 〇〇엔 신속해외송금을 신청하였으니, 원화를 입금할 계좌를 알려달라&amp;gt; 라고 요청하면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 상담관께서 외교부 명의의 계좌와, 얼마를 송금해야 하는지 알려 주십니다. 저는 &lt;b&gt;1만 5천엔&lt;/b&gt;을 신속해외송금 요청하였는데, 입금해야 할 금액은 &lt;b&gt;18만 2250원&lt;/b&gt;이었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수수료 3만원을 제외해도 100엔당 1015원으로 환율이 굉장히 높게 적용된 것인데, 일단 &lt;b&gt;추후 정산&lt;/b&gt;된다고 합니다. 정산이 언제 될지는 모르겠지만 정산이 되면 이 부분은 업데이트하도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무튼 외교부 계좌(농협은행 기준 계좌번호 1310-01-001001, 예금주: 외교부)로 정해진 금액을 송금하고, 다시 영사콜센터에 송금 완료하였다고 연락을 하면 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;1690463043418.jpg&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1603&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kLVLv/btso7SxUAjt/i3AuWJxhuqtKiToN1QYG2K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kLVLv/btso7SxUAjt/i3AuWJxhuqtKiToN1QYG2K/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kLVLv/btso7SxUAjt/i3AuWJxhuqtKiToN1QYG2K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkLVLv%2Fbtso7SxUAjt%2Fi3AuWJxhuqtKiToN1QYG2K%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1080&quot; height=&quot;1603&quot; data-filename=&quot;1690463043418.jpg&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1603&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 영사콜센터에서 해외공관에 파티스를 통해 입금내역을 전송합니다. 이것도 한 10~20분 정도 걸립니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 전산 통보를 받은 담당자분이 외화 현금을 주십니다. 저 같은 경우에는 담당자분이 SBJ은행 현금카드를 가져오셔서는, 영사관 앞에 있는 세븐일레븐 편의점 ATM에서 현금을 손수 인출해서 전달해 주셨습니다...&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;의 간단한 사용후기였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 지갑을 안 잃어버리는 게 최선이겠지요? 여러분은 저처럼 해외에서 지갑 잃어버리시지 마시길...&lt;/p&gt;
&lt;div class=&quot;notranslate&quot; style=&quot;all: initial;&quot;&gt;&amp;nbsp;&lt;/div&gt;</description>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/66</guid>
      <comments>https://pscr.tistory.com/66#entry66comment</comments>
      <pubDate>Thu, 27 Jul 2023 22:12:06 +0900</pubDate>
    </item>
    <item>
      <title>Linux Foundation 자격증 시험 가격 및 할인 정보 (CKA, CKAD, LFCS 등)</title>
      <link>https://pscr.tistory.com/63</link>
      <description>&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;목차 보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;div class=&quot;book-toc&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;목차&lt;/p&gt;
&lt;ul id=&quot;toc&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Linux Foundation Training &amp;amp; Certification이란?&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;lf.png&quot; data-origin-width=&quot;2560&quot; data-origin-height=&quot;861&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lYblR/btr5RRweGMq/L7k5zkYgclkkdVBp1HdGyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lYblR/btr5RRweGMq/L7k5zkYgclkkdVBp1HdGyK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lYblR/btr5RRweGMq/L7k5zkYgclkkdVBp1HdGyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlYblR%2Fbtr5RRweGMq%2FL7k5zkYgclkkdVBp1HdGyK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;135&quot; data-filename=&quot;lf.png&quot; data-origin-width=&quot;2560&quot; data-origin-height=&quot;861&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리눅스 재단(The Linux Foundation; LF)에서는, 해당 재단에서 관리하는 오픈소스 솔루션과 관련된 자격증을 여럿 제공하고 있습니다. 리눅스와 관련된 자격증인 Linux Foundation Certified System Admin(&lt;b&gt;LFCS&lt;/b&gt;; 리눅스 재단 공인 시스템 관리자), 쿠버네티스와 관련된 자격증인 Certified Kubernetes Administrator(&lt;b&gt;CKA&lt;/b&gt;; 공인 쿠버네티스 관리자) 자격증이 대표적입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리눅스 재단의 자격증 시험은 기본적으로 비대면 방식이고, 시험은 &lt;b&gt;영어&lt;/b&gt;로 치뤄집니다. 단, 일부 자격증 시험은 일본어나 중국어(간체)로도 제공됩니다. 한국어는 지원되지 않습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;LFTraining_Promo_March23_potofgold-1.png&quot; data-origin-width=&quot;1500&quot; data-origin-height=&quot;1512&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o2Nav/btr5PQLp9yT/TsNbhD1Quz7TkGysU8Y7N0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o2Nav/btr5PQLp9yT/TsNbhD1Quz7TkGysU8Y7N0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o2Nav/btr5PQLp9yT/TsNbhD1Quz7TkGysU8Y7N0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo2Nav%2Fbtr5PQLp9yT%2FTsNbhD1Quz7TkGysU8Y7N0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;302&quot; data-filename=&quot;LFTraining_Promo_March23_potofgold-1.png&quot; data-origin-width=&quot;1500&quot; data-origin-height=&quot;1512&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 리눅스 재단에서는 해당 자격증과 관련된 &lt;b&gt;교육 과정&lt;/b&gt;도 제공하고 있는데, 크게 강의(Course), 부트캠프(Bootcamp), 번들(Bundle)의 3종류가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 &lt;b&gt;강의(Course)&lt;/b&gt;를 구매하면 일정 기간(보통 12개월)동안 리눅스 재단 강사의 인터넷 강의를 수강할 수 있습니다. &lt;b&gt;번들(Bundle)&lt;/b&gt;은 각종 강의와 관련된 자격증 시험 응시권을 함께 묶어서 판매하는 것을 말합니다. 또, &lt;b&gt;부트캠프(Bootcamp)&lt;/b&gt;는 인터넷 강의, 온라인 실습 과정과 함께 리눅스 재단 강사와의 화상 채팅, 포럼을 통한 질문이 가능한 종합 묶음 세트로, 자격증 시험 응시권도 함께 따라옵니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리눅스 재단 강의는 기본적으로 &lt;b&gt;영어&lt;/b&gt;로 제공되며, 일부 강의의 경우 일본어, 중국어 서비스가 제공됩니다. 한국어는 지원되지 않습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;자격증 시험 응시료 (할인 미적용 가격)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물가 상승에 따라 LF의 자격증 시험 응시료도 상승 추세를 보이고 있습니다. 현재 리눅스 재단에서 제공하는 각종 시험 응시료의 &lt;b&gt;정가&lt;/b&gt;는 다음과 같습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;CKA, CKAD, CKS, LFCT, LFCS&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공인 쿠버네티스 관리자(Certified Kubernetes Administrator; CKA), 공인 쿠버네티스 애플리케이션 개발자(Certified Kubernetes Application Developer; CKAD), 공인 쿠버네티스 보안 전문가(Certified Kubernetes Security Specialist; CKS), 리눅스 재단 공인 클라우드 기술자(Linux Foundation Certified Cloud Technician; LFCT), 리눅스 재단 공인 시스템 관리자(Linux Foundation Certified System Administrator; LFCS) 의 응시료:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;s&gt;$300 (2014년 8월 ~ 2021년 6월 30일)&lt;/s&gt;&lt;/li&gt;
&lt;li&gt;&lt;s&gt;$375 (2021년 7월 1일 ~ 2022년 7월 30일)&lt;/s&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt; $395 (2022년 8월 ~ 현재)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;KCNA, KCSA, LFCA, RVFA&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿠버네티스 및 클라우드 네이티브 전문가(Kubernetes and Cloud Native Associate; KCNA), 쿠버네티스 및 클라우드 보안 전문가(Kubernetes and Cloud Security Associate; KCSA), 리눅스 재단 공인 IT 전문가(Linux Foundation Certified IT Associate; LFCA), RISC-V Foundational Associate(RVFA) 의 응시료:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;s&gt;$200 (~ 2021년 6월 30일)&lt;/s&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;$250 (2021년 7월 ~ 현재)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;일본어판 시험 (CKA-JP, CKAD-JP, CKS-JP, LFCS-JP)&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;s&gt;$300 (2020년 2월~ ?)&lt;/s&gt;&lt;/li&gt;
&lt;li&gt;&lt;s&gt;$330&lt;/s&gt;&lt;/li&gt;
&lt;li&gt;&lt;s&gt;$410&lt;/s&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;$430, LPI-Japan을 통해 응시하는 경우 ￥55,000 (2023년 현재)&lt;br /&gt;&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;근데 그냥 CKA를 봐도 일본어, 중국어 시험문제를 선택할 수 있기 때문에? 일본어를 시험을 보고 싶다고 해도 굳이 CKA-JP를 선택할 필요는 없을 것 같습니다.&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;h3 data-ke-size=&quot;size23&quot;&gt;할인 이벤트&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리눅스 재단의 자격증 응시료를 보면, 편한 마음으로 응시하기에는 꽤나 비싼 가격이 형성되어 있는 것이 사실입니다. 다행히도, 리눅스 재단에서는 비정기적으로 20~40% 정도 응시료를 할인해 주는 이벤트를 개최하고 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;LFTraining_SeptemberPromo_graphics-02-2.svg&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/phsRO/btr5PRi7lDs/Jg0W6EWZJObdWWhxHWukK1/tfile.svg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/phsRO/btr5PRi7lDs/Jg0W6EWZJObdWWhxHWukK1/tfile.svg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/phsRO/btr5PRi7lDs/Jg0W6EWZJObdWWhxHWukK1/tfile.svg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FphsRO%2Fbtr5PRi7lDs%2FJg0W6EWZJObdWWhxHWukK1%2Ftfile.svg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;300&quot; data-filename=&quot;LFTraining_SeptemberPromo_graphics-02-2.svg&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;할인율은 이벤트마다 달라지지만 보통 30% 전후입니다. 할인 이벤트 자체는 대부분 &lt;b&gt;매월 중순에 시작해서 월말까지 계속&lt;/b&gt;되는 경향을 보이지만, 이벤트마다 할인되는 항목이 다르기 때문에 주의가 필요합니다. 예를 들어 어떤 달에는 특정 시험에 대해서만 할인을 제공하거나, 시험은 할인하지 않고 강의나 부트캠프만 할인하는 경우가 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;cm.png&quot; data-origin-width=&quot;2400&quot; data-origin-height=&quot;1256&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dwq9ys/btr5ORcNTHq/KEMfkFpLKUPx6b0IIndse0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dwq9ys/btr5ORcNTHq/KEMfkFpLKUPx6b0IIndse0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dwq9ys/btr5ORcNTHq/KEMfkFpLKUPx6b0IIndse0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdwq9ys%2Fbtr5ORcNTHq%2FKEMfkFpLKUPx6b0IIndse0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;262&quot; data-filename=&quot;cm.png&quot; data-origin-width=&quot;2400&quot; data-origin-height=&quot;1256&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;일반적으로 할인율이 가장 높은 시기는 블랙 프라이데이~사이버 먼데이 기간이 있는 매년 11월 말~12월 초 사이&lt;/b&gt;로, 보통 해당 기간에는 &lt;b&gt;대략 50% 근처까지 할인이 제공&lt;/b&gt;되며 사은품으로 리눅스 재단 굿즈(턱스 펭귄 인형, 머그컵, 모자, 양말 등)을 보내 주기도 합니다. 또 시스템 관리자의 날(7월)도 할인율이 비교적 높습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 자격증 취득이 급하지 않다면 11월까지 기다려 보는 것도 방법일 것입니다.&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;&lt;b&gt;현재 진행 중인 이벤트&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2024년 5월 세일: 부트캠프・번들 50% 할인 / 시험 40% 할인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://training.linuxfoundation.org/may-2024-promo&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://training.linuxfoundation.org/may-2024-promo&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(코드: MAY24PLUS / MAY24 2024년 5월 14일 ~ 21일 UTC 23:59까지. )&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;&lt;b&gt;기존 이벤트 이력 (만료됨)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 리눅스 재단 영문판 사이트에서는 이벤트 기간이 끝나면 이벤트 페이지를 내려 버리기 때문에, 아래에 걸려 있는 이벤트 페이지 링크는 모두 리눅스 재단의 일본어판 사이트로 연결되어 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2024년 5월 4일 포스의 날 기념 세일: 번들 40% 할인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(코드: FOURTH24 2024년 5월 3일 ~ 6일 UTC 23:59까지. )&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2024년 4월 지구의 날 기념 세일: 일괄 30% 할인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://training.linuxfoundation.org/ja/april-2024/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://training.linuxfoundation.org/ja/april-2024/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(코드: IWD24 2024년 4월 9일 ~ 16일 UTC 23:59까지. )&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2024년 3월 국제 여성의 날 기념 세일: 일괄 30% 할인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://training.linuxfoundation.org/ja/march-iwd-2024-promo/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://training.linuxfoundation.org/ja/march-iwd-2024-promo/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(코드: LUNAR24 2024년 3월 6일 ~ 8일 UTC 23:59까지. )&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2024년 2월 음력설 세일: 일괄 40% 할인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://training.linuxfoundation.org/ja/lunar24/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://training.linuxfoundation.org/ja/lunar24/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(코드: LUNAR24 2024년 2월 6일 ~ 9일 UTC 23:59까지. )&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2024년 1월 신년 세일: 일괄 35% 할인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://training.linuxfoundation.org/jan-2024-two-day-promo/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://training.linuxfoundation.org/jan-2024-two-day-promo/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(코드: AWARDS35 2024년 1월 30일 ~ 31일 UTC 23:59까지. )&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2023년 11월 사이버 먼데이 세일: 부트캠프・번들 65% 할인 / 시험 50% 할인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://training.linuxfoundation.org/cyber-monday-2023/&quot;&gt;https://training.linuxfoundation.org/cyber-monday-2023/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(2023년 11월 27일 ~ 2023년 12월 4일 UTC 23:59까지)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;올해 최대 할인율입니다.&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CKA &lt;s&gt;$395&lt;/s&gt; &amp;rarr; $198&lt;/li&gt;
&lt;li&gt;LFCT &lt;s&gt;$395&lt;/s&gt; &amp;rarr; $198&lt;/li&gt;
&lt;li&gt;LFCS &lt;s&gt;$395&lt;/s&gt; &amp;rarr; $198&lt;/li&gt;
&lt;li&gt;PCA &lt;s&gt;$250&lt;/s&gt; &amp;rarr; $125&lt;/li&gt;
&lt;li&gt;LFCA &lt;s&gt;$250&lt;/s&gt; &amp;rarr; $125&lt;/li&gt;
&lt;li&gt;CKAD &lt;s&gt;$395&lt;/s&gt; &amp;rarr; $198&lt;/li&gt;
&lt;li&gt;CKS &lt;s&gt;$395&lt;/s&gt; &amp;rarr; $198&lt;/li&gt;
&lt;li&gt;KCNA &lt;s&gt;$250&lt;/s&gt; &amp;rarr; $125&lt;/li&gt;
&lt;li&gt;FOCP &lt;s&gt;$300&lt;/s&gt; &amp;rarr; $150&lt;/li&gt;
&lt;li&gt;RVFA &lt;s&gt;$250&lt;/s&gt; &amp;rarr; $125&lt;/li&gt;
&lt;li&gt;CTAD &lt;s&gt;$250&lt;/s&gt; &amp;rarr; $125&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비고: 해당 기간 구매자에게 턱스 펭귄 인형, 리눅스 재단 모자, 양말 증정&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2023년 9월 신학기 세일: 일괄 35% 할인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://training.linuxfoundation.org/september-2023-promo/&quot;&gt;https://training.linuxfoundation.org/september-2023-promo/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(코드: BACKTOSCHOOL35 2023년 9월 12일 ~ 19일 UTC 23:59까지. )&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2023년 7월 시스템 관리자의 날 세일: 부트캠프 $400 / 번들 $200 / 시험 $100 할인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://training.linuxfoundation.org/july-2023/&quot;&gt;https://training.linuxfoundation.org/july-2023/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사은품으로 턱스 양말 또는 리눅스 재단 모자가 제공됩니다.&lt;br /&gt;(코드: JULY23400, JULY23200, JULY23100 2023년 7월 18일 ~ 30일 UTC 23:59까지. )&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2023년 7월 Prime Day 세일: 전 종류 40% 할인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://training.linuxfoundation.org/ja/july-prime-day-2023-promo/&quot;&gt;https://training.linuxfoundation.org/ja/july-prime-day-2023-promo/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;(코드: PRIME23 2023년 7월 11일 ~ 12일 UTC 23:59까지. )&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2023년 6월 세일: 부트캠프・번들 40% / 시험 30% 할인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://training.linuxfoundation.org/ja/june-2023/&quot;&gt;https://training.linuxfoundation.org/ja/june-2023/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;&lt;br /&gt;&lt;/s&gt;(코드: JUNEBBQ40 / JUNEBBQ30 2023년 6월 13일 ~ 20일 UTC 23:59까지. )&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2023년 5월 세일: 부트캠프・번들 50% / 시험 40% 할인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://training.linuxfoundation.org/ja/may-grad-2023/&quot;&gt;https://training.linuxfoundation.org/ja/may-grad-2023/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;&lt;br /&gt;&lt;/s&gt;(코드: MAYGRAD50 / MAYGRAD40 2023년 5월 16일 ~ 23일 UTC 23:59까지. )&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2023년 4월 세일: 전체 30% 할인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://training.linuxfoundation.org/ja/april-2-2023/&quot;&gt;https://training.linuxfoundation.org/ja/april-2-2023/&lt;/a&gt;&lt;br /&gt;&lt;s&gt;&lt;/s&gt;&lt;s&gt;&lt;a href=&quot;https://training.linuxfoundation.org/ja/april-1-2023&quot;&gt;https://training.linuxfoundation.org/ja/april-1-2023&lt;/a&gt;&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;(코드: APRIL23, 2023년 4월 12일 ~ 18일 UTC 23:59까지)&lt;/s&gt;&lt;s&gt;&lt;br /&gt;&lt;/s&gt;(코드: HOMERUN30 2023년 4월 25일 ~ 30일 UTC 23:59까지. 이번 달은 이벤트를 일주일씩 두 번 했습니다)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CKA &lt;s&gt;$395&lt;/s&gt; &amp;rarr; 277&lt;/li&gt;
&lt;li&gt;LFCS &lt;s&gt;$395&lt;/s&gt; &amp;rarr; 277&lt;/li&gt;
&lt;li&gt;LFCA &lt;s&gt;$250&lt;/s&gt; &amp;rarr; 175&lt;/li&gt;
&lt;li&gt;CKAD &lt;s&gt;$395&lt;/s&gt; &amp;rarr; 277&lt;/li&gt;
&lt;li&gt;CKS &lt;s&gt;$395&lt;/s&gt; &amp;rarr; 277&lt;/li&gt;
&lt;li&gt;KCNA &lt;s&gt;$250&lt;/s&gt; &amp;rarr; 175&lt;/li&gt;
&lt;li&gt;CTAD &lt;s&gt;$250&lt;/s&gt; &amp;rarr; 175&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2023년 3월 세일: 부트캠프 40% / 번들 35% / 시험 25% 할인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://training.linuxfoundation.org/ja/march-2023-potgold/&quot;&gt;https://training.linuxfoundation.org/ja/march-2023-potgold/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(코드: MARCHBUN23, 2023년 3월 16일 ~ 2023년 3월 27일까지)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CKA &lt;s&gt;$395&lt;/s&gt; &amp;rarr; $297&lt;/li&gt;
&lt;li&gt;LFCS &lt;s&gt;$395&lt;/s&gt; &amp;rarr; $297&lt;/li&gt;
&lt;li&gt;LFCA &lt;s&gt;$250&lt;/s&gt; &amp;rarr; $188&lt;/li&gt;
&lt;li&gt;CKAD &lt;s&gt;$395&lt;/s&gt; &amp;rarr; $297&lt;/li&gt;
&lt;li&gt;CKS &lt;s&gt;$395&lt;/s&gt; &amp;rarr; $297&lt;/li&gt;
&lt;li&gt;KCNA &lt;s&gt;$250&lt;/s&gt; &amp;rarr; $188&lt;/li&gt;
&lt;li&gt;FOCP &lt;s&gt;$300&lt;/s&gt; &amp;rarr; $225&lt;/li&gt;
&lt;li&gt;CTAD &lt;s&gt;$250&lt;/s&gt; &amp;rarr; $188&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2023년 2월 세일: 부트캠프・번들 50% / 시험 30% 할인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://training.linuxfoundation.org/ja/february-2023/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://training.linuxfoundation.org/ja/february-2023/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(코드: AWARDS23 / AWARDCERT23, 2023년 2월 20일 ~ 2023년 2월 28일 UTC 23:59까지)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CKA &lt;s&gt;$395&lt;/s&gt; &amp;rarr; 277&lt;/li&gt;
&lt;li&gt;LFCS &lt;s&gt;$395&lt;/s&gt; &amp;rarr; 277&lt;/li&gt;
&lt;li&gt;LFCA &lt;s&gt;$250&lt;/s&gt; &amp;rarr; 175&lt;/li&gt;
&lt;li&gt;CKAD &lt;s&gt;$395&lt;/s&gt; &amp;rarr; 277&lt;/li&gt;
&lt;li&gt;CKS &lt;s&gt;$395&lt;/s&gt; &amp;rarr; 277&lt;/li&gt;
&lt;li&gt;KCNA &lt;s&gt;$250&lt;/s&gt; &amp;rarr; 175&lt;/li&gt;
&lt;li&gt;CTAD &lt;s&gt;$250&lt;/s&gt; &amp;rarr; 175&lt;/li&gt;
&lt;li&gt;CKA-JP &lt;s&gt;$430&lt;/s&gt; &amp;rarr; $301&lt;/li&gt;
&lt;li&gt;LFCS-JP &lt;s&gt;$430&lt;/s&gt; &amp;rarr; $301&lt;/li&gt;
&lt;li&gt;LCFA-JP &lt;s&gt;$275&lt;/s&gt; &amp;rarr;$193&lt;/li&gt;
&lt;li&gt;CKAD-JP &lt;s&gt;$430&lt;/s&gt; &amp;rarr; $301&lt;/li&gt;
&lt;li&gt;CKS-JP &lt;s&gt;$430&lt;/s&gt; &amp;rarr; $301&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2023년 1월 신년 세일: 부트캠프・번들・신규 시험 35% 할인 / 시험 25% 할인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://training.linuxfoundation.org/ja/jan2023/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://training.linuxfoundation.org/ja/jan2023/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(코드 NEWYEAR23+ / NEWYEAR23, 2023년 1월 24일 ~ 2023년 1월 31일 UTC 23:59까지)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CKA &lt;del&gt;$395&lt;/del&gt; &amp;rarr; 297&lt;/li&gt;
&lt;li&gt;LFCS &lt;del&gt;$395&lt;/del&gt; &amp;rarr; 297&lt;/li&gt;
&lt;li&gt;LFCA &lt;del&gt;$250&lt;/del&gt; &amp;rarr; 188&lt;/li&gt;
&lt;li&gt;CKAD &lt;del&gt;$395&lt;/del&gt; &amp;rarr; 297&lt;/li&gt;
&lt;li&gt;CKS &lt;del&gt;$395&lt;/del&gt; &amp;rarr; 297&lt;/li&gt;
&lt;li&gt;KCNA &lt;del&gt;$250&lt;/del&gt; &amp;rarr; 188&lt;/li&gt;
&lt;li&gt;FOCP &lt;del&gt;$300&lt;/del&gt; &amp;rarr; 225&lt;/li&gt;
&lt;li&gt;CTAD &lt;del&gt;$250&lt;/del&gt; &amp;rarr; 188&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2022년 11월 사이버 먼데이 세일: 부트캠프・번들 65% 할인 / 시험 50% 할인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://training.linuxfoundation.org/ja/cyber-2022/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://training.linuxfoundation.org/ja/cyber-2022/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(2023년 11월 28일 ~ 2023년 12월 7일 UTC 23:59까지)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CKA &lt;del&gt;$395&lt;/del&gt; &amp;rarr; $198&lt;/li&gt;
&lt;li&gt;LFCT &lt;del&gt;$395&lt;/del&gt; &amp;rarr; $198&lt;/li&gt;
&lt;li&gt;LFCS &lt;del&gt;$395&lt;/del&gt; &amp;rarr; $198&lt;/li&gt;
&lt;li&gt;PCA &lt;del&gt;$250&lt;/del&gt; &amp;rarr; $125&lt;/li&gt;
&lt;li&gt;LFCA &lt;del&gt;$250&lt;/del&gt; &amp;rarr; $125&lt;/li&gt;
&lt;li&gt;CKAD &lt;del&gt;$395&lt;/del&gt; &amp;rarr; $198&lt;/li&gt;
&lt;li&gt;CKS &lt;del&gt;$395&lt;/del&gt; &amp;rarr; $198&lt;/li&gt;
&lt;li&gt;KCNA &lt;del&gt;$250&lt;/del&gt; &amp;rarr; $125&lt;/li&gt;
&lt;li&gt;FOCP &lt;del&gt;$300&lt;/del&gt; &amp;rarr; $150&lt;/li&gt;
&lt;li&gt;RVFA &lt;del&gt;$250&lt;/del&gt; &amp;rarr; $125&lt;/li&gt;
&lt;li&gt;CTAD &lt;del&gt;$250&lt;/del&gt; &amp;rarr; $125&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비고: 해당 기간 구매자에게 턱스 펭귄 인형, 리눅스 재단 모자, 양말 증정&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2022년 10월 할로윈 세일: 부트캠프・번들 40% 할인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://training.linuxfoundation.org/ja/oct-2022-offer/&quot;&gt;https://training.linuxfoundation.org/ja/oct-2022-offer/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(코드 BOO22, 2022년 10월 18일 ~ 2022년 10월 25일 UTC 23:59까지)&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2022년 9월 세일: 부트캠프・번들・각종 강의・시험 35% 할인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://training.linuxfoundation.org/ja/september-2022-promo-b2c/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://training.linuxfoundation.org/ja/september-2022-promo-b2c/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(코드 SEPTEMBER35, 2022년 9월 20일 ~ 2022년 9월 27일 UTC 23:59까지)&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2022년 8월 Back to School BOGO 세일: 시험 구입 시 해당 시험의 강의 무료제공&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://training.linuxfoundation.org/ja/august-2022-promo-b2c/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://training.linuxfoundation.org/ja/august-2022-promo-b2c/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(코드 BACK2SCHOOL, 2022년 8월 16일 ~ 2022년 8월 30일 UTC 23:59까지)&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2022년 7월 시스템 관리자의 날 기념 세일: 부트캠프・번들 $200 할인, 시험 $100 할인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://training.linuxfoundation.org/ja/july-2022-promo/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://training.linuxfoundation.org/ja/july-2022-promo/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(코드: SYSADMINDAY200 / SYSADMINDAY100, 2022년 7월 19일 ~ 2022년 7월 29일 UTC 23:59까지)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비고: 해당 기간 구매자에게 턱스 펭귄 양말 증정&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2022년 6월 세일: 부트캠프・번들 40%, 클라우드 관련 강의・시험 30% 할인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://training.linuxfoundation.org/ja/june-2022-promo/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://training.linuxfoundation.org/ja/june-2022-promo/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(코드: LEVELUP40 / LEVELUP30, 2022년 6월 14일 ~ 2022년 6월 21일 UTC 23:59까지)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CKA &lt;s&gt;$375&lt;/s&gt; &amp;rarr; $263&lt;/li&gt;
&lt;li&gt;CKAD &lt;s&gt;$375&lt;/s&gt; &amp;rarr; $263&lt;/li&gt;
&lt;li&gt;CKS &lt;s&gt;$375&lt;/s&gt; &amp;rarr; $263&lt;/li&gt;
&lt;li&gt;KCNA &lt;s&gt;$250&lt;/s&gt; &amp;rarr; $175&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2022년 5월 세일: 번들 35% 할인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://training.linuxfoundation.org/ja/may-2022-promo/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://training.linuxfoundation.org/ja/may-2022-promo/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(코드 BETTER22, 2022년 5월 10일 ~ 2022년 5월 17일 UTC 23:59까지)&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2022년 4월 세일: 부트캠프・번들 50% 할인, 시험 40% 할인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://training.linuxfoundation.org/ja/april-2022/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://training.linuxfoundation.org/ja/april-2022/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(코드 SPRING22, 2022년 4월 12일 ~ 2022년 4월 19일 UTC 23:59까지)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CKA &lt;s&gt;$375&lt;/s&gt; &amp;rarr; $225&lt;/li&gt;
&lt;li&gt;LFCS &lt;s&gt;$375&lt;/s&gt; &amp;rarr; $225&lt;/li&gt;
&lt;li&gt;LFCA &lt;s&gt;$250&lt;/s&gt; &amp;rarr; $175&lt;/li&gt;
&lt;li&gt;CKAD &lt;s&gt;$375&lt;/s&gt; &amp;rarr; $225&lt;/li&gt;
&lt;li&gt;CKS &lt;s&gt;$375&lt;/s&gt; &amp;rarr; $225&lt;/li&gt;
&lt;li&gt;KCNA &lt;s&gt;$250&lt;/s&gt; &amp;rarr; $150&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2022년 3월 세일: 클라우드 부트캠프 30% 할인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://training.linuxfoundation.org/ja/march-2022-promo-b2c/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://training.linuxfoundation.org/ja/march-2022-promo-b2c/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(코드 CLOUD22, 2022년 3월 15일 ~ 2022년 3월 22일 UTC 23:59까지)&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2022년 2월 세일: LFCA・LFCS 관련 번들 50%, LFCA・LFCS 시험 35% 할인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://training.linuxfoundation.org/ja/february-2022-promo-b2c/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://training.linuxfoundation.org/ja/february-2022-promo-b2c/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(코드 LINUX22 / LFPB22 / EXAM35, 2022년 2월 15일 ~ 2022년 2월 22일 UTC 23:59까지)&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2022년 1월 세일: KNCA 번들 33% 할인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://training.linuxfoundation.org/ja/january-2022-promo-b2c/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://training.linuxfoundation.org/ja/january-2022-promo-b2c/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(코드 KNCA22A, 2022년 1월 26일 ~ 2022년 1월 31일 UTC 23:59까지)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;KCNE 강의 + KNCA 시험 &lt;s&gt;$299&lt;/s&gt; &amp;rarr; $199&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2021년 12월 연말 세일: 모든 강의・시험 35% 할인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://training.linuxfoundation.org/ja/december-2021-promo/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://training.linuxfoundation.org/ja/december-2021-promo/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(코드 GIVELEARNING21, 2021년 12월 15일 ~ 2021년 12월 22일 UTC 23:59까지)&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2021년 11월 사이버 먼데이 세일: 번들・부트캠프 65%, 강의・시험 50% 할인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://training.linuxfoundation.org/ja/cyber-monday-2021/#coursescertifications&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://training.linuxfoundation.org/ja/cyber-monday-2021/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(코드 CYBER21BC / CYBER21PB / CYBER21BUN / CYBER21NEW / CYBER21CC, 2021년 11월 29일 ~ 2021년 12월 8일 UTC 23:59까지)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CKA &lt;s&gt;$375&lt;/s&gt; &amp;rarr; $188&lt;/li&gt;
&lt;li&gt;LFCS &lt;s&gt;$375&lt;/s&gt; &amp;rarr; $188&lt;/li&gt;
&lt;li&gt;LFCA &lt;s&gt;$250&lt;/s&gt; &amp;rarr; $125&lt;/li&gt;
&lt;li&gt;CKAD &lt;s&gt;$375&lt;/s&gt; &amp;rarr; $188&lt;/li&gt;
&lt;li&gt;CKS &lt;s&gt;$375&lt;/s&gt; &amp;rarr; $188&lt;/li&gt;
&lt;li&gt;KCNA &lt;s&gt;$250&lt;/s&gt; &amp;rarr; $125&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비고: 구입 시 리눅스 재단 머그컵, 모자, Tux(턱스; 리눅스 마스코트) 인형 증정&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2021년 9월 세일: 클라우드 엔지니어 부트캠프 $600 할인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://training.linuxfoundation.org/ja/september-2021-promo/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://training.linuxfoundation.org/ja/september-2021-promo/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(코드 BOOTCAMP2021, 2021年9月14日 ~ 2021年9月21日23:59 UTC까지)&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2021년 8월 세일: 시험 구매 시 강의 무료 이벤트&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://training.linuxfoundation.org/ja/august-2021-promo/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://training.linuxfoundation.org/ja/august-2021-promo/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(코드 FREE21, 2021年8月10日 ~ 2021年8月24日23:59 UTC까지)&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2021년 7월 시스템 관리자의 날 세일: 전 품목 $100 할인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://training.linuxfoundation.org/ja/july-2021-promo/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://training.linuxfoundation.org/ja/july-2021-promo/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(코드 SYSADMIN100, 2021年7月20日 ~ 2021年7月30日23:59 UTC까지)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CKA &lt;s&gt;$375&lt;/s&gt; &amp;rarr; $275&lt;/li&gt;
&lt;li&gt;LFCS &lt;s&gt;$375&lt;/s&gt; &amp;rarr; $275&lt;/li&gt;
&lt;li&gt;LFCA &lt;s&gt;$250&lt;/s&gt; &amp;rarr; $150&lt;/li&gt;
&lt;li&gt;CKAD &lt;s&gt;$375&lt;/s&gt; &amp;rarr; $275&lt;/li&gt;
&lt;li&gt;CKS &lt;s&gt;$375&lt;/s&gt; &amp;rarr; $275&lt;/li&gt;
&lt;li&gt;KCNA &lt;s&gt;$250&lt;/s&gt; &amp;rarr; $150&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2021년 6월 여름 세일: 전 품목 25% 할인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://training.linuxfoundation.org/ja/june-2021-promo/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://training.linuxfoundation.org/ja/june-2021-promo/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(코드 SUMMER25, 2021年6月21日 ~ 2021年6月22日23:59 UTC까지)&lt;/p&gt;
&lt;div class=&quot;notranslate&quot; style=&quot;all: initial;&quot;&gt;&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2021년 4월 턱스 30주년 세일: 전 품목 30% 할인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://training.linuxfoundation.org/ja/tux-turns-30-promo/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://training.linuxfoundation.org/ja/tux-turns-30-promo/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(코드 MORETUX30, 2021년 4월 21일 ~ 2021년 4월 22일 태평양시각 23:59까지)&lt;/p&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;div class=&quot;notranslate&quot; style=&quot;all: initial;&quot;&gt;&amp;nbsp;&lt;/div&gt;</description>
      <category>콤퓨우터/Linux</category>
      <author>파란화면</author>
      <guid isPermaLink="true">https://pscr.tistory.com/63</guid>
      <comments>https://pscr.tistory.com/63#entry63comment</comments>
      <pubDate>Fri, 24 Mar 2023 20:24:36 +0900</pubDate>
    </item>
  </channel>
</rss>