<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>dan-te.log</title>
        <link>https://velog.io/</link>
        <description>it's me.</description>
        <lastBuildDate>Fri, 20 Dec 2024 12:09:54 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. dan-te.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/dan-te" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[서평] 기초부터 배우는 최신 스토리지 입문]]></title>
            <link>https://velog.io/@dan-te/%EC%84%9C%ED%8F%89-%EA%B8%B0%EC%B4%88%EB%B6%80%ED%84%B0-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EC%B5%9C%EC%8B%A0-%EC%8A%A4%ED%86%A0%EB%A6%AC%EC%A7%80-%EC%9E%85%EB%AC%B8</link>
            <guid>https://velog.io/@dan-te/%EC%84%9C%ED%8F%89-%EA%B8%B0%EC%B4%88%EB%B6%80%ED%84%B0-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EC%B5%9C%EC%8B%A0-%EC%8A%A4%ED%86%A0%EB%A6%AC%EC%A7%80-%EC%9E%85%EB%AC%B8</guid>
            <pubDate>Fri, 20 Dec 2024 12:09:54 GMT</pubDate>
            <description><![CDATA[<p>서평 이벤트로 당첨되어 읽은 &quot;기초부터 배우는 최신 스토리지 입문&quot; 입니다.</p>
<p>제가 알기론 스토리지 입문 책은 없는 것으로 알고있는데, 이번에 이 책이 번역서로 나와 인기가 많은것으로 보입니다.
클라우드 환경으로 접어들면서 클라우드 밑단의 기술을 접할일이 별로 없다보니 다른 분들에겐 생소한 책이라고 느껴질 수 있을 것 같은데요.
이 책을 통해 스토리지가 무엇이고 왜 필요하고 왜 중요한지 그리고 다른 내용들을 쉽게 접할 수 있을 것 같다는 생각이듭니다.</p>
<p>저는 클라우드 기술을 처음 접하면서 오브젝트 스토리지가 생소했었는데, 이 책을 읽으면서 이런 스토리지 장비들이 있고 이런 스토리지 용어가 있구나 같은 느낌을 받으실 것 같네요.
저도 마찬가지로 스토리지 부분은 약하다보니 생소한 느낌은 있었지만, 되게 쉽게 설명해준 덕에 잘 이해할 수 있었습니다.</p>
<p>이렇게 그림도 작게나마 있어서 이해하는데 있어 조금 도움이 되었습니다.
<img src="https://velog.velcdn.com/images/dan-te/post/2a7a55fd-a633-41a2-9049-e9165ab79d88/image.png" alt=""></p>
<p>가상머신, 오픈스택이나 쿠버네티스에 스토리지 기능을 이용하는 부분도 같이 볼 수 있는데요. 이 책에선 이미 구성된 환경에서 블록 스토리지나 파일 스토리지를 연결하는법에 대해 알려주다 보니 따라하기 어려운 부분도 있을겁니다.</p>
<p>맥북에선 kind(<a href="https://kind.sigs.k8s.io/">https://kind.sigs.k8s.io/</a>) 를 이용해서 작게나마 쿠버네티스를 올려서 테스트 해볼 수 있을 것 같고,
또는 오픈스택을 올릴 수 있는 환경에선 오픈스택을 올려서 테스트 해보셔도 좋을 것 같습니다.
<a href="https://www.server-world.info/en/note?os=Ubuntu_22.04&amp;p=openstack_zed&amp;f=1">https://www.server-world.info/en/note?os=Ubuntu_22.04&amp;p=openstack_zed&amp;f=1</a></p>
<p>스토리지는 매우매우 중요하기 때문에 스토리지 설계, 성능, 모니터링, 특히 백업! 등 중요한 내용을 알기 쉽게 알려주고 있습니다.
근데 당연히 입문이니까 그렇게 깊은 내용까진 안가지만, 이것을 더 파해쳐보고 싶다면 따로 공부를 하시면 좋을 것 같습니다.
저도 이 책에서 새로운 용어나 좀 더 알아보고 싶은 내용이 있어 별도로 찾아보려고 합니다.
&quot;그림으로 공부하느 IT 인프라 구조&quot; 책도 읽으면 뭔가 좋을 것 같은 생각이 들어서 공유드려봅니다.
<a href="https://www.yes24.com/Product/Goods/95800974">https://www.yes24.com/Product/Goods/95800974</a></p>
<p>이렇게 서평을 통해 이 책을 접해볼 수 있게 해준 제이펍 출판사, 네트워크 전문가 따라잡기 매니저님 감사합니다~~</p>
<p>[구매사이트]
<a href="https://www.yes24.com/Product/Goods/139707484">https://www.yes24.com/Product/Goods/139707484</a>
<a href="https://product.kyobobook.co.kr/detail/S000214845345">https://product.kyobobook.co.kr/detail/S000214845345</a>
<a href="https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=352902444&amp;start=slayer">https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=352902444&amp;start=slayer</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[서평] 그림으로 이해하는 인지과학]]></title>
            <link>https://velog.io/@dan-te/%EC%84%9C%ED%8F%89-%EA%B7%B8%EB%A6%BC%EC%9C%BC%EB%A1%9C-%EC%9D%B4%ED%95%B4%ED%95%98%EB%8A%94-%EC%9D%B8%EC%A7%80%EA%B3%BC%ED%95%99</link>
            <guid>https://velog.io/@dan-te/%EC%84%9C%ED%8F%89-%EA%B7%B8%EB%A6%BC%EC%9C%BC%EB%A1%9C-%EC%9D%B4%ED%95%B4%ED%95%98%EB%8A%94-%EC%9D%B8%EC%A7%80%EA%B3%BC%ED%95%99</guid>
            <pubDate>Tue, 16 Jul 2024 14:19:24 GMT</pubDate>
            <description><![CDATA[<p align="center"><img src="https://velog.velcdn.com/images/dan-te/post/1dd81cf9-2673-41f0-9a3d-9162d9485b5f/image.jpg" width="50%" height="100%">


<p>어느 날, 네이버 네트워크 전문가 따라잡기 카페에서 그림으로 이해하는 시리즈 서평단을 모집하는 글이 있었습니다.</p>
<p>  많은 종류의 책이 있어서 고민을 많이 했지만, 요즘 대세가 또 인공지능 이다 보니 이에 해당되는 인지과학을 선택하여 서평단에 당첨이 되었습니다.</p>
<p>  인지라는 단어는 많이 들어봤지 실제로 해당 단어가 어떤 뜻을 내포하고 있는가에 대한 생각은 해본적이 없었던 것 같습니다. 인지란 보통 대상물이 어떤 것인지 해석하여 인식한다는 뜻으로 쓰이지만, 인지과학 연구에서의 인지는 일반적인 의미에만 국한되지 않는다고 합니다.</p>
<p>  이렇듯 해당 책에서는 인지과학에 대한 기본 개념들이 나오며 철학적인 내용과 생소한 단어들이 좀 있다보니 읽고 해석하는데 시간이 좀 걸린 것 같습니다. 하지만, 이 책에서는 아래 그림과 같이 그림 설명도 잘 되어있어 따분한 느낌보다 궁금증을 유발하도록 설명을 하고 있어 계속 몰입하면서 보게 되는 맛도 있습니다.
  <p align="center"><img src="https://velog.velcdn.com/images/dan-te/post/de6bd2c3-7758-48e4-81f1-5f485f343440/image.jpg" width="50%" height="100%"></p>
<p>특히 읽으면서 &quot;얼굴의 기억과 인지&quot; 부분이 흥미로웠는데, 사람 얼굴을 기억 함에 있어 당연한 부분들을 어떠한 과정으로 얼굴을 기억하고 인지하는지에 대해 설명하는데 어떻게 실험하고 어떻게 추론하면서 연구를 했는지 흥미로웠습니다.</p>
<p>이 책은 딥러닝, AI, 뇌과학, 심리학 또는 마케팅 같은 분야에 관심 있거나 종사하는분이라면 한번 가볍게 볼 수 있는 책으로 추천드리고 싶습니다.</p>
<p>또는 우리가 어떻게 생각을 하며, 어떠한 과정으로 말을 하고 대상을 구분 할 수 있는지 이러한 부분에 궁금증을 갖고 계신분이라면 적극적으로 추천드립니다.</p>
<p><strong>[구매 사이트]</strong>
    교보문고:   <a href="https://product.kyobobook.co.kr/detail/S000001834816">https://product.kyobobook.co.kr/detail/S000001834816</a> 
예스24:   <a href="https://www.yes24.com/Product/Goods/127086566">https://www.yes24.com/Product/Goods/127086566</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[12-smoke-test]]></title>
            <link>https://velog.io/@dan-te/12-smoke-test</link>
            <guid>https://velog.io/@dan-te/12-smoke-test</guid>
            <pubDate>Sun, 02 Jun 2024 08:27:54 GMT</pubDate>
            <description><![CDATA[<h3 id="smoke-test">Smoke Test</h3>
<hr>
<p>이번 랩에서는 Kubernetes Cluster가 올바르게 작동하는지 확인하기 위한 일련의 작업을 수행합니다.</p>
<h3 id="data-encryption"><strong>Data Encryption</strong></h3>
<hr>
<p>이 섹션에서는 저장된 secret 데이터를 암호화 하는 기능을 확인합니다.</p>
<p>(<a href="https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/#verifying-that-data-is-encrypted">https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/#verifying-that-data-is-encrypted</a>)</p>
<p>generic secret을 생성합니다.</p>
<pre><code class="language-go">kubectl create secret generic kubernetes-the-hard-way \
  --from-literal=&quot;mykey=mydata&quot;</code></pre>
<p>hexdump를 통해 etcd에 저장 된 <code>kubernetes-the-hard-way</code> secret 데이터를 확인합니다.</p>
<pre><code class="language-go">ssh root@controlplane-1 \
    &#39;etcdctl get /registry/secrets/default/kubernetes-the-hard-way | hexdump -C&#39;</code></pre>
<pre><code class="language-go">00000000  2f 72 65 67 69 73 74 72  79 2f 73 65 63 72 65 74  |/registry/secret|
00000010  73 2f 64 65 66 61 75 6c  74 2f 6b 75 62 65 72 6e  |s/default/kubern|
00000020  65 74 65 73 2d 74 68 65  2d 68 61 72 64 2d 77 61  |etes-the-hard-wa|
00000030  79 0a 6b 38 73 3a 65 6e  63 3a 61 65 73 63 62 63  |y.k8s:enc:aescbc|
00000040  3a 76 31 3a 6b 65 79 31  3a 99 40 67 50 33 67 56  |:v1:key1:.@gP3gV|
00000050  8f c4 46 65 68 49 c3 06  13 46 5f be c1 16 4a 98  |..FehI...F_...J.|
00000060  59 f5 35 fc a9 bd 54 67  19 63 3a e9 48 93 94 ac  |Y.5...Tg.c:.H...|
00000070  a2 5a 30 ca 14 4c 4d 44  6a 66 5f ec 69 91 d8 a9  |.Z0..LMDjf_.i...|
00000080  a2 91 ac 51 0f ba b8 e2  c2 33 b8 61 c3 a7 33 96  |...Q.....3.a..3.|
00000090  ed 28 45 94 7c 03 5c 9e  8e b4 36 45 52 61 f1 c3  |.(E.|.\...6ERa..|
000000a0  72 ce 22 41 12 58 3c 9b  b9 a5 c4 c1 c0 02 da 09  |r.&quot;A.X&lt;.........|
000000b0  cc 7e ff 3d 8a a1 58 d7  40 c9 40 7e dd fd 0a a1  |.~.=..X.@.@~....|
000000c0  65 40 94 b5 35 41 88 3f  e9 64 37 e9 4b c5 9f eb  |e@..5A.?.d7.K...|
000000d0  8b 6b 53 91 6f f2 4c 7b  48 3d 59 90 e6 49 49 20  |.kS.o.L{H=Y..II |
000000e0  e8 6b 0e 06 ac 34 1c 82  d7 fe a2 86 e3 d7 b2 e4  |.k...4..........|
000000f0  dc 5a 7d f7 ca 06 7a a8  b5 c3 ef b5 1a 2d 48 e2  |.Z}...z......-H.|
00000100  bf cf 91 b5 dd 0b 97 0a  7c b6 3b ac 16 ee 06 c6  |........|.;.....|
00000110  cd 4b bf 17 51 26 c5 8d  b6 25 b9 27 c1 73 8c 86  |.K..Q&amp;...%.&#39;.s..|
00000120  23 58 20 2c 71 5a 0d 79  da db cc 0d d4 3c 3e 68  |#X ,qZ.y.....&lt;&gt;h|
00000130  17 f8 0c 7a e7 cb 45 8a  13 4f 0a 58 bf 8b 64 75  |...z..E..O.X..du|
00000140  09 73 9a 07 35 56 33 ba  a6 3d a1 aa a1 ea 2e 71  |.s..5V3..=.....q|
00000150  03 f3 a2 62 ee 3a 0c 41  31 0a                    |...b.:.A1.|
0000015a</code></pre>
<p>etcd 키에는 <code>k8s:enc:aescbc:v1:key1</code> 접두사가 붙어야합니다. <code>aescbc</code> 공급자가 <code>key1</code> 암호화 키로 데이터를 암호하는데 사용되었음을 나타냅니다.</p>
<p>etcd 암호화를 안했을 경우 이와 같이 secret 데이터가 평문으로 저장된 값을 확인할 수 있습니다.</p>
<pre><code class="language-go">00000000  2f 72 65 67 69 73 74 72  79 2f 73 65 63 72 65 74  |/registry/secret|
00000010  73 2f 64 65 66 61 75 6c  74 2f 6b 75 62 65 72 6e  |s/default/kubern|
00000020  65 74 65 73 2d 74 68 65  2d 68 61 72 64 2d 77 61  |etes-the-hard-wa|
00000030  79 0a 6b 38 73 00 0a 0c  0a 02 76 31 12 06 53 65  |y.k8s.....v1..Se|
00000040  63 72 65 74 12 dd 01 0a  c1 01 0a 17 6b 75 62 65  |cret........kube|
00000050  72 6e 65 74 65 73 2d 74  68 65 2d 68 61 72 64 2d  |rnetes-the-hard-|
00000060  77 61 79 12 00 1a 07 64  65 66 61 75 6c 74 22 00  |way....default&quot;.|
00000070  2a 24 35 64 39 30 64 38  36 62 2d 36 61 36 62 2d  |*$5d90d86b-6a6b-|
00000080  34 33 39 66 2d 61 30 34  37 2d 64 61 35 37 34 36  |439f-a047-da5746|
00000090  37 65 62 62 63 62 32 00  38 00 42 08 08 cf ba f0  |7ebbcb2.8.B.....|
000000a0  b2 06 10 00 7a 00 8a 01  62 0a 0e 6b 75 62 65 63  |....z...b..kubec|
000000b0  74 6c 2d 63 72 65 61 74  65 12 06 55 70 64 61 74  |tl-create..Updat|
000000c0  65 1a 02 76 31 22 08 08  cf ba f0 b2 06 10 00 32  |e..v1&quot;.........2|
000000d0  08 46 69 65 6c 64 73 56  31 3a 2e 0a 2c 7b 22 66  |.FieldsV1:..,{&quot;f|
000000e0  3a 64 61 74 61 22 3a 7b  22 2e 22 3a 7b 7d 2c 22  |:data&quot;:{&quot;.&quot;:{},&quot;|
000000f0  66 3a 6d 79 6b 65 79 22  3a 7b 7d 7d 2c 22 66 3a  |f:**mykey**&quot;:{}},&quot;f:|
00000100  74 79 70 65 22 3a 7b 7d  7d 42 00 12 0f 0a 05 6d  |type&quot;:{}}B.....m|
00000110  79 6b 65 79 12 06 6d 79  64 61 74 61 1a 06 4f 70  |ykey..**mydata**..Op|
00000120  61 71 75 65 1a 00 22 00  0a                       |aque..&quot;..|
00000129</code></pre>
<h3 id="deployments">Deployments</h3>
<hr>
<p>이 섹션에서는 Deployment 리소스를 생성하고 관리하는 기능을 확인합니다.</p>
<p>nginx web server의 deployment 리소스를 생성합니다.</p>
<pre><code class="language-go">kubectl create deployment nginx \
  --image=nginx:latest </code></pre>
<p><code>nginx</code> deployment에서 생성된 pod를 확인합니다. </p>
<pre><code class="language-go">kubectl get pods -l app=nginx</code></pre>
<pre><code class="language-go">NAME                     READY   STATUS    RESTARTS   AGE
nginx-7584b6f84c-j7x9m   1/1     Running   0          2m20s</code></pre>
<h3 id="port-forwarding"><strong>Port Forwarding</strong></h3>
<p>이 섹션에서는 port forward를 사용하여 원격으로 어플리케이션에 접근하는 기능을 확인합니다.</p>
<p><a href="https://kubernetes.io/docs/tasks/access-application-cluster/port-forward-access-application-cluster/">Use Port Forwarding to Access Applications in a Cluster</a></p>
<p><code>nginx</code> pod의 이름을 검색합니다.</p>
<pre><code class="language-go">POD_NAME=$(kubectl get pods -l app=nginx \
  -o jsonpath=&quot;{.items[0].metadata.name}&quot;)</code></pre>
<p>local machine의 port 8080을 <code>nginx</code> pod의 port 80으로 forward 합니다.</p>
<pre><code class="language-go">kubectl port-forward $POD_NAME 8080:80</code></pre>
<pre><code class="language-go">Forwarding from 127.0.0.1:8080 -&gt; 80
Forwarding from [::1]:8080 -&gt; 80</code></pre>
<p>새로운 터미널 창에서 HTTP 요청을 보내봅니다.</p>
<pre><code class="language-go"> curl --head http://127.0.0.1:8080</code></pre>
<pre><code class="language-go">HTTP/1.1 200 OK
Server: nginx/1.27.0
Date: Sun, 02 Jun 2024 07:51:09 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 28 May 2024 13:22:30 GMT
Connection: keep-alive
ETag: &quot;6655da96-267&quot;
Accept-Ranges: bytes</code></pre>
<p>이전  터미널로 다시 돌아와서 <code>nginx</code> pod로의 port forward를 중지합니다.</p>
<pre><code class="language-go">Forwarding from 127.0.0.1:8080 -&gt; 80
Forwarding from [::1]:8080 -&gt; 80
Handling connection for 8080
^C</code></pre>
<h3 id="logs"><strong>Logs</strong></h3>
<p>이 섹션에서는 컨테이너 log를 검색하는 기능을 확인합니다.</p>
<p><a href="https://kubernetes.io/docs/concepts/cluster-administration/logging/">https://kubernetes.io/docs/concepts/cluster-administration/logging/</a></p>
<p><code>nginx</code> pod의 로그를 출력합니다.</p>
<pre><code class="language-go">kubectl logs $POD_NAME</code></pre>
<pre><code class="language-go">...
127.0.0.1 - - [02/Jun/2024:07:51:09 +0000] &quot;HEAD / HTTP/1.1&quot; 200 0 &quot;-&quot; &quot;curl/7.81.0&quot; &quot;-&quot;</code></pre>
<h3 id="exec"><strong>EXEC</strong></h3>
<hr>
<p>이 섹션에서는 컨테이너에서 명령을 실행하는 기능을 확인합니다.</p>
<p><a href="https://kubernetes.io/docs/tasks/debug/debug-application/get-shell-running-container/#running-individual-commands-in-a-container">https://kubernetes.io/docs/tasks/debug/debug-application/get-shell-running-container/#running-individual-commands-in-a-container</a></p>
<p><code>nginx</code> 컨테이너에서 <code>nginx -v</code> 명령을 실행하여 nginx 버전을 출력합니다.</p>
<pre><code class="language-go">kubectl exec -ti $POD_NAME -- nginx -v</code></pre>
<pre><code class="language-go">nginx version: nginx/1.27.0</code></pre>
<h3 id="service">Service</h3>
<hr>
<p>이 섹션에서는 Service 리소스를 활용하여 어플리케이션을 노출하는 기능을 확인합니다.</p>
<p><code>NodePort</code> 서비스를 사용해 <code>nginx</code> deployment를 노출합니다.</p>
<pre><code class="language-go">kubectl expose deployment nginx \
  --port 80 --type NodePort</code></pre>
<p><code>LoadBalancer</code> 서비스 타입은 <code>cloud provider intergration</code> 환경에서 Kubernetes Cluster를 구성하지 않았기에 사용할 수 없습니다.</p>
<p>(<a href="https://kubernetes.io/docs/setup/#cloud-provider">https://kubernetes.io/docs/setup/#cloud-provider</a>)</p>
<p><code>nginx</code> 서비스에 할당된 Node Port를 검색합니다.</p>
<pre><code class="language-go">NODE_PORT=$(kubectl get svc nginx \
  --output=jsonpath=&#39;{range .spec.ports[0]}{.nodePort}&#39;)</code></pre>
<p>노드의 IP 주소와 노드포트를 사용해 HTTP 요청을 보내봅니다.</p>
<pre><code class="language-go"> curl -I http://node-2:${NODE_PORT}</code></pre>
<pre><code class="language-go">HTTP/1.1 200 OK
Server: nginx/1.27.0
Date: Sun, 02 Jun 2024 08:11:33 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 28 May 2024 13:22:30 GMT
Connection: keep-alive
ETag: &quot;6655da96-267&quot;
Accept-Ranges: bytes</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[11-pod-network-routes]]></title>
            <link>https://velog.io/@dan-te/11-pod-network-routes</link>
            <guid>https://velog.io/@dan-te/11-pod-network-routes</guid>
            <pubDate>Sun, 02 Jun 2024 08:26:35 GMT</pubDate>
            <description><![CDATA[<h3 id="provisioning-pod-network-routes"><strong>Provisioning Pod Network Routes</strong></h3>
<hr>
<p>노드에 할당 된 pod는 Node의 Pod CIDR 범위에서 IP주소를 받습니다. 현재 Pod는 네트워크 라우팅 설정이 안되어있어 다른 노드에 실행 중인 다른 Pod와 통신을 할 수 없습니다.</p>
<p>이번 랩에서는 각 worker node에 대해 노드의 POD CIDR 범위를 노드의 내부 IP 주소에 매핑하는 경로를 생성하는 작업을 진행합니다.</p>
<p><a href="https://kubernetes.io/docs/concepts/cluster-administration/networking/#how-to-achieve-this">https://kubernetes.io/docs/concepts/cluster-administration/networking/#how-to-achieve-this</a></p>
<ul>
<li>Kubernetes networking model을 다른 방법으로 구현한 내용입니다.</li>
</ul>
<h3 id="the-routing-table">The Routing Table</h3>
<hr>
<p>이번 섹션에서는 <code>kubernetes-the-hard-way</code> VPC 네트워크에서 route를 생성하는데 필요한 정보를 수집합니다.</p>
<p>각 서버들의 내부 IP 주소와 Pod CIDR 범위를 추출합니다.</p>
<pre><code class="language-go">{
  CONTROLPLANE_1_IP=$(grep controlplane-1 /k8s-hardway/machines.txt | cut -d &quot; &quot; -f 1)
  NODE_1_IP=$(grep node-1 /k8s-hardway/machines.txt | cut -d &quot; &quot; -f 1)
  NODE_1_SUBNET=$(grep node-1 /k8s-hardway/machines.txt | cut -d &quot; &quot; -f 4)
  NODE_2_IP=$(grep node-2 /k8s-hardway/machines.txt | cut -d &quot; &quot; -f 1)
  NODE_2_SUBNET=$(grep node-2 /k8s-hardway/machines.txt | cut -d &quot; &quot; -f 4)
}</code></pre>
<pre><code class="language-go">ssh root@controlplane-1 &lt;&lt;EOF
  ip route add ${NODE_1_SUBNET} via ${NODE_1_IP}
  ip route add ${NODE_2_SUBNET} via ${NODE_2_IP}
EOF</code></pre>
<pre><code class="language-go">ssh root@node-1 &lt;&lt;EOF
  ip route add ${NODE_2_SUBNET} via ${NODE_2_IP}
EOF</code></pre>
<pre><code class="language-go">ssh root@node-2 &lt;&lt;EOF
  ip route add ${NODE_1_SUBNET} via ${NODE_1_IP}
EOF</code></pre>
<h3 id="verification"><strong>Verification</strong></h3>
<hr>
<pre><code class="language-go">ssh root@controlplane-1 ip route</code></pre>
<pre><code class="language-go">default via 10.0.32.1 dev enp3s0
192.168.10.0/24 via 10.0.34.93 dev enp3s0
192.168.11.0/24 via 10.0.32.237 dev enp3s0</code></pre>
<pre><code class="language-go">ssh root@node-1 ip route</code></pre>
<pre><code class="language-go">default via 10.0.32.1 dev enp3s0
192.168.11.0/24 via 10.0.32.237 dev enp3s0</code></pre>
<pre><code class="language-go">ssh root@node-2 ip route</code></pre>
<pre><code class="language-go">default via 10.0.32.1 dev enp3s0
192.168.10.0/24 via 10.0.34.93 dev enp3s0</code></pre>
<p>Next: <a href="https://velog.io/@dan-te/12-smoke-test">Smoke Test</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[10-configuring-kubectl]]></title>
            <link>https://velog.io/@dan-te/10-configuring-kubectl</link>
            <guid>https://velog.io/@dan-te/10-configuring-kubectl</guid>
            <pubDate>Sun, 02 Jun 2024 08:26:05 GMT</pubDate>
            <description><![CDATA[<h3 id="configuring-kubectl-for-remote-access"><strong>Configuring kubectl for Remote Access</strong></h3>
<hr>
<p>이번 랩에서는 <code>admin</code> 자격 증명 기반으로 <code>kubectl</code> 명령어에 대한 kubeconfig 파일을 생성합니다.</p>
<p>해당 작업은 <code>jumpbox</code>  서버에서 수행합니다.</p>
<h3 id="the-admin-kubernetes-configuration-file"><strong>The Admin Kubernetes Configuration File</strong></h3>
<hr>
<p>각 kubeconfig는 연결할 Kubernetes API Server가 필요합니다.</p>
<p>이전 랩에서 작업한 <code>/etc/hosts</code> DNS 엔트리 항목을 기반으로 <code>controlplane-1.kubernetes.local</code> 과 통신이 되어야 합니다.</p>
<pre><code class="language-go">curl -k --cacert ca.crt \
  https://controlplane-1.kubernetes.local:6443/version</code></pre>
<pre><code class="language-go">{
  &quot;major&quot;: &quot;1&quot;,
  &quot;minor&quot;: &quot;30&quot;,
  &quot;gitVersion&quot;: &quot;v1.30.1&quot;,
  &quot;gitCommit&quot;: &quot;6911225c3f747e1cd9d109c305436d08b668f086&quot;,
  &quot;gitTreeState&quot;: &quot;clean&quot;,
  &quot;buildDate&quot;: &quot;2024-05-14T10:42:02Z&quot;,
  &quot;goVersion&quot;: &quot;go1.22.2&quot;,
  &quot;compiler&quot;: &quot;gc&quot;,
  &quot;platform&quot;: &quot;linux/amd64&quot;
}</code></pre>
<p><code>admin</code> 으로 인증하는데 필요한 kubeconfig 파일을  생성합니다.</p>
<pre><code class="language-go">{
  kubectl config set-cluster kubernetes-the-hard-way \
    --certificate-authority=/k8s-hardway/tls/ca.crt \
    --embed-certs=true \
    --server=https://controlplane-1.kubernetes.local:6443

  kubectl config set-credentials admin \
    --client-certificate=/k8s-hardway/tls/admin.crt \
    --client-key=/k8s-hardway/tls/admin.key

  kubectl config set-context kubernetes-the-hard-way \
    --cluster=kubernetes-the-hard-way \
    --user=admin

  kubectl config use-context kubernetes-the-hard-way
}</code></pre>
<p>위 명령어를 실행하면, <code>kubectl</code> 명령줄 도구에서 사용하는 기본 위치인 <code>~/.kube/config</code> 에 kubeconfig 파일이 생성 됩니다.  해당 작업을 하면 다른 설정을 안해도 <code>kubectl</code>명령을 실행할 수 있습니다.</p>
<h3 id="verification">Verification</h3>
<hr>
<p>Kubernetes Cluster 버전을 확인합니다.</p>
<pre><code class="language-go">kubectl version</code></pre>
<pre><code class="language-go">Client Version: v1.30.1
Kustomize Version: v5.0.4-0.20230601165947-6ce0bf390ce3
Server Version: v1.30.1</code></pre>
<p>Kubernetes Cluster에 있는 노드들을 확인합니다.</p>
<pre><code class="language-go">kubectl get nodes</code></pre>
<pre><code class="language-go">NAME     STATUS   ROLES    AGE   VERSION
node-1   Ready    &lt;none&gt;   12m   v1.30.1
node-2   Ready    &lt;none&gt;   10m   v1.30.1</code></pre>
<p>Next: <a href="https://velog.io/@dan-te/11-pod-network-routes">Provisioning Pod Network Routes</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[09-bootstrapping-kubernetes-workers]]></title>
            <link>https://velog.io/@dan-te/09-bootstrapping-kubernetes-workers</link>
            <guid>https://velog.io/@dan-te/09-bootstrapping-kubernetes-workers</guid>
            <pubDate>Sun, 02 Jun 2024 08:25:38 GMT</pubDate>
            <description><![CDATA[<h3 id="bootstrapping-the-kubernetes-worker-nodes"><strong>Bootstrapping the Kubernetes Worker Nodes</strong></h3>
<hr>
<p>이번 실습에서는 2개의 Worker node를 bootstrap 하는 과정입니다. runc, container networking plugin, containerd, kubelet, kube-proxy 컴포넌트들을 설치합니다.</p>
<h3 id="prerequisites"><strong>Prerequisites</strong></h3>
<hr>
<p>각 worker 서버에 Kubernetes 바이너리 및 system unit 파일들을 옮기기 전에 일부 파일들을 <code>jumpbox</code> 에서 생성합니다.</p>
<pre><code class="language-go">cat &lt;&lt;EOF &gt; /k8s-hardway/configs/10-bridge.conf
{
  &quot;cniVersion&quot;: &quot;1.0.0&quot;,
  &quot;name&quot;: &quot;bridge&quot;,
  &quot;type&quot;: &quot;bridge&quot;,
  &quot;bridge&quot;: &quot;cni0&quot;,
  &quot;isGateway&quot;: true,
  &quot;ipMasq&quot;: true,
  &quot;ipam&quot;: {
    &quot;type&quot;: &quot;host-local&quot;,
    &quot;ranges&quot;: [
      [{&quot;subnet&quot;: &quot;SUBNET&quot;}]
    ],
    &quot;routes&quot;: [{&quot;dst&quot;: &quot;0.0.0.0/0&quot;}]
  }
}
EOF</code></pre>
<pre><code class="language-go">cat &lt;&lt;EOF &gt; /k8s-hardway/configs/99-loopback.conf
{
  &quot;cniVersion&quot;: &quot;1.1.0&quot;,
  &quot;name&quot;: &quot;lo&quot;,
  &quot;type&quot;: &quot;loopback&quot;
}
EOF</code></pre>
<pre><code class="language-go">
cat &lt;&lt;EOF &gt; /k8s-hardway/configs/containerd-config.toml
version = 2

[plugins.&quot;io.containerd.grpc.v1.cri&quot;]
  [plugins.&quot;io.containerd.grpc.v1.cri&quot;.containerd]
    snapshotter = &quot;overlayfs&quot;
    default_runtime_name = &quot;runc&quot;
  [plugins.&quot;io.containerd.grpc.v1.cri&quot;.containerd.runtimes.runc]
    runtime_type = &quot;io.containerd.runc.v2&quot;
  [plugins.&quot;io.containerd.grpc.v1.cri&quot;.containerd.runtimes.runc.options]
    SystemdCgroup = true
[plugins.&quot;io.containerd.grpc.v1.cri&quot;.cni]
  bin_dir = &quot;/opt/cni/bin&quot;
  conf_dir = &quot;/etc/cni/net.d&quot;
EOF</code></pre>
<pre><code class="language-go">cat &lt;&lt;EOF &gt; /k8s-hardway/configs/kube-proxy-config.yaml
kind: KubeProxyConfiguration
apiVersion: kubeproxy.config.k8s.io/v1alpha1
clientConnection:
  kubeconfig: &quot;/var/lib/kube-proxy/kubeconfig&quot;
mode: &quot;iptables&quot;
clusterCIDR: &quot;192.168.0.0/16&quot;
EOF</code></pre>
<p><code>clusterCIDR</code> 값은 POD 아이피 대역으로 설정해줍니다. <code>kube-controller-manager.service</code> 파일의 <code>cluster-cidr</code> 값과 동일합니다.</p>
<pre><code class="language-go">cat &lt;&lt;EOF &gt; /k8s-hardway/configs/kubelet-config.yaml
kind: KubeletConfiguration
apiVersion: kubelet.config.k8s.io/v1beta1
authentication:
  anonymous:
    enabled: false
  webhook:
    enabled: true
  x509:
    clientCAFile: &quot;/var/lib/kubelet/ca.crt&quot;
authorization:
  mode: Webhook
clusterDomain: &quot;cluster.local&quot;
clusterDNS:
  - &quot;172.16.0.10&quot;
cgroupDriver: systemd
containerRuntimeEndpoint: &quot;unix:///var/run/containerd/containerd.sock&quot;
podCIDR: &quot;SUBNET&quot;
resolvConf: &quot;/etc/resolv.conf&quot;
runtimeRequestTimeout: &quot;15m&quot;
tlsCertFile: &quot;/var/lib/kubelet/kubelet.crt&quot;
tlsPrivateKeyFile: &quot;/var/lib/kubelet/kubelet.key&quot;
EOF</code></pre>
<p><code>clusterDNS</code> 값은 <strong><code>kube-apiserver.service</code> 파일의</strong> <code>service-cluster-ip-range</code> 아이피 대역에서 끝자리를 10으로 설정해줍니다.</p>
<pre><code class="language-go">cat &lt;&lt;EOF &gt; /k8s-hardway/units/containerd.service
[Unit]
Description=containerd container runtime
Documentation=https://containerd.io
After=network.target

[Service]
ExecStartPre=/sbin/modprobe overlay
ExecStart=/bin/containerd
Restart=always
RestartSec=5
Delegate=yes
KillMode=process
OOMScoreAdjust=-999
LimitNOFILE=1048576
LimitNPROC=infinity
LimitCORE=infinity

[Install]
WantedBy=multi-user.target
EOF</code></pre>
<pre><code class="language-go">cat &lt;&lt;EOF &gt; /k8s-hardway/units/kube-proxy.service
Unit]
Description=Kubernetes Kube Proxy
Documentation=https://github.com/kubernetes/kubernetes

[Service]
ExecStart=/usr/local/bin/kube-proxy \
  --config=/var/lib/kube-proxy/kube-proxy-config.yaml
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF</code></pre>
<pre><code class="language-go">cat &lt;&lt;EOF &gt; /k8s-hardway/units/kubelet.service
[Unit]
Description=Kubernetes Kubelet
Documentation=https://github.com/kubernetes/kubernetes
After=containerd.service
Requires=containerd.service

[Service]
ExecStart=/usr/local/bin/kubelet \
  --config=/var/lib/kubelet/kubelet-config.yaml \
  --kubeconfig=/var/lib/kubelet/kubeconfig \
  --register-node=true \
  --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF</code></pre>
<p>위 파일들을 다 생성했으면, 각 서버로 복사합니다.</p>
<pre><code class="language-go">for host in node-1 node-2; do
  SUBNET=$(grep $host /k8s-hardway/machines.txt | cut -d &quot; &quot; -f 4)
  sed &quot;s|SUBNET|$SUBNET|g&quot; \
    /k8s-hardway/configs/10-bridge.conf &gt; 10-bridge.conf 

  sed &quot;s|SUBNET|$SUBNET|g&quot; \
    /k8s-hardway/configs/kubelet-config.yaml &gt; kubelet-config.yaml

  scp 10-bridge.conf kubelet-config.yaml \
  root@$host:~/
done
</code></pre>
<pre><code class="language-go">for host in node-1 node-2; do
  scp \
     /k8s-hardway/downloads/runc.amd64 \
     /k8s-hardway/downloads/crictl-v1.30.0-linux-amd64.tar.gz \
     /k8s-hardway/downloads/cni-plugins-linux-amd64-v1.5.0.tgz \
     /k8s-hardway/downloads/containerd-1.7.14-linux-amd64.tar.gz \
     /k8s-hardway/downloads/kubectl \
     /k8s-hardway/downloads/kubelet \
     /k8s-hardway/downloads/kube-proxy \
     /k8s-hardway/configs/99-loopback.conf \
     /k8s-hardway/configs/containerd-config.toml \
     /k8s-hardway/configs/kubelet-config.yaml \
     /k8s-hardway/configs/kube-proxy-config.yaml \
     /k8s-hardway/units/containerd.service \
     /k8s-hardway/units/kubelet.service \
     /k8s-hardway/units/kube-proxy.service \
    root@$host:~/
done</code></pre>
<p>이 실습은 각 worker node(node-1, node-2)에서 작업해야 합니다. ssh 명령어를 사용해 worker node로 접근합니다.</p>
<pre><code class="language-go">ssh root@node-1</code></pre>
<h3 id="provisioning-a-kubernetes-worker-node"><strong>Provisioning a Kubernetes Worker Node</strong></h3>
<hr>
<p>OS 의존성 패키지들을 설치합니다.</p>
<pre><code class="language-go">{
  apt-get update
  apt-get -y install socat conntrack ipset
}</code></pre>
<p>socat 바이너리는 <code>kubectl port-forward</code> 명령어를 지원합니다.</p>
<p><strong>Disable Swap</strong></p>
<hr>
<p>기본적으로 kubelet 실행 시 swap이 활성화 되어있다면, 동작하지 않습니다. Kubernetes가 적절한 리소스 할당과 서비스 품질을 제공할 수 있도록 swap을 비활성화 하는게 좋습니다.</p>
<ul>
<li><a href="https://kubernetes.io/blog/2023/08/24/swap-linux-beta/">https://kubernetes.io/blog/2023/08/24/swap-linux-beta/</a> kubernetes 1.28 에 swap을 지원합니다.</li>
<li><a href="https://kubernetes.io/docs/concepts/architecture/nodes/#swap-memory">https://kubernetes.io/docs/concepts/architecture/nodes/#swap-memory</a></li>
<li>swap이 활성화 된 상태로 kubernetes 설치할 경우 kubelet 설정파일에서 <code>failSwapOn</code>, <code>swapBehavior</code> 설정을 하셔야합니다.</li>
</ul>
<p>swapon 명령어로 확인이 가능하며, 결과가 아무것도 없다면, swap은 현재 비활성화 상태입니다. </p>
<pre><code class="language-go">swapon --show</code></pre>
<p>swap이 활성화 되어 있다면 다음과 같이 진행하여 비활성화를 진행합니다.</p>
<pre><code class="language-go">swapoff -a</code></pre>
<p>하지만, 해당 명령어는 임시 조치이며, 완전히 비활성화 하려면 swap 관련 설정 파일(/etc/fstab, systemd.swap)을 통해 비활성화를 진행해야 합니다. 해당 설정은 시스템마다 다르기에 본 글에서는 다루지 않겠습니다.</p>
<p>디렉터리을 생성합니다.</p>
<pre><code class="language-go">mkdir -p \
  /etc/cni/net.d \
  /opt/cni/bin \
  /var/lib/kubelet \
  /var/lib/kube-proxy \
  /var/lib/kubernetes \
  /var/run/kubernetes</code></pre>
<p>관련 바이너리들을 설치합니다.</p>
<pre><code class="language-go">{
  mkdir -p containerd
  tar -xvf crictl-v1.30.0-linux-amd64.tar.gz
  tar -xvf containerd-1.7.14-linux-amd64.tar.gz -C containerd
  tar -xvf cni-plugins-linux-amd64-v1.5.0.tgz -C /opt/cni/bin/
  mv runc.amd64 runc
  chmod +x crictl kubectl kube-proxy kubelet runc 
  mv crictl kubectl kube-proxy kubelet runc /usr/local/bin/
  mv containerd/bin/* /bin/
}</code></pre>
<p><strong>Configure CNI Networking</strong></p>
<p><code>bridge</code> network 설정 파일을 옮깁니다.</p>
<pre><code class="language-go">mv 10-bridge.conf 99-loopback.conf /etc/cni/net.d/</code></pre>
<p><strong>Configure containerd</strong></p>
<p><code>containerd</code> 설정 파일을 옮깁니다.</p>
<pre><code class="language-go">{
  mkdir -p /etc/containerd/
  mv containerd-config.toml /etc/containerd/config.toml
  mv containerd.service /etc/systemd/system/
}</code></pre>
<p><strong>Configure the Kubelet</strong></p>
<p><code>kubelet</code> 설정 파일 및 system unit 파일을 옮깁니다.</p>
<pre><code class="language-go">{
  mv kubelet-config.yaml /var/lib/kubelet/
  mv kubelet.service /etc/systemd/system/
}</code></pre>
<p><strong>Configure the Kubernetes Proxy</strong></p>
<p><code>kube-proxy</code> 설정 파일 및 system unit 파일을 옮깁니다.</p>
<pre><code class="language-go">{
  mv kube-proxy-config.yaml /var/lib/kube-proxy/
  mv kube-proxy.service /etc/systemd/system/
}</code></pre>
<p><strong>Start the Worker Services</strong></p>
<p><code>kubelet</code>, <code>kube-proxy</code> 서비스를 실행합니다.</p>
<pre><code class="language-go">{
  systemctl daemon-reload
  systemctl enable containerd kubelet kube-proxy
  systemctl start containerd kubelet kube-proxy
}</code></pre>
<p>여기까지의 과정을 node-2 서버에서도 진행합니다.</p>
<h3 id="verification"><strong>Verification</strong></h3>
<hr>
<p>이번 섹션에서 작업한 worker 노드는 kubectl을 통해 확인할 수 없습니다. 다시 <code>jumpbox</code> 서버에서 아래 명령어를 실행해 확인합니다.</p>
<p>등록된 Kubernetes 노드를 확인합니다.</p>
<pre><code class="language-go">ssh root@controlplane-1 \
  &quot;kubectl get nodes \
  --kubeconfig admin.kubeconfig&quot;</code></pre>
<pre><code class="language-go">NAME     STATUS   ROLES    AGE     VERSION
node-1   Ready    &lt;none&gt;   3m31s   v1.30.1
node-2   Ready    &lt;none&gt;   100s    v1.30.1</code></pre>
<p>Next: <a href="https://velog.io/@dan-te/10-configuring-kubectl">Configuring kubectl for Remote Access</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[08-bootstrapping-kubernetes-controllers]]></title>
            <link>https://velog.io/@dan-te/08-bootstrapping-kubernetes-controllers</link>
            <guid>https://velog.io/@dan-te/08-bootstrapping-kubernetes-controllers</guid>
            <pubDate>Sun, 02 Jun 2024 08:24:48 GMT</pubDate>
            <description><![CDATA[<h3 id="bootstrapping-the-kubernetes-control-plane">Bootstrapping the Kubernetes Control Plane</h3>
<hr>
<p>이번 랩에서는 Kubernetes control plane을 부트스트랩을 진행합니다. 이 과정엔 <code>controlplane-1</code> 에 Kubernetes API Server, Scheduler 그리고 Controller manager를 설치합니다.</p>
<h3 id="prerequisites">Prerequisites</h3>
<hr>
<p>Kubernetes 관련 실행파일들과 systemd unit 파일을 <code>controlplane-1</code> 로 복사합니다.</p>
<p><strong>kube-apiserver</strong></p>
<p><code>kube-apiserver.service</code> 파일을 설정할 때 <code>service-cluster-ip</code> 옵션의 값은 <code>04-certificate-authority</code> 페이지에서 <code>ca.conf</code> 에 설정한 <code>[kube-api-server_alt_names]</code> 항목의 Service IP 범위로 수정해야 합니다.</p>
<pre><code class="language-go">cat &lt;&lt;EOF &gt; /k8s-hardway/units/kube-apiserver.service
[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/kubernetes/kubernetes

[Service]
ExecStart=/usr/local/bin/kube-apiserver \\
  --allow-privileged=true \\
  --apiserver-count=1 \\
  --audit-log-maxage=30 \\
  --audit-log-maxbackup=3 \\
  --audit-log-maxsize=100 \\
  --audit-log-path=/var/log/audit.log \\
  --authorization-mode=Node,RBAC \\
  --bind-address=0.0.0.0 \\
  --client-ca-file=/var/lib/kubernetes/ca.crt \\
  --enable-admission-plugins=NamespaceLifecycle,NodeRestriction,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota \\
  --etcd-servers=http://127.0.0.1:2379 \\
  --event-ttl=1h \\
  --encryption-provider-config=/var/lib/kubernetes/encryption-config.yaml \\
  --kubelet-certificate-authority=/var/lib/kubernetes/ca.crt \\
  --kubelet-client-certificate=/var/lib/kubernetes/kube-api-server.crt \\
  --kubelet-client-key=/var/lib/kubernetes/kube-api-server.key \\
  --runtime-config=&#39;api/all=true&#39; \\
  --service-account-key-file=/var/lib/kubernetes/service-accounts.crt \\
  --service-account-signing-key-file=/var/lib/kubernetes/service-accounts.key \\
  --service-account-issuer=https://controlplane-1.kubernetes.local:6443 \\
  --service-cluster-ip-range=172.16.0.0/24 \\
  --service-node-port-range=30000-32767 \\
  --tls-cert-file=/var/lib/kubernetes/kube-api-server.crt \\
  --tls-private-key-file=/var/lib/kubernetes/kube-api-server.key \\
  --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF</code></pre>
<pre><code class="language-go">cat &lt;&lt;EOF &gt; /k8s-hardway/configs/kube-apiserver-to-kubelet.yaml 
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: &quot;true&quot;
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
  name: system:kube-apiserver-to-kubelet
rules:
  - apiGroups:
      - &quot;&quot;
    resources:
      - nodes/proxy
      - nodes/stats
      - nodes/log
      - nodes/spec
      - nodes/metrics
    verbs:
      - &quot;*&quot;
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: system:kube-apiserver
  namespace: &quot;&quot;
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:kube-apiserver-to-kubelet
subjects:
  - apiGroup: rbac.authorization.k8s.io
    kind: User
    name: kubernetes
EOF</code></pre>
<p><strong>kube-scheduler</strong></p>
<pre><code class="language-go">cat &lt;&lt;EOF &gt; /k8s-hardway/units/kube-scheduler.service
[Unit]
Description=Kubernetes Scheduler
Documentation=https://github.com/kubernetes/kubernetes

[Service]
ExecStart=/usr/local/bin/kube-scheduler \\
  --config=/etc/kubernetes/config/kube-scheduler.yaml \\
  --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF</code></pre>
<pre><code class="language-go">cat &lt;&lt;EOF &gt; /k8s-hardway/configs/kube-scheduler.yaml
apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
clientConnection:
  kubeconfig: &quot;/var/lib/kubernetes/kube-scheduler.kubeconfig&quot;
leaderElection:
  leaderElect: true
EOF</code></pre>
<p><strong>kube-controller-manager</strong></p>
<p><code>kube-controller-manager.service</code> 파일을 설정할 때 <code>cluster-cidr</code> 옵션은 <code>03-compute-resources</code> 페이지에서 설정한 <code>POD_SUBNET</code> 의 전체 IP 범위로 수정하고, <code>service-cluster-ip</code> 옵션은 <code>kube-apiserver.service</code> 파일에 지정한 <code>service-cluster-ip</code> 값이랑 동일하게 수정해야 합니다.</p>
<pre><code class="language-go">cat &lt;&lt;EOF &gt; /k8s-hardway/units/kube-controller-manager.service
[Unit]
Description=Kubernetes Controller Manager
Documentation=https://github.com/kubernetes/kubernetes

[Service]
ExecStart=/usr/local/bin/kube-controller-manager \\
  --bind-address=0.0.0.0 \\
  --cluster-cidr=192.168.0.0/16 \\
  --cluster-name=kubernetes \\
  --cluster-signing-cert-file=/var/lib/kubernetes/ca.crt \\
  --cluster-signing-key-file=/var/lib/kubernetes/ca.key \\
  --kubeconfig=/var/lib/kubernetes/kube-controller-manager.kubeconfig \\
  --root-ca-file=/var/lib/kubernetes/ca.crt \\
  --service-account-private-key-file=/var/lib/kubernetes/service-accounts.key \\
  --service-cluster-ip-range=172.16.0.0/24 \\
  --use-service-account-credentials=true \\
  --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF</code></pre>
<p>위 작업이 완료됐으면, <code>controlplane-1</code> 서버로 파일을 복사합니다.</p>
<pre><code class="language-go">scp \
  /k8s-hardway/downloads/kube-apiserver \
  /k8s-hardway/downloads/kube-controller-manager \
  /k8s-hardway/downloads/kube-scheduler \
  /k8s-hardway/downloads/kubectl \
  /k8s-hardway/units/kube-apiserver.service \
  /k8s-hardway/units/kube-controller-manager.service \
  /k8s-hardway/units/kube-scheduler.service \
  /k8s-hardway/configs/kube-scheduler.yaml \
  /k8s-hardway/configs/kube-apiserver-to-kubelet.yaml \
  root@controlplane-1:~/</code></pre>
<p>이 후 다음 실습은 무조건 <code>controlplane-1</code> 으로 접근하여 세팅해야 합니다.</p>
<pre><code class="language-go">ssh root@controlplane-1</code></pre>
<h3 id="provision-the-kubernetes-control-plane">Provision the Kubernetes Control Plane</h3>
<hr>
<p>Kubernetes 설정 관련 디렉터리를 생성합니다.</p>
<pre><code class="language-go">mkdir -p /etc/kubernetes/config</code></pre>
<p><strong>Install the Kubernetes Controller Binaries</strong></p>
<p>Kubernetes 관련 실행파일들을 옮깁니다.</p>
<pre><code class="language-go">{
  chmod +x kube-apiserver \
    kube-controller-manager \
    kube-scheduler kubectl

  mv kube-apiserver \
    kube-controller-manager \
    kube-scheduler kubectl \
    /usr/local/bin/
}</code></pre>
<p><strong>Configure the Kubernetes API Server</strong></p>
<pre><code class="language-go">{
  mkdir -p /var/lib/kubernetes/

  mv ca.crt ca.key \
    kube-api-server.key kube-api-server.crt \
    service-accounts.key service-accounts.crt \
    encryption-config.yaml \
    /var/lib/kubernetes/
}</code></pre>
<p><code>kube-apiserver.service</code> systemd unit 파일을 옮깁니다.</p>
<pre><code class="language-go">mv kube-apiserver.service \
  /etc/systemd/system/kube-apiserver.service</code></pre>
<p><strong>Configure the Kubernetes Controller Manager</strong></p>
<p><code>kube-controller-manager</code>  kubeconfig 파일을 옮깁니다.</p>
<pre><code class="language-go">mv kube-controller-manager.kubeconfig /var/lib/kubernetes/</code></pre>
<p><code>kube-controller-manager.service</code> systemd unit 파일을 옮깁니다.</p>
<p><strong>Configure the Kubernetes Scheduler</strong></p>
<p><code>kube-scheduler</code> kubeconfig 파일을 옮깁니다.</p>
<pre><code class="language-go">mv kube-scheduler.kubeconfig /var/lib/kubernetes/</code></pre>
<p><code>kube-scheduler.yaml</code> 설정 파일도 옮깁니다.</p>
<pre><code class="language-go">mv kube-scheduler.yaml /etc/kubernetes/config/</code></pre>
<p><code>kube-scheduler.service</code> systemd unit을 옮깁니다.</p>
<pre><code class="language-go">mv kube-scheduler.service /etc/systemd/system/</code></pre>
<p><strong>Start the Controller Services</strong></p>
<pre><code class="language-go">{
  systemctl daemon-reload

  systemctl enable kube-apiserver \
    kube-controller-manager kube-scheduler

  systemctl start kube-apiserver \
    kube-controller-manager kube-scheduler
}</code></pre>
<p>Kubernetes API Server가 완전히 초기화 하는데 최대 10초 정도 소요 됩니다.</p>
<p><strong>Verification</strong></p>
<pre><code class="language-go">kubectl cluster-info \
  --kubeconfig admin.kubeconfig</code></pre>
<pre><code class="language-go">Kubernetes control plane is running at https://127.0.0.1:6443</code></pre>
<h3 id="rbac-for-kubelet-authorization"><strong>RBAC for Kubelet Authorization</strong></h3>
<hr>
<p>이번 섹션에서는 Kubernetes API Server가 각 worker node의 Kubelet API 로 접근할 수 있도록 RBAC 권한을 설정합니다.</p>
<p>Pod에서 metric, logs를 검색하고 명령을 실행하려면, Kubelet API에 접근이 필요합니다.</p>
<p>이번 튜토리얼에서는 kubelet <code>--authorization-mode</code> 옵션을 <code>webhook</code> 으로 설정합니다.  Webhook 모드는 <code>SubjectAcessReview</code> API를 사용하여 승인을 결정합니다.</p>
<p>이 섹션의 실행 명령은 전체 클러스터에 영향을 미치며, controller node에서만 실행해야합니다.</p>
<p>Kubelet API에 접근하고 Pod 관리와 관련된 일반적인 작업을 수행할 수 있는 <code>system:kube-apiserver-to-kubelet</code> ClusterRole을 생성합니다.</p>
<pre><code class="language-go">kubectl apply -f kube-apiserver-to-kubelet.yaml \
  --kubeconfig admin.kubeconfig</code></pre>
<p><strong>Verification</strong></p>
<p>지금은 Kubernetes Control plane이 실행중입니다. <code>jumpbox</code> 서버에서 다음 명령을 실행해 잘 동작하는지 확인해봅니다.</p>
<p>curl을 이용해 Kubernetes 버전 정보를 HTTP GET 요청을 수행합니다.</p>
<pre><code class="language-go">curl -k --cacert ca.crt https://controlplane-1.kubernetes.local:6443/version</code></pre>
<pre><code class="language-go">{
  &quot;major&quot;: &quot;1&quot;,
  &quot;minor&quot;: &quot;30&quot;,
  &quot;gitVersion&quot;: &quot;v1.30.1&quot;,
  &quot;gitCommit&quot;: &quot;6911225c3f747e1cd9d109c305436d08b668f086&quot;,
  &quot;gitTreeState&quot;: &quot;clean&quot;,
  &quot;buildDate&quot;: &quot;2024-05-14T10:42:02Z&quot;,
  &quot;goVersion&quot;: &quot;go1.22.2&quot;,
  &quot;compiler&quot;: &quot;gc&quot;,
  &quot;platform&quot;: &quot;linux/amd64&quot;
}</code></pre>
<p>Next: <a href="https://velog.io/@dan-te/09-bootstrapping-kubernetes-workers">Bootstrapping the Kubernetes Worker Nodes</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[07-bootstrapping-etcd]]></title>
            <link>https://velog.io/@dan-te/07-bootstrapping-etcd</link>
            <guid>https://velog.io/@dan-te/07-bootstrapping-etcd</guid>
            <pubDate>Sun, 02 Jun 2024 08:23:55 GMT</pubDate>
            <description><![CDATA[<h3 id="bootstrapping-the-etcd-cluster">Bootstrapping the etcd Cluster</h3>
<hr>
<p>Kubernetes 컴포넌트들은 상태비저장(stateless)이며 클러스터 정보들은 <code>etcd</code> 에 저장합니다.</p>
<p>이번 랩에서는 <code>controlplane-1</code> 서버에 <code>etcd</code> 를 부트스트랩하는 과정을 진행합니다.</p>
<p><code>etcd</code> 는 고가용성을 위해 3대 이상 서버를 준비하는것을 권장하지만, 이번 튜토리얼은 1대로 진행됩니다.</p>
<p><a href="https://etcd.io/docs/v3.5/faq/">https://etcd.io/docs/v3.5/faq/</a> 공식 사이트에서 확인하실 수 있습니다.</p>
<h3 id="prerequstites">Prerequstites</h3>
<hr>
<pre><code class="language-go">
mkdir /k8s-hardway/units/
ETCD_NAME=controlplane-1

cat &gt; /k8s-hardway/units/etcd.service &lt;&lt;EOF
[Unit]
Description=etcd
Documentation=https://github.com/etcd-io/etcd

[Service]
Type=notify
ExecStart=/usr/local/bin/etcd \\
  --name ${ETCD_NAME} \\
  --initial-advertise-peer-urls http://127.0.0.1:2380 \\
  --listen-peer-urls http://127.0.0.1:2380 \\
  --listen-client-urls http://127.0.0.1:2379 \\
  --advertise-client-urls http://127.0.0.1:2379 \\
  --initial-cluster-token etcd-cluster-0 \\
  --initial-cluster controlplane-1=http://127.0.0.1:2380 \\
  --initial-cluster-state new \\
  --data-dir=/var/lib/etcd
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF</code></pre>
<p><code>controlplane-1</code> 서버에 <code>etcd</code> 실행파일과 systemd unit 파일을 복사합니다.</p>
<pre><code class="language-go">scp \
  /k8s-hardway/downloads/etcd-v3.5.13-linux-amd64.tar.gz \
  /k8s-hardway/units/etcd.service \
  root@controlplane-1:~/</code></pre>
<p>이번 실습은 <code>controlplane-1</code> 서버에서 작업해야 합니다. SSH를 이용해 해당 서버에 접근합ㄴ디ㅏ.</p>
<pre><code class="language-go">ssh root@controlplane-1</code></pre>
<h3 id="bootstrapping-an-etcd-cluster">Bootstrapping an etcd Cluster</h3>
<hr>
<p><strong>Install the etcd Binaries</strong></p>
<p>etcd 압축 파일을 풀고 관련 파일들을 <code>/usr/local/bin</code> 디렉터리에 옮깁니다.</p>
<pre><code class="language-go">{
  tar -xvf etcd-v3.5.13-linux-amd64.tar.gz
  mv etcd-v3.5.13-linux-amd64/etcd* /usr/local/bin/
} </code></pre>
<p><strong>Configure the etcd Server</strong></p>
<pre><code class="language-go">{
  mkdir -p /etc/etcd /var/lib/etcd
  chmod 700 /var/lib/etcd
  cp ca.crt \
    /etc/etcd/
}</code></pre>
<p>etcd 멤버는 etcd cluster 내에 고유한 이름을 가져야합니다. 현재 이 서버의 hostname과 etcd에 설정한 hostname이 동일한지 확인이 필요합니다.</p>
<pre><code class="language-go"> grep `hostname` etcd.service</code></pre>
<pre><code class="language-go">  --name controlplane-1 \
  --initial-cluster controlplane-1=http://127.0.0.1:2380 \</code></pre>
<p>etcd를 데몬으로 실행하기 위해 <code>/etc/systemd/system/</code> 디렉터리에 systemd unit 파일을 옮깁니다.</p>
<pre><code class="language-go">mv etcd.service /etc/systemd/system/</code></pre>
<p><strong>Start the etcd Server</strong></p>
<p>etcd 서버를 실행합니다.</p>
<pre><code class="language-go">{
  systemctl daemon-reload
  systemctl enable etcd
  systemctl start etcd
}</code></pre>
<h3 id="vertification">Vertification</h3>
<hr>
<p>etcd 서버가 잘 동작하는지 확인합니다.</p>
<pre><code class="language-go">systemctl status etcd</code></pre>
<pre><code class="language-go">● etcd.service - etcd
     Loaded: loaded (/etc/systemd/system/etcd.service; enabled; vendor preset: &gt;
     Active: active (running) since Wed 2024-05-29 07:33:31 UTC; 8s ago
       Docs: https://github.com/etcd-io/etcd
   Main PID: 4970 (etcd)
      Tasks: 9 (limit: 9389)
     Memory: 6.7M
        CPU: 44ms
     CGroup: /system.slice/etcd.service
             └─4970 /usr/local/bin/etcd --name controlplane-1 --initial-adverti&gt;</code></pre>
<p>etcd 클러스터 멤버를 확인합니다.</p>
<pre><code class="language-go">etcdctl member list</code></pre>
<pre><code class="language-go">6702b0a34e2cfd39, started, controlplane-1, http://127.0.0.1:2380, http://127.0.0.1:2379, false</code></pre>
<p>Next: <a href="https://velog.io/@dan-te/08-bootstrapping-kubernetes-controllers">Bootstrapping the Kubernetes Control Plane</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[06-data-encryption-keys]]></title>
            <link>https://velog.io/@dan-te/06-data-encryption-keys</link>
            <guid>https://velog.io/@dan-te/06-data-encryption-keys</guid>
            <pubDate>Sun, 02 Jun 2024 08:23:14 GMT</pubDate>
            <description><![CDATA[<h3 id="generating-the-data-encryption-config-and-key">Generating the Data Encryption Config and Key</h3>
<hr>
<p>Kubernetes는 클러스터 상태, 어플리케이션 구성 그리고 secret을 포함한 다양한 데이터를 저장합니다.</p>
<p>Kubernetes는 클러스터 데이터를 저장 중에 암호화 할 수 있는 기능을 지원합니다.</p>
<p>이번 실습에서는 Kubernetes Secret을 암호화 하기 위한 암호화 키와 암호화 설정파일을 생성합니다.</p>
<p><a href="https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/#understanding-the-encryption-at-rest-configuration">https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/#understanding-the-encryption-at-rest-configuration</a></p>
<p>해당 작업을 진행하는 이유는 Kubernetes Secret 리소스 생성 시 Kubernetes 저장소인 <code>ETCD</code> 에 정보를 저장하는데 이땐 평문으로 저장됩니다.</p>
<p> <code>ETCD</code> 에 Kubernetes의 Secret 리소스를 조회하면 평문으로 조회되니, 이를 방지하기 위해 <code>ETCD</code> 저장 시 암호화해서 저장 하도록 합니다.</p>
<h3 id="the-encryption-key">The Encryption Key</h3>
<hr>
<p>암호화 키를 생성합니다.</p>
<pre><code class="language-go">export ENCRYPTION_KEY=$(head -c 32 /dev/urandom | base64)</code></pre>
<p><strong>The Encryption Config File</strong></p>
<hr>
<p><code>encryption-config.yaml</code> 암호화 설정파일을 생성합니다.</p>
<pre><code class="language-go">mkdir /k8s-hardway/configs

cat &gt; /k8s-hardway/configs/encryption-config.yaml &lt;&lt;EOF
kind: EncryptionConfig
apiVersion: v1
resources:
  - resources:
      - secrets
    providers:
      - aescbc:
          keys:
            - name: key1
              secret: ${ENCRYPTION_KEY}
      - identity: {}
EOF
</code></pre>
<p><code>encryption-config.yaml</code> 파일을 <code>controlplane-1</code> 서버로 복사합니다.</p>
<pre><code class="language-go">scp /k8s-hardway/configs/encryption-config.yaml root@controlplane-1:~/</code></pre>
<p>Next: <a href="https://velog.io/@dan-te/07-bootstrapping-etcd">Bootstrapping the etcd Cluster</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[05-kubernetes-configuration-files]]></title>
            <link>https://velog.io/@dan-te/05-kubernetes-configuration-files</link>
            <guid>https://velog.io/@dan-te/05-kubernetes-configuration-files</guid>
            <pubDate>Sun, 02 Jun 2024 08:22:45 GMT</pubDate>
            <description><![CDATA[<h3 id="generating-kubernetes-configuration-files-for-authentication">Generating Kubernetes configuration Files for Authentication</h3>
<hr>
<p>이번 랩에서는 Kubernetes 클라이언트가 kuberenetes API 서버를 찾고 인증할 수 있도록 kubeconfig로 알려진 Kubernetes 설정 파일을 생성합니다.</p>
<h3 id="client-authentication-configs">Client Authentication configs</h3>
<hr>
<p>이 섹션은 <code>kubelet</code> 과 <code>admin</code> 사용자를 위한 kubeconfig 파일을 생성합니다.</p>
<h3 id="the-kubelet-kubernetes-configuration-file">The kubelet Kubernetes Configuration File</h3>
<p>kubelet용 kubeconfig 파일을 생성할 때 kubelet의 node 이름과 일치하는 클라이언트 인증서를 사용해야 합니다. 이 작업은 kubelet이 Kubernetes <a href="https://kubernetes.io/docs/reference/access-authn-authz/node/">Node Authorizer</a>에 의해 승인되도록 합니다.</p>
<p>아래 명령어들은 04-certificate-authority 실습 중에 SSL 인증서를 생성한 동일한 디렉터리에서 실행해야 합니다.</p>
<pre><code class="language-go">for host in node-1 node-2; do
  kubectl config set-cluster kubernetes-the-hard-way \
    --certificate-authority=/k8s-hardway/tls/ca.crt \
    --embed-certs=true \
    --server=https://controlplane-1.kubernetes.local:6443 \
    --kubeconfig=/k8s-hardway/tls/${host}.kubeconfig

  kubectl config set-credentials system:node:${host} \
    --client-certificate=/k8s-hardway/tls/${host}.crt \
    --client-key=/k8s-hardway/tls/${host}.key \
    --embed-certs=true \
    --kubeconfig=/k8s-hardway/tls/${host}.kubeconfig

  kubectl config set-context default \
    --cluster=kubernetes-the-hard-way \
    --user=system:node:${host} \
    --kubeconfig=/k8s-hardway/tls/${host}.kubeconfig

  kubectl config use-context default \
    --kubeconfig=/k8s-hardway/tls/${host}.kubeconfig
done</code></pre>
<pre><code class="language-go">Cluster &quot;kubernetes-the-hard-way&quot; set.
User &quot;system:node:node-1&quot; set.
Context &quot;default&quot; created.
Switched to context &quot;default&quot;.
Cluster &quot;kubernetes-the-hard-way&quot; set.
User &quot;system:node:node-2&quot; set.
Context &quot;default&quot; created.
Switched to context &quot;default&quot;.</code></pre>
<pre><code class="language-go">ls -1 /k8s-hardway/tls/node-1.kubeconfig /k8s-hardway/tls/node-2.kubeconfig
# /k8s-hardway/tls/node-1.kubeconfig
# /k8s-hardway/tls/node-2.kubeconfig
</code></pre>
<h3 id="the-kube-proxy-kubernetes-configuration-file">The kube-proxy Kubernetes configuration File</h3>
<hr>
<p>이 섹션에서는 <code>kube-proxy</code> 서비스의 kubeconfig 파일을 생성합니다.</p>
<pre><code class="language-go">{
  kubectl config set-cluster kubernetes-the-hard-way \
    --certificate-authority=/k8s-hardway/tls/ca.crt \
    --embed-certs=true \
    --server=https://controlplane-1.kubernetes.local:6443 \
    --kubeconfig=/k8s-hardway/tls/kube-proxy.kubeconfig

  kubectl config set-credentials system:kube-proxy \
    --client-certificate=/k8s-hardway/tls/kube-proxy.crt \
    --client-key=/k8s-hardway/tls/kube-proxy.key \
    --embed-certs=true \
    --kubeconfig=/k8s-hardway/tls/kube-proxy.kubeconfig

  kubectl config set-context default \
    --cluster=kubernetes-the-hard-way \
    --user=system:kube-proxy \
    --kubeconfig=/k8s-hardway/tls/kube-proxy.kubeconfig

  kubectl config use-context default \
    --kubeconfig=/k8s-hardway/tls/kube-proxy.kubeconfig
}</code></pre>
<pre><code class="language-go">Cluster &quot;kubernetes-the-hard-way&quot; set.
User &quot;system:kube-proxy&quot; set.
Context &quot;default&quot; created.
Switched to context &quot;default&quot;.</code></pre>
<pre><code class="language-go">ls -1 /k8s-hardway/tls/kube-proxy.kubeconfig
# /k8s-hardway/tls/kube-proxy.kubeconfig</code></pre>
<h3 id="the-kube-controller-manager-kubernetes-configuration-file">The kube-controller-manager Kubernetes Configuration File</h3>
<hr>
<p><code>kube-controller-manager</code> 서비스를 위한 kubeconfig 파일을 생성합니다.</p>
<pre><code class="language-go">{
  kubectl config set-cluster kubernetes-the-hard-way \
    --certificate-authority=/k8s-hardway/tls/ca.crt \
    --embed-certs=true \
    --server=https://controlplane-1.kubernetes.local:6443 \
    --kubeconfig=/k8s-hardway/tls/kube-controller-manager.kubeconfig

  kubectl config set-credentials system:kube-controller-manager \
    --client-certificate=/k8s-hardway/tls/kube-controller-manager.crt \
    --client-key=/k8s-hardway/tls/kube-controller-manager.key \
    --embed-certs=true \
    --kubeconfig=/k8s-hardway/tls/kube-controller-manager.kubeconfig

  kubectl config set-context default \
    --cluster=kubernetes-the-hard-way \
    --user=system:kube-controller-manager \
    --kubeconfig=/k8s-hardway/tls/kube-controller-manager.kubeconfig

  kubectl config use-context default \
    --kubeconfig=/k8s-hardway/tls/kube-controller-manager.kubeconfig
}
</code></pre>
<pre><code class="language-go">Cluster &quot;kubernetes-the-hard-way&quot; set.
User &quot;system:kube-controller-manager&quot; set.
Context &quot;default&quot; created.
Switched to context &quot;default&quot;.</code></pre>
<pre><code class="language-go">ls -1 /k8s-hardway/tls/kube-controller-manager.kubeconfig
# /k8s-hardway/tls/kube-controller-manager.kubeconfig</code></pre>
<h3 id="the-kube-scheduler-kubernetes-configuration-file">The kube-scheduler Kubernetes Configuration File</h3>
<hr>
<p><code>kube-scheduler</code> 서비스를 위한 kubeconfig 파일을 생성합니다.</p>
<pre><code class="language-go">{
  kubectl config set-cluster kubernetes-the-hard-way \
    --certificate-authority=/k8s-hardway/tls/ca.crt \
    --embed-certs=true \
    --server=https://controlplane-1.kubernetes.local:6443 \
    --kubeconfig=/k8s-hardway/tls/kube-scheduler.kubeconfig

  kubectl config set-credentials system:kube-scheduler \
    --client-certificate=/k8s-hardway/tls/kube-scheduler.crt \
    --client-key=/k8s-hardway/tls/kube-scheduler.key \
    --embed-certs=true \
    --kubeconfig=/k8s-hardway/tls/kube-scheduler.kubeconfig

  kubectl config set-context default \
    --cluster=kubernetes-the-hard-way \
    --user=system:kube-scheduler \
    --kubeconfig=/k8s-hardway/tls/kube-scheduler.kubeconfig

  kubectl config use-context default \
    --kubeconfig=/k8s-hardway/tls/kube-scheduler.kubeconfig
}</code></pre>
<pre><code class="language-go">Cluster &quot;kubernetes-the-hard-way&quot; set.
User &quot;system:kube-scheduler&quot; set.
Context &quot;default&quot; created.
Switched to context &quot;default&quot;.</code></pre>
<pre><code class="language-go">ls -1 /k8s-hardway/tls/kube-scheduler.kubeconfig
# /k8s-hardway/tls/kube-scheduler.kubeconfig</code></pre>
<h3 id="the-admin-kubernetes-configuration-file">The admin Kubernetes Configuration File</h3>
<hr>
<p><code>admin</code> 사용자를 위한 kubeconfig 파일을 생성합니다.</p>
<pre><code class="language-go">{
  kubectl config set-cluster kubernetes-the-hard-way \
    --certificate-authority=/k8s-hardway/tls/ca.crt \
    --embed-certs=true \
    --server=https://127.0.0.1:6443 \
    --kubeconfig=/k8s-hardway/tls/admin.kubeconfig

  kubectl config set-credentials admin \
    --client-certificate=/k8s-hardway/tls/admin.crt \
    --client-key=/k8s-hardway/tls/admin.key \
    --embed-certs=true \
    --kubeconfig=/k8s-hardway/tls/admin.kubeconfig

  kubectl config set-context default \
    --cluster=kubernetes-the-hard-way \
    --user=admin \
    --kubeconfig=/k8s-hardway/tls/admin.kubeconfig

  kubectl config use-context default \
    --kubeconfig=/k8s-hardway/tls/admin.kubeconfig
}</code></pre>
<pre><code class="language-go">Cluster &quot;kubernetes-the-hard-way&quot; set.
User &quot;admin&quot; set.
Context &quot;default&quot; created.
Switched to context &quot;default&quot;.</code></pre>
<pre><code class="language-go">ls -1 /k8s-hardway/tls/admin.kubeconfig
# /k8s-hardway/tls/admin.kubeconfig</code></pre>
<h3 id="distribute-the-kubernetes-configuration-files">Distribute the Kubernetes Configuration Files</h3>
<hr>
<p><code>node-1</code>, <code>node-2</code> 서버로 <code>kubelet</code> , <code>kube-proxy</code> kubeconfig 파일을 복사합니다.</p>
<pre><code class="language-go">for host in node-1 node-2; do
  ssh root@$host &quot;mkdir /var/lib/{kube-proxy,kubelet}&quot;

  scp /k8s-hardway/tls/kube-proxy.kubeconfig \
    root@$host:/var/lib/kube-proxy/kubeconfig \

  scp /k8s-hardway/tls/${host}.kubeconfig \
    root@$host:/var/lib/kubelet/kubeconfig
done</code></pre>
<p><code>controlplane-1</code> 서버로 <code>kube-controller-manager</code>, <code>kube-scheduler</code> kubeconfig 파일을 복사합니다.</p>
<pre><code class="language-go">scp /k8s-hardway/tls/admin.kubeconfig \
  /k8s-hardway/tls/kube-controller-manager.kubeconfig \
  /k8s-hardway/tls/kube-scheduler.kubeconfig \
  root@controlplane-1:~/</code></pre>
<p>Next: <a href="https://velog.io/@dan-te/06-data-encryption-keys">Generating the Data Encryption Config and Key</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[04-certificate-authority]]></title>
            <link>https://velog.io/@dan-te/04-certificate-authority</link>
            <guid>https://velog.io/@dan-te/04-certificate-authority</guid>
            <pubDate>Sun, 02 Jun 2024 08:22:19 GMT</pubDate>
            <description><![CDATA[<h3 id="provisioning-a-ca-and-generating-tls-certificates">Provisioning a CA and Generating TLS Certificates</h3>
<hr>
<p>이번 랩에서는 openssl을 사용하여 PKI 인프라를 설정하고 인증 기관(Certificate Authority)을 부트스트랩해 kube-apiserver, kube-controller-manager, kube-scheduler, kubelet 그리고 kube-proxy와 같은 컴포넌트를 위한 TLS 인증서를 생성할 것입니다.</p>
<h3 id="certificate-authority">Certificate Authority</h3>
<hr>
<p>이 섹션에서는  인증 기관(Certificate Authority)를 설정해 Kubernetes 컴포넌트를 위한 추가 TLS 인증서를 생성할 수 있도록합니다.</p>
<p><code>openssl</code> 을 사용해 CA를 설정하고 인증서를 생성하는 과정은 특히 처음 할 때 시간이 많이 걸릴 수 있습니다. </p>
<p>아래 <code>ca.conf</code> 파일은 Kubernetes 컴포넌트에 대한 인증서를 생성하는데 필요한 모든 정보가 정의 되어있습니다. 해당 파일은 각 환경에 맞게 수정하시면 됩니다. (가장 중요한 부분이라 생각되니, 오타 없이 수정하셔야합니다.)</p>
<pre><code class="language-go">
mkdir /k8s-hardway/tls/
cat &lt;&lt;EOF &gt; /k8s-hardway/tls/ca.conf 
[req]
distinguished_name = req_distinguished_name
prompt             = no
x509_extensions    = ca_x509_extensions

[ca_x509_extensions]
basicConstraints = CA:TRUE
keyUsage         = cRLSign, keyCertSign

[req_distinguished_name]
C   = KR
CN  = CA

[admin]
distinguished_name = admin_distinguished_name
prompt             = no
req_extensions     = default_req_extensions

[admin_distinguished_name]
CN = admin
O  = system:masters

# Service Accounts
#
# The Kubernetes Controller Manager leverages a key pair to generate
# and sign service account tokens as described in the
# [managing service accounts](https://kubernetes.io/docs/admin/service-accounts-admin/)
# documentation.

[service-accounts]
distinguished_name = service-accounts_distinguished_name
prompt             = no
req_extensions     = default_req_extensions

[service-accounts_distinguished_name]
CN = service-accounts

# Worker Nodes
#
# Kubernetes uses a [special-purpose authorization mode](https://kubernetes.io/docs/admin/authorization/node/)
# called Node Authorizer, that specifically authorizes API requests made
# by [Kubelets](https://kubernetes.io/docs/concepts/overview/components/#kubelet).
# In order to be authorized by the Node Authorizer, Kubelets must use a credential
# that identifies them as being in the &#39;system:nodes&#39; group, with a username
# of &#39;system:node:&lt;nodeName&gt;&#39;.

[node-1]
distinguished_name = node-1_distinguished_name
prompt             = no
req_extensions     = node-1_req_extensions

[node-1_req_extensions]
basicConstraints     = CA:FALSE
extendedKeyUsage     = clientAuth, serverAuth
keyUsage             = critical, digitalSignature, keyEncipherment
nsCertType           = client
nsComment            = &quot;Node-1 Certificate&quot;
subjectAltName       = DNS:node-1, IP:127.0.0.1
subjectKeyIdentifier = hash

[node-1_distinguished_name]
CN = system:node:node-1
O  = system:nodes
C  = KR

[node-2]
distinguished_name = node-2_distinguished_name
prompt             = no
req_extensions     = node-2_req_extensions

[node-2_req_extensions]
basicConstraints     = CA:FALSE
extendedKeyUsage     = clientAuth, serverAuth
keyUsage             = critical, digitalSignature, keyEncipherment
nsCertType           = client
nsComment            = &quot;Node-2 Certificate&quot;
subjectAltName       = DNS:node-2, IP:127.0.0.1
subjectKeyIdentifier = hash

[node-2_distinguished_name]
CN = system:node:node-2
O  = system:nodes
C  = KR

# Kube Proxy Section
[kube-proxy]
distinguished_name = kube-proxy_distinguished_name
prompt             = no
req_extensions     = kube-proxy_req_extensions

[kube-proxy_req_extensions]
basicConstraints     = CA:FALSE
extendedKeyUsage     = clientAuth, serverAuth
keyUsage             = critical, digitalSignature, keyEncipherment
nsCertType           = client
nsComment            = &quot;Kube Proxy Certificate&quot;
subjectAltName       = DNS:kube-proxy, IP:127.0.0.1
subjectKeyIdentifier = hash

[kube-proxy_distinguished_name]
CN = system:kube-proxy
O  = system:node-proxier
C  = KR

# Controller Manager
[kube-controller-manager]
distinguished_name = kube-controller-manager_distinguished_name
prompt             = no
req_extensions     = kube-controller-manager_req_extensions

[kube-controller-manager_req_extensions]
basicConstraints     = CA:FALSE
extendedKeyUsage     = clientAuth, serverAuth
keyUsage             = critical, digitalSignature, keyEncipherment
nsCertType           = client
nsComment            = &quot;Kube Controller Manager Certificate&quot;
subjectAltName       = DNS:kube-proxy, IP:127.0.0.1
subjectKeyIdentifier = hash

[kube-controller-manager_distinguished_name]
CN = system:kube-controller-manager
O  = system:kube-controller-manager
C  = KR

# Scheduler
[kube-scheduler]
distinguished_name = kube-scheduler_distinguished_name
prompt             = no
req_extensions     = kube-scheduler_req_extensions

[kube-scheduler_req_extensions]
basicConstraints     = CA:FALSE
extendedKeyUsage     = clientAuth, serverAuth
keyUsage             = critical, digitalSignature, keyEncipherment
nsCertType           = client
nsComment            = &quot;Kube Scheduler Certificate&quot;
subjectAltName       = DNS:kube-scheduler, IP:127.0.0.1
subjectKeyIdentifier = hash

[kube-scheduler_distinguished_name]
CN = system:kube-scheduler
O  = system:system:kube-scheduler
C  = KR

# API Server
#
# The Kubernetes API server is automatically assigned the &#39;kubernetes&#39;
# internal dns name, which will be linked to the first IP address (&#39;172.16.0.1&#39;)
# from the address range (&#39;172.16.0.0/24&#39;) reserved for internal cluster
# services.

[kube-api-server]
distinguished_name = kube-api-server_distinguished_name
prompt             = no
req_extensions     = kube-api-server_req_extensions

[kube-api-server_req_extensions]
basicConstraints     = CA:FALSE
extendedKeyUsage     = clientAuth, serverAuth
keyUsage             = critical, digitalSignature, keyEncipherment
nsCertType           = client
nsComment            = &quot;Kube Scheduler Certificate&quot;
subjectAltName       = @kube-api-server_alt_names
subjectKeyIdentifier = hash

[kube-api-server_alt_names]
IP.0  = 127.0.0.1
IP.1  = 172.16.0.1
DNS.0 = kubernetes
DNS.1 = kubernetes.default
DNS.2 = kubernetes.default.svc
DNS.3 = kubernetes.default.svc.cluster
DNS.4 = kubernetes.svc.cluster.local
DNS.5 = controlplane-1.kubernetes.local
DNS.6 = api-server.kubernetes.local

[kube-api-server_distinguished_name]
CN = kubernetes
C  = KR

[default_req_extensions]
basicConstraints     = CA:FALSE
extendedKeyUsage     = clientAuth
keyUsage             = critical, digitalSignature, keyEncipherment
nsCertType           = client
nsComment            = &quot;Admin Client Certificate&quot;
subjectKeyIdentifier = hash
EOF</code></pre>
<p>Kubernetes the hard way 튜토리얼을 완료하기 위해 <code>ca.conf</code> 파일의 모든 내용을 이해할 필요는 없지만,</p>
<p><code>openssl</code> 과 인증서 관리를 위한 설정을 배우는 출발점으로 생각하면 좋습니다.</p>
<p>모든 certificate authority는 Private key와 root certificate로 시작됩니다. </p>
<p>이번 섹션에서는 Self-signed certificate authority를 생성 할 것이며, 튜토리얼을 진행하는데 있어 이것만으로 충분하지만, 실제 운영 환경에서는 이렇게 하지 않는것이 좋습니다.</p>
<p>CA 설정 파일, certificate 그리고 private key를 생성합니다.</p>
<pre><code class="language-go">{
  openssl genrsa -out /k8s-hardway/tls/ca.key 4096
  openssl req -x509 -new -sha512 -noenc \
    -key /k8s-hardway/tls/ca.key -days 3653 \
    -config /k8s-hardway/tls/ca.conf \
    -out /k8s-hardway/tls/ca.crt
}</code></pre>
<pre><code class="language-go">ls -al /k8s-hardway/tls/
# --- result ---
# total 24
# drwxr-xr-x 2 root root 4096 May 29 01:00 .
# drwxr-xr-x 4 root root 4096 May 29 00:47 ..
# -rw-r--r-- 1 root root 5643 May 29 00:49 ca.conf
# -rw-r--r-- 1 root root 1793 May 29 01:00 ca.crt
# -rw------- 1 root root 3272 May 29 01:00 ca.key</code></pre>
<h3 id="create-client-and-server-certificates">Create Client and Server Certificates</h3>
<hr>
<p>이번 섹션에서는 각 Kubernetes 컴포넌트의 Client와 Server 인증서와 Kubernetes <code>admin</code> 사용자에 대한 Client 인증서를 생성합니다.</p>
<p>kubernetes 컴포넌트의 certificate와 private key를 생성합니다.</p>
<pre><code class="language-go">certs=(
  &quot;admin&quot; &quot;node-1&quot; &quot;node-2&quot;
  &quot;kube-proxy&quot; &quot;kube-scheduler&quot;
  &quot;kube-controller-manager&quot;
  &quot;kube-api-server&quot;
  &quot;service-accounts&quot;
)</code></pre>
<pre><code class="language-go">for i in ${certs[*]}; do
  openssl genrsa -out &quot;/k8s-hardway/tls/${i}.key&quot; 4096

  openssl req -new -key &quot;/k8s-hardway/tls/${i}.key&quot; -sha256 \
    -config &quot;/k8s-hardway/tls/ca.conf&quot; -section ${i} \
    -out &quot;/k8s-hardway/tls/${i}.csr&quot;

  openssl x509 -req -days 3653 -in &quot;/k8s-hardway/tls/${i}.csr&quot; \
    -copy_extensions copyall \
    -sha256 -CA &quot;/k8s-hardway/tls/ca.crt&quot; \
    -CAkey &quot;/k8s-hardway/tls/ca.key&quot; \
    -CAcreateserial \
    -out &quot;/k8s-hardway/tls/${i}.crt&quot;
done</code></pre>
<p>위 명령어를 실행하면, private key, certificate request와 각 Kubernetes 컴포넌트에 대한 Singed SSL Certificate 파일이 생성됩니다.</p>
<pre><code class="language-go">ls -1 /k8s-hardway/tls/*.crt /k8s-hardway/tls/*.key /k8s-hardway/tls/*.csr</code></pre>
<pre><code class="language-go">/k8s-hardway/tls/admin.crt
/k8s-hardway/tls/admin.csr
/k8s-hardway/tls/admin.key
/k8s-hardway/tls/ca.crt
/k8s-hardway/tls/ca.key
/k8s-hardway/tls/kube-api-server.crt
/k8s-hardway/tls/kube-api-server.csr
/k8s-hardway/tls/kube-api-server.key
/k8s-hardway/tls/kube-controller-manager.crt
/k8s-hardway/tls/kube-controller-manager.csr
/k8s-hardway/tls/kube-controller-manager.key
/k8s-hardway/tls/kube-proxy.crt
/k8s-hardway/tls/kube-proxy.csr
/k8s-hardway/tls/kube-proxy.key
/k8s-hardway/tls/kube-scheduler.crt
/k8s-hardway/tls/kube-scheduler.csr
/k8s-hardway/tls/kube-scheduler.key
/k8s-hardway/tls/node-1.crt
/k8s-hardway/tls/node-1.csr
/k8s-hardway/tls/node-1.key
/k8s-hardway/tls/node-2.crt
/k8s-hardway/tls/node-2.csr
/k8s-hardway/tls/node-2.key
/k8s-hardway/tls/service-accounts.crt
/k8s-hardway/tls/service-accounts.csr
/k8s-hardway/tls/service-accounts.key</code></pre>
<h3 id="distribute-the-client-and-server-certificates">Distribute the Client and Server Certificates</h3>
<hr>
<p>이 섹션에서는  <code>jumpbox</code> 서버에서 <code>node-1</code>, <code>node-2</code> 서버로 각 Kubernetes 컴포넌트가 인증서를 쌍으로 찾을 수 있는 디렉터리로 이전에 생성한 인증서를 복사합니다.</p>
<p><code>node-1</code>, <code>node-2</code> 서버에 맞게 certificate와 private key를 복사합니다.</p>
<pre><code class="language-go">for host in node-1 node-2; do
  ssh root@$host mkdir /var/lib/kubelet/

  scp /k8s-hardway/tls/ca.crt root@$host:/var/lib/kubelet/

  scp /k8s-hardway/tls/$host.crt \
    root@$host:/var/lib/kubelet/kubelet.crt

  scp /k8s-hardway/tls/$host.key \
    root@$host:/var/lib/kubelet/kubelet.key
done</code></pre>
<pre><code class="language-go">ca.crt                                        100% 1793     4.2MB/s   00:00
node-1.crt                                    100% 2041     3.8MB/s   00:00
node-1.key                                    100% 3272     6.1MB/s   00:00
ca.crt                                        100% 1793     3.9MB/s   00:00
node-2.crt                                    100% 2041     4.8MB/s   00:00
node-2.key                                    100% 3272     7.7MB/s   00:0</code></pre>
<p><code>controlplane-1</code> 서버로 동일하게 인증서를 복사합니다.</p>
<pre><code class="language-go">scp \
 /k8s-hardway/tls/ca.key /k8s-hardway/tls/ca.crt \
  /k8s-hardway/tls/kube-api-server.key /k8s-hardway/tls/kube-api-server.crt \
  /k8s-hardway/tls/service-accounts.key /k8s-hardway/tls/service-accounts.crt \
  root@controlplane-1:~/</code></pre>
<pre><code class="language-go">ca.key                                        100% 3272     5.7MB/s   00:00
ca.crt                                        100% 1793     5.5MB/s   00:00
kube-api-server.key                           100% 3272     9.5MB/s   00:00
kube-api-server.crt                           100% 2256     5.9MB/s   00:00
service-accounts.key                          100% 3272    10.5MB/s   00:00
service-accounts.crt                          100% 1952     5.9MB/s   00:00</code></pre>
<p><code>kube-proxy</code>, <code>kube-controller-manager</code>, <code>kube-schedueler</code> 그리고 <code>kubelet</code> 클라이언트 인증서는 다음 실습에 클라이언트 인증 설정 파일을 생성하는데 사용됩니다.</p>
<p>Next: <a href="https://velog.io/@dan-te/05-kubernetes-configuration-files">Generating Kubernetes Configuration Files for Authentication</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[03-compute-resources]]></title>
            <link>https://velog.io/@dan-te/03-compute-resources</link>
            <guid>https://velog.io/@dan-te/03-compute-resources</guid>
            <pubDate>Sun, 02 Jun 2024 08:21:38 GMT</pubDate>
            <description><![CDATA[<h3 id="machine-database">Machine Database</h3>
<hr>
<p>Kubernetes Cluster를 구성하기 위해 Kubernetes Controlplane, 컨테이너가 실행 될 worker 노드가 필요합니다.</p>
<p>(kubernetes hard way 경우 kubernetes controlplane은 kubelet을 설치하지 않기 때문에 컨테이너가 동작하진 않습니다.)</p>
<p>이 튜토리얼은 kubernetes controlplane, worker node에 사용할  다양한 서버 속성들을 아래와 같은 예시로 장비 데이터베이스용 텍스트 파일로 저장하여 설정을 하고자 합니다.</p>
<pre><code class="language-go">IPV4_ADDRESS FQDN HOSTNAME POD_SUBNET</code></pre>
<p><code>IPV4_ADDRESS</code> 은 서버의 IP, <code>FQDN</code> 은 fully qualified domain name, <code>HOSTNAME</code> 은 host name, <code>POD_SUBNET</code> 은 Pod의 IP 서브넷을 나타냅니다.</p>
<p>Kubernetes는 Pod당 하나의 IP 주소를 할당하며, <code>POD_SUBNET</code> 은 Kubernetes Cluster 내 각 서버에 할당된 고유 IP 주소 범위를 나타냅니다.</p>
<p>자신의 시스템 환경에 맞춰 수정 후 장비 데이터베이스 파일을 생성합니다.</p>
<pre><code class="language-go">cd /k8s-hardway
cat &lt;&lt;EOF &gt; machines.txt 
10.0.35.207 controlplane-1.kubernetes.local controlplane-1  
10.0.34.93 node-1.kubernetes.local node-1 192.168.10.0/24
10.0.32.237 node-2.kubernetes.local node-2 192.168.11.0/24
EOF</code></pre>
<h3 id="configure-ssh-access">Configure SSH Access</h3>
<hr>
<p>SSH는 Kubernets Cluster를 구성하는데 사용됩니다. 위에 생성한 장비 데이터 파일에 대한</p>
<p>root SSH 접근 권한이 있는지 확인하고, root 접근이 안되어 있을 경우 <code>/etc/ssh/sshd_config</code> 파일을 root로 접근할 수 있게 수정 후 SSH를 재시작 하면 됩니다.</p>
<p>Enable root SSH Access</p>
<hr>
<p>만약에 root 계정의 SSH 접근 권한이 활성화 되어있을 경우 해당 섹션은 넘어가셔도 됩니다.</p>
<p>리눅스 운영체제마다 다르지만, 보안상 root 계정을 통한 SSH 접근은 비활성화 되어 있는 경우가 있습니다. root라는 사용자 명은 널리 알리어져 있으며, 만약에 엄청 취약한 패스워드를 사용하고 있다면,  외부에서 쉽게 SSH 접근을 할 수 있기에 공격에 매우 취약합니다.</p>
<p>하지만, 해당 튜토리얼의 단계를 간소화 하기 위해 SSH를 통한 root 계정 액세스를 활성화를 합니다.</p>
<p>(이 가이드는 외부에서 접근하면 위험하기에 외부에서 접근 가능한 서버라면, 방화벽 인바운드 정책 또는 root 계정 패스워드를 강력하게 설정하시면 됩니다.)  </p>
<p>각 서버에 접근하여 root 계정으로 전환합니다.</p>
<pre><code class="language-go">su - root 
OR 
sudo -i  </code></pre>
<p><code>/etc/ssh/sshd_config</code> 의 <code>PermitRootLogin</code> 옵션을 no에서 yes로 변경합니다.</p>
<pre><code class="language-go">sed -i \
  &#39;s/^#PermitRootLogin.*/PermitRootLogin yes/&#39; \
  /etc/ssh/sshd_config</code></pre>
<p>설정파일을 수정했으니<code>sshd</code> (SSH Daemon)SSH 서버를 재시작합니다.</p>
<pre><code class="language-go">systemctl restart sshd
systemctl status sshd

# OUTPUT
# &gt; ● ssh.service - OpenBSD Secure Shell server
#     Loaded: loaded (/lib/systemd/system/ssh.service; enabled; vendor preset: e&gt;
#     Active: active (running) since Mon 2024-05-27 15:20:38 UTC; 10s ago`</code></pre>
<h2 id="generate-and-distribute-ssh-keys">Generate and Distribute SSH Keys</h2>
<hr>
<p>이 섹션에서는  <code>controlplane-1</code>, <code>node-1</code>, <code>node-2</code> 에 대한 SSH Key pair를 생성하고,서버에 배포 작업을 합니다.</p>
<p>해당 작업은 튜토리얼 동안 jumpbox 서버에서 명령을 실행하는데 사용될 것입니다.</p>
<p>SSH Key 생성</p>
<pre><code class="language-go">ssh-keygen</code></pre>
<pre><code class="language-go">Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa
Your public key has been saved in /root/.ssh/id_rsa.pub</code></pre>
<p>생성한 SSH public key를 각 서버에 복사합니다.</p>
<pre><code class="language-go">while read IP FQDN HOST SUBNET; do 
  ssh-copy-id root@${IP}
done &lt; /k8s-hardway/machines.txt</code></pre>
<p>만약 해당 작업이 실패할 경우 jumpbox의 <code>/root/.ssh/id_rsa.pub</code> 파일 내용을 각 서버의 <code>/root/.ssh/authorized_keys</code> 파일에 복사하시면 됩니다.</p>
<p><code>.ssh</code> 디렉터리도 없으면 <code>mkdir /root/.ssh &amp;&amp; chmod 700 /root/.ssh</code> 를 실행하시면 됩니다.</p>
<p>정상적으로 SSH public key가 추가 됐다면, 잘 동작하는지 확인해봅시다.</p>
<pre><code class="language-go">while read IP FQDN HOST SUBNET; do
  ssh -n root@${IP} uname -o -m
done &lt; /k8s-hardway/machines.txt</code></pre>
<pre><code class="language-go">x86_64 GNU/Linux
x86_64 GNU/Linux
x86_64 GNU/Linux</code></pre>
<h3 id="hostnames">Hostnames</h3>
<hr>
<p>이번 섹션에는 <code>controlplane-1</code>, <code>node-1</code>, <code>node-2</code> 서버에 대한 host name을 설정합니다.</p>
<p>hostname은 <code>jumpbox</code> 서버에서 각 서버마다 명령어를 실행할 때 사용될 것입니다.</p>
<p>그리고 hostname은 Kubernetes Cluster에 중요한 역할을 하며, Kubernetes API 서버에 명령을 실행하기 위해 IP 주소말고 <code>controlplane-1</code> 의 hostname으로 사용할 것입니다.</p>
<pre><code class="language-go">while read IP FQDN HOST SUBNET; do 
    CMD=&quot;sed -i &#39;s/^127.0.0.1.*/127.0.0.1\t${FQDN} ${HOST}/&#39; /etc/hosts&quot;
    ssh -n root@${IP} &quot;$CMD&quot;
    ssh -n root@${IP} hostnamectl hostname ${HOST}
done &lt; /k8s-hardway/machines.txt</code></pre>
<p>정상적으로 잘 설정 됐는지 확인해봅니다.</p>
<pre><code class="language-go">while read IP FQDN HOST SUBNET; do
  ssh -n root@${IP} hostname --fqdn
done &lt; /k8s-hardway/machines.txt</code></pre>
<pre><code class="language-go">controlplane-1.kubernetes.local
node-1.kubernetes.local
node-2.kubernetes.local</code></pre>
<p>해당 작업이 안될 경우 각 서버에 접근하여 <code>/etc/hosts</code> 파일을 다음과 깉이 수정하셔도 됩니다.</p>
<pre><code class="language-go">cat /etc/hosts
127.0.0.1    node-1.kubernetes.local node-1</code></pre>
<h3 id="dns">DNS</h3>
<hr>
<p>이번 섹션에는 <code>jumpbox</code> 서버의 <code>/etc/hosts</code> 파일과 <code>controlplane-1</code>, <code>node-1</code>, <code>node-2</code>  서버의 <code>/etc/hosts</code> 파일에 추가될 DNS <code>hosts</code> 파일을 생성할 것입니다.</p>
<p>새로운 <code>hosts</code> 파일을 생성하고 헤더를 추가하여 추가되는 서버를 식별합니다.</p>
<pre><code class="language-go">echo &quot;&quot; &gt; /k8s-hardway/hosts
echo &quot;# Kubernetes The Hard Way&quot; &gt;&gt; /k8s-hardway/hosts</code></pre>
<p>machines.txt 파일의 각 서버에 대한 DNS entry를 생성하고 hosts 파일에 추가합니다.</p>
<pre><code class="language-go">while read IP FQDN HOST SUBNET; do 
    ENTRY=&quot;${IP} ${FQDN} ${HOST}&quot;
    echo $ENTRY &gt;&gt; /k8s-hardway/hosts
done &lt; /k8s-hardway/machines.txt</code></pre>
<p>hosts 파일에 DNS entry가 잘 추가됐는지 확인해봅니다.</p>
<pre><code class="language-go">cat /k8s-hardway/host</code></pre>
<pre><code class="language-go">
# Kubernetes The Hard Way
10.0.35.207 controlplane-1.kubernetes.local controlplane-1
10.0.34.93 node-1.kubernetes.local node-1
10.0.32.237 node-2.kubernetes.local node-2</code></pre>
<h3 id="adding-dns-entries-to-a-local-machine">Adding DNS Entries To A Local Machine</h3>
<hr>
<p>이번 섹션에는 앞에서 생성한 <code>hosts</code> 파일을 <code>jumpbox</code> 서버의 <code>/etc/hosts</code> 파일에 추가합니다.</p>
<p> hosts에 존재하는 DNS entry를 <code>/etc/hosts</code> 파일에 추가합니다.</p>
<pre><code class="language-go">cat /k8s-hardway/hosts &gt;&gt; /etc/hosts</code></pre>
<p> <code>/etc/hosts</code> 파일이 업데이트 됐는지 확인해봅니다.</p>
<pre><code class="language-go">cat /etc/hosts
127.0.0.1 localhost

# The following lines are desirable for IPv6 capable hosts
::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
ff02::3 ip6-allhosts

# Kubernetes The Hard Way
10.0.35.207 controlplane-1.kubernetes.local controlplane-1
10.0.34.93 node-1.kubernetes.local node-1
10.0.32.237 node-2.kubernetes.local node-2</code></pre>
<p>이제 hostname을 사용하여 <code>/k8s-hardway/machines.txt</code> 파일에 나열된 각 서버에 SSH로 접근할 수 있어야합니다.</p>
<pre><code class="language-go">for host in controlplane-1 node-1 node-2
   do ssh root@${host} uname -o -m -n
done</code></pre>
<pre><code class="language-go">controlplane-1 x86_64 GNU/Linux
node-1 x86_64 GNU/Linux
node-2 x86_64 GNU/Linux</code></pre>
<h3 id="adding-dns-entries-to-the-remote-machines">Adding DNS Entries To The Remote Machines</h3>
<hr>
<p><code>jumpbox</code> 서버에서 <code>/etc/hosts</code> 파일에 DNS Entry를 추가한 작업을 각 서버마다 동일하게 작업해줍니다.</p>
<p><code>hosts</code> 파일을 각 서버에 복사하고 해당 내용을 <code>/etc/hosts</code> 파일에 추가합니다.</p>
<pre><code class="language-go">while read IP FQDN HOST SUBNET; do
  scp hosts root@${HOST}:~/
  ssh -n \
    root@${HOST} &quot;cat hosts &gt;&gt; /etc/hosts&quot;
done &lt; /k8s-hardway/machines.txt</code></pre>
<pre><code class="language-go">hosts                                         100%  171   448.5KB/s   00:00
hosts                                         100%  171    37.4KB/s   00:00
hosts                                         100%  171   381.4KB/s   00:00</code></pre>
<p>정상적으로 적용이 됐는지 확인해봅니다.</p>
<pre><code class="language-go">while read IP FQDN HOST SUBNET; do
  ssh -n \
    root@${HOST} &quot;cat /etc/hosts&quot;
done &lt; /k8s-hardway/machines.txt</code></pre>
<p>이제는 <code>jumpbox</code> 서버 뿐만 아니라 Kubernetes Cluster의 3개 서버 중 어느 서버에서 연결할 때 IP 주소 대신 hostname을 사용하여 연결할 수 있습니다.</p>
<p>Next: <a href="https://velog.io/@dan-te/04-certificate-authority">Provisioning the CA and Generating TLS Certificates</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[02-Setting up the Jumpbox]]></title>
            <link>https://velog.io/@dan-te/02-Setting-up-the-Jumpbox</link>
            <guid>https://velog.io/@dan-te/02-Setting-up-the-Jumpbox</guid>
            <pubDate>Sun, 02 Jun 2024 08:20:31 GMT</pubDate>
            <description><![CDATA[<h3 id="set-up-the-jumpbox">Set Up The Jumpbox</h3>
<hr>
<p>해당 Lab에선 jumpbox 서버를 kubernetes 구성에 사용할 명령어를 실행하는데 사용됩니다.</p>
<p>Jumpbox 서버에서 kubernetes cluster를 처음부터 끝까지 설정한다고 생각하시면 됩니다.</p>
<h3 id="install-command-line-utilities">Install Command Line Utilities</h3>
<hr>
<pre><code class="language-go">ssh root@jumpbox</code></pre>
<p>Jumpbox로 접근해서 root 계정으로 명령어를 실행 할 것이며, 명령어를 실행할 때 마다 sudo를 안 붙여도 돼서 편리하기도 합니다.</p>
<p>이제 jumpbox로 로그인을 완료했으면, kubernetes cluster 구성에 필요한 전반적인 유틸리티 툴들을 설치 하고자 합니다.</p>
<pre><code class="language-go">apt-get install -y wget curl vim openssl

# 몇몇 툴들은 이미 설치되어있을 수 있지만, 있을 경우 실행해도 큰 지장은 없습니다.
# 최신 버전이 아닐 경우 패키지 업데이트가 될 수 있습니다.</code></pre>
<p>kubernetes cluster를 구성할 필요 컴포넌트를 다운로드합니다.</p>
<pre><code class="language-go">{
    mkdir -p /k8s-hardway/downloads
    cd /k8s-hardway/downloads

    # Download the components
    # cni plugin
    wget https://github.com/containernetworking/plugins/releases/download/v1.5.0/cni-plugins-linux-amd64-v1.5.0.tgz
    # contaienrd
    wget https://github.com/containerd/containerd/releases/download/v1.7.14/containerd-1.7.14-linux-amd64.tar.gz
    # crictl
    wget https://github.com/kubernetes-sigs/cri-tools/releases/download/v1.30.0/crictl-v1.30.0-linux-amd64.tar.gz
    # runc
    wget https://github.com/opencontainers/runc/releases/download/v1.1.12/runc.amd64
    # etcd
    wget https://github.com/etcd-io/etcd/releases/download/v3.5.13/etcd-v3.5.13-linux-amd64.tar.gz


    # kube-apiserver
    wget https://dl.k8s.io/v1.30.1/bin/linux/amd64/kube-apiserver
    # kube-controller-manager
  wget https://dl.k8s.io/v1.30.1/bin/linux/amd64/kube-controller-manager
    # kube-scheduler
    wget https://dl.k8s.io/v1.30.1/bin/linux/amd64/kube-scheduler
    # kube-proxy
    wget https://dl.k8s.io/v1.30.1/bin/linux/amd64/kube-proxy
    # kubelet
    wget https://dl.k8s.io/v1.30.1/bin/linux/amd64/kubelet
    # kubectl
    wget https://dl.k8s.io/v1.30.1/bin/linux/amd64/kubectl
}

# ls -loh
-- 파일 확인 -- 
total 611M
-rw-r--r-- 1 root  46M May 20 07:23 cni-plugins-linux-amd64-v1.5.0.tgz
-rw-r--r-- 1 root  46M Mar 11 15:23 containerd-1.7.14-linux-amd64.tar.gz
-rw-r--r-- 1 root  25M Apr 18 08:31 crictl-v1.30.0-linux-amd64.tar.gz
-rw-r--r-- 1 root  20M Mar 29 18:47 etcd-v3.5.13-linux-amd64.tar.gz
-rw-r--r-- 1 root 108M May 15 07:01 kube-apiserver
-rw-r--r-- 1 root 103M May 15 07:01 kube-controller-manager
-rw-r--r-- 1 root  55M May 15 07:01 kube-proxy
-rw-r--r-- 1 root  56M May 15 07:01 kube-scheduler
-rw-r--r-- 1 root  50M May 15 07:01 kubectl
-rw-r--r-- 1 root  96M May 15 07:01 kubelet
-rw-r--r-- 1 root  11M Jan 23 13:16 runc.amd64</code></pre>
<p>kubernetes 관련 컴포넌트들은 <a href="https://kubernetes.io/releases/download/">https://kubernetes.io/releases/download/</a> 공식 사이트 통해서 확인하실 수 있습니다.</p>
<h3 id="install-kubectl">Install kubectl</h3>
<hr>
<p>jumpbox 서버에서 kubernetes client 도구인 kubectl를 설치합니다.</p>
<p>튜토리얼 뒤에 kubernetes cluster가 구성되면, kubectl 도구는 kubernetes controlplane과 통신하는데 사용됩니다.</p>
<pre><code class="language-go">{
  cd /k8s-hardway
  chmod +x downloads/kubectl
  cp downloads/kubectl /usr/local/bin/
}</code></pre>
<pre><code class="language-go">kubectl version --client
Client Version: v1.30.1
Kustomize Version: v5.0.4-0.20230601165947-6ce0bf390ce3</code></pre>
<p>kubectl이 정상적으로 동작하는지 확인해 보았습니다.</p>
<p>이번 섹션은 kubernetes cluster를 구성하는데 있어 필요한 컴포넌트들을 준비한 섹션이였습니다.</p>
<p>Next: <a href="https://velog.io/@dan-te/03-compute-resources">Provisioning Compute Resources</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[01-prerequisites]]></title>
            <link>https://velog.io/@dan-te/01-prerequisites</link>
            <guid>https://velog.io/@dan-te/01-prerequisites</guid>
            <pubDate>Sun, 02 Jun 2024 08:18:43 GMT</pubDate>
            <description><![CDATA[<h3 id="사전-준비">사전 준비</h3>
<hr>
<p>jumpbox 1대, kubernetes control-plane 1대 그리고 Worker node 2대를 준비해 kubernetes cluster 구성을 할 예정입니다.</p>
<p>아래 서버들은 어디에 구성을 하든 통신만 가능하다면 문제는 없습니다.</p>
<p>(단 aws같은 퍼블릭 클라우드의 경우 <strong><code>source/destination checks</code></strong>를 비활성화 해야 pod 간 통신이 문제없이 되실 겁니다.)</p>
<p><a href="https://docs.aws.amazon.com/vpc/latest/userguide/VPC_NAT_Instance.html#EIP_Disable_SrcDestCheck">https://docs.aws.amazon.com/vpc/latest/userguide/VPC_NAT_Instance.html#EIP_Disable_SrcDestCheck</a> </p>
<table>
<thead>
<tr>
<th>Name</th>
<th>OS</th>
<th>IP</th>
<th>spec</th>
<th>description</th>
</tr>
</thead>
<tbody><tr>
<td>jumpbox</td>
<td>Ubuntu 22.04</td>
<td>10.0.35.177</td>
<td>4core, 8GB, 50GB</td>
<td>kubernetes 관리</td>
</tr>
<tr>
<td>controlplane-1</td>
<td>Ubuntu 22.04</td>
<td>10.0.35.207</td>
<td>4core, 8GB, 50GB</td>
<td>kubernetes controlplane(master)</td>
</tr>
<tr>
<td>node-1</td>
<td>Ubuntu 22.04</td>
<td>10.0.34.93</td>
<td>4core, 8GB, 50GB</td>
<td>kubernetes worker node</td>
</tr>
<tr>
<td>node-2</td>
<td>Ubuntu 22.04</td>
<td>10.0.32.237</td>
<td>4core, 8GB, 50GB</td>
<td>kubernetes woker node</td>
</tr>
</tbody></table>
<p>Next: <a href="https://velog.io/@dan-te/02-Setting-up-the-Jumpbox">Setting up the Jumpbox</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[00-kubernetes the hard way 소개]]></title>
            <link>https://velog.io/@dan-te/00-kubernetes-the-hard-way-%EC%86%8C%EA%B0%9C</link>
            <guid>https://velog.io/@dan-te/00-kubernetes-the-hard-way-%EC%86%8C%EA%B0%9C</guid>
            <pubDate>Sun, 02 Jun 2024 08:17:46 GMT</pubDate>
            <description><![CDATA[<h3 id="개요">개요</h3>
<hr>
<p><a href="https://github.com/kelseyhightower/kubernetes-the-hard-way/">github.com/kelseyhightower/kubernetes-the-hard-way</a></p>
<p>첫 쿠버네티스를 접할 때 kubernetes the hard way를 통해 어떻게 설치하고 작동하는지 알아봤습니다.</p>
<p>kubernetes 1.30 나온 기념으로 복습도 할 겸 다시 정리해보고자 합니다.</p>
<p>kubernetes the hard way는 kubernetes를 어렵게 세팅하는 방법입니다. 자동으로 구성해주는 kubeamd, kubespray 없이 오로지 kubernetes cluster를 구성하는데 있어 각 작업에 대해 이해하는겁니다.</p>
<p>Kubernetes the hard way는 kelseyhightower 님이 작성한 글 기반으로 저만의 내용으로 다시 정리하려고 합니다.</p>
<h3 id="kubernetes-cluster-component">Kubernetes Cluster Component</h3>
<hr>
<ul>
<li>Kubernetes v1.30.1</li>
<li>containerd v1.7.14</li>
<li>cni v1.5.0</li>
<li>etcd v3.5.13</li>
</ul>
<p>위 컴포넌트들을 통해서 kubernetes control-plane 1대, Worker node 2대를 세팅해 진행할 예정입니다.</p>
<table>
<thead>
<tr>
<th>Name</th>
<th>IP</th>
<th>spec</th>
<th>describe</th>
</tr>
</thead>
<tbody><tr>
<td>jumpbox</td>
<td>10.0.35.177</td>
<td>4core, 8GB, 50GB</td>
<td>kubernetes 관리</td>
</tr>
<tr>
<td>controlplane-1</td>
<td>10.0.35.207</td>
<td>4core, 8GB, 50GB</td>
<td>kubernetes controlplane(master)</td>
</tr>
<tr>
<td>node-1</td>
<td>10.0.34.93</td>
<td>4core, 8GB, 50GB</td>
<td>kubernetes worker node</td>
</tr>
<tr>
<td>node-2</td>
<td>10.0.32.237</td>
<td>4core, 8GB, 50GB</td>
<td>kubernetes woker node</td>
</tr>
</tbody></table>
<p>다른분들도 참고해서 kubernetes the hard way를 따라 해보고 싶으시면, kubernetes 최소 스펙으로 진행 하셔도 지장은 없습니다. 특히 같은 네트워크 대역에 진행하면 좀 더 수월하실 겁니다.</p>
<h3 id="labs">Labs</h3>
<hr>
<p>Lab 순서는 깃헙 게시글과 동일하게 진행 될 예정입니다.</p>
<ul>
<li><a href="https://velog.io/@dan-te/01-prerequisites">Prerequisites</a></li>
<li><a href="https://velog.io/@dan-te/02-Setting-up-the-Jumpbox">Setting up the Jumpbox</a></li>
<li><a href="https://velog.io/@dan-te/03-compute-resources">Provisioning Compute Resources</a></li>
<li><a href="https://velog.io/@dan-te/04-certificate-authority">Provisioning the CA and Generating TLS Certificates</a></li>
<li><a href="https://velog.io/@dan-te/05-kubernetes-configuration-files">Generating Kubernetes Configuration Files for Authentication</a></li>
<li><a href="https://velog.io/@dan-te/06-data-encryption-keys">Generating the Data Encryption Config and Key</a></li>
<li><a href="https://velog.io/@dan-te/07-bootstrapping-etcd">Bootstrapping the etcd Cluster</a></li>
<li><a href="https://velog.io/@dan-te/08-bootstrapping-kubernetes-controllers">Bootstrapping the Kubernetes Control Plane</a></li>
<li><a href="https://velog.io/@dan-te/09-bootstrapping-kubernetes-workers">Bootstrapping the Kubernetes Worker Nodes</a></li>
<li><a href="https://velog.io/@dan-te/10-configuring-kubectl">Configuring kubectl for Remote Access</a></li>
<li><a href="https://velog.io/@dan-te/11-pod-network-routes">Provisioning Pod Network Routes</a></li>
<li><a href="https://velog.io/@dan-te/12-smoke-test">Smoke Test</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[kind] MacBook m1에 kuernetes 설치해보기]]></title>
            <link>https://velog.io/@dan-te/kind-MacBook-m1%EC%97%90-kuernetes-%EC%84%A4%EC%B9%98%ED%95%B4%EB%B3%B4%EA%B8%B0</link>
            <guid>https://velog.io/@dan-te/kind-MacBook-m1%EC%97%90-kuernetes-%EC%84%A4%EC%B9%98%ED%95%B4%EB%B3%B4%EA%B8%B0</guid>
            <pubDate>Sat, 25 Nov 2023 06:36:15 GMT</pubDate>
            <description><![CDATA[<h3 id="kind-설치">Kind 설치</h3>
<p>Kubernetes 공부용으로 Kubernetes를 어디에 설치해야할지 난감하다면, minikube, k3s, kind를 사용해서 간단하게 Kubernetes를 구축할 수 있다.</p>
<p>본 글에서는 Kind를 이용하여 간단하게 Kubernetes를 구축 해 보고자 한다.
<a href="https://kind.sigs.k8s.io/">Kind 공식 사이트</a></p>
<p>Kind를 설치하기 전에 go, docker 또는 podman이 있어야 하는데 없는 경우 아래 명령어로 설치 후
Kind를 설치하면 된다.</p>
<pre><code>brew install docker
brew install go</code></pre><p>이제 Kind를 설치 해 보자 완전 간단하다.</p>
<pre><code>brew install kind</code></pre><p>이러면 Kind 설치는 끝났고 Kubernetes도 한줄이면 끝난다.</p>
<pre><code>kind create cluster


**# 출력
Creating cluster &quot;kind&quot; ...
 ✓ Ensuring node image (kindest/node:v1.27.3) 🖼
 ✓ Preparing nodes 📦
 ✓ Writing configuration 📜
 ✓ Starting control-plane 🕹️
 ✓ Installing CNI 🔌
 ✓ Installing StorageClass 💾
Set kubectl context to &quot;kind-kind&quot;
You can now use your cluster with:

kubectl cluster-info --context kind-kind</code></pre><h3 id="kubernetes-동작-확인">Kubernetes 동작 확인</h3>
<p>이렇게 Kubernetes 설치는 끝났고, 정상적으로 설치된 것을 확인하려면 <code>kubectl</code> 명령어를 써야하는데 없으면 해당 파일도 설치해야한다.(이미 파일이 있다면 문제없다.)</p>
<pre><code>curl -LO &quot;https://dl.k8s.io/release/v1.27.3/bin/linux/arm64/kubectl&quot;
chmod u+x kubectl #실행권한 추가
mv kubectl /usr/local/bin/kubectl #kubectl 파일 위치 변경</code></pre><p>Kind로 설치한 Kubernetes 버전이 <code>v1.27.3</code>이므로, 해당 버전에 맞게 설치하자.
참고로 마이너 버전이 1정도 차이나는건 괜찮다. 예를 들어 1.26 버전의 kubectl를 설치해도 되고, 1.28을 설치해도 무관하다.
<code>kubectl version</code> 으로 현재 kubectl(client) 버전과 Kubernetes(server) 간의 버전을 확인할 수 있다.</p>
<pre><code>kubectl cluster-info --context kind-kind</code></pre><p>이후 위 명령어를 실행하면, 아래처럼 결과가 출력된다.</p>
<pre><code>Kubernetes control plane is running at https://127.0.0.1:53824
CoreDNS is running at https://127.0.0.1:53824/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy</code></pre><p>이제 Kubernetes가 정상적으로 동작하는지 확인해보자.</p>
<pre><code>kubectl get node -owide
NAME                 STATUS   ROLES           AGE   VERSION   INTERNAL-IP   EXTERNAL-IP   OS-IMAGE                         KERNEL-VERSION     CONTAINER-RUNTIME
kind-control-plane   Ready    control-plane   35m   v1.27.3   172.18.0.2    &lt;none&gt;        Debian GNU/Linux 11 (bullseye)   5.15.49-linuxkit   containerd://1.7.1</code></pre><p>Kubernetes <code>control-plane</code> 1개가 생성됐다.</p>
<pre><code>kubectl get pod -A -owide
NAMESPACE            NAME                                         READY   STATUS    RESTARTS   AGE   IP           NODE                 NOMINATED NODE   READINESS GATES
kube-system          coredns-5d78c9869d-22kx4                     1/1     Running   0          25s   10.244.0.3   kind-control-plane   &lt;none&gt;           &lt;none&gt;
kube-system          coredns-5d78c9869d-z6jxl                     1/1     Running   0          25s   10.244.0.4   kind-control-plane   &lt;none&gt;           &lt;none&gt;
kube-system          etcd-kind-control-plane                      1/1     Running   0          40s   172.18.0.2   kind-control-plane   &lt;none&gt;           &lt;none&gt;
kube-system          kindnet-7fsx9                                1/1     Running   0          25s   172.18.0.2   kind-control-plane   &lt;none&gt;           &lt;none&gt;
kube-system          kube-apiserver-kind-control-plane            1/1     Running   0          42s   172.18.0.2   kind-control-plane   &lt;none&gt;           &lt;none&gt;
kube-system          kube-controller-manager-kind-control-plane   1/1     Running   0          41s   172.18.0.2   kind-control-plane   &lt;none&gt;           &lt;none&gt;
kube-system          kube-proxy-hdhqm                             1/1     Running   0          25s   172.18.0.2   kind-control-plane   &lt;none&gt;           &lt;none&gt;
kube-system          kube-scheduler-kind-control-plane            1/1     Running   0          42s   172.18.0.2   kind-control-plane   &lt;none&gt;           &lt;none&gt;
local-path-storage   local-path-provisioner-6bc4bddd6b-9p7s8      1/1     Running   0          25s   10.244.0.2   kind-control-plane   &lt;none&gt;           &lt;none&gt;</code></pre><p><code>kube-system</code> 네임스페이스에 coredns, etcd, kube-apiserver, kube-controlloer-manager, kube-scheduler, kube-proxy 그리고 kindnet이 생성됐다.</p>
<pre><code>cat &lt;&lt;EOF &gt;nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 1
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.23
---
apiVersion: v1
kind: Service
metadata:
  name:  nginx-service
spec:
  selector:
    app: nginx
  ports:
  - protocol: TCP
    port: 80
EOF</code></pre><p>이렇게 테스트용으로 Kubernetes에 nginx라는 Pod를 생성해 볼 것이다.</p>
<pre><code>kubectl apply -f nginx.yaml

# 출력
deployment.apps/nginx created
service/nginx-service created</code></pre><p>이러면 <code>default</code> 네임스페이스에 deployment와 service에 리소스들이 생성이 되었고,</p>
<pre><code>kubectl get all
NAME                         READY   STATUS    RESTARTS   AGE
pod/nginx-76478fbd9f-wpv2r   1/1     Running   0          12s

NAME                    TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
service/kubernetes      ClusterIP   10.96.0.1      &lt;none&gt;        443/TCP   9m3s
service/nginx-service   ClusterIP   10.96.75.195   &lt;none&gt;        80/TCP    12s

NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx   1/1     1            1           12s

NAME                               DESIRED   CURRENT   READY   AGE
replicaset.apps/nginx-76478fbd9f   1         1         1       12s</code></pre><p>최종적으로 위와 같이 리소스들이 생성되었다.</p>
<p>그럼 nginx가 정상적으로 동작하는지 확인하려면 웹페이지에 접근해봐야 확인이 가능하니 <code>port-forward</code> 기능을 이용하여 접근해보자.</p>
<pre><code>kubectl port-forward svc/nginx-service 8080:80
Forwarding from 127.0.0.1:8080 -&gt; 80
Forwarding from [::1]:8080 -&gt; 80</code></pre><p>이렇게 포트포워딩을하면 맥북에서 nginx로 접근할 수 있다.
<img src="https://velog.velcdn.com/images/dan-te/post/41f1278f-210e-44ba-bcf8-c24f45bedff7/image.png" alt=""></p>
<p>웹 브라우저에서<code>localhost:8080</code>을 검색하면 위와 같이 nginx 기본 홈페이지 화면이 출력된다.
이로써 Kind를 이용해 Kubernetes 구축 및 확인이 끝났다.</p>
<h3 id="kind-삭제">Kind 삭제</h3>
<p><code>kind delete cluster</code>로 kubernetes를 삭제할 수 있다.</p>
<pre><code>kind delete cluster --name kind
Deleting cluster &quot;kind&quot; ...
Deleted nodes: [&quot;kind-control-plane&quot;]</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[Istio] Istio ingress gateway TCP Keep Alive 설정해보기]]></title>
            <link>https://velog.io/@dan-te/Istio-Istio-ingress-gateway-TCP-Keep-Alive-%EC%84%A4%EC%A0%95%ED%95%B4%EB%B3%B4%EA%B8%B0</link>
            <guid>https://velog.io/@dan-te/Istio-Istio-ingress-gateway-TCP-Keep-Alive-%EC%84%A4%EC%A0%95%ED%95%B4%EB%B3%B4%EA%B8%B0</guid>
            <pubDate>Mon, 20 Nov 2023 15:07:00 GMT</pubDate>
            <description><![CDATA[<h3 id="들어가기-앞서">들어가기 앞서</h3>
<p>Keep Alive  대해 알아보자, Keep Alive의 네이버 기준 사전적 의미는 &quot;살아 있다&quot; 또는 &quot;꺼지지 않게 하다&quot; 라는 의미를 가지고 있다.</p>
<h3 id="그럼-keep-alive는-왜-쓸까">그럼 Keep Alive는 왜 쓸까?</h3>
<p>보통은 Client와 Server 간의 통신을 <code>유지</code> 하려고 keep alive를 적용한다.
<img src="https://velog.velcdn.com/images/dan-te/post/24c3816f-c8a3-4720-a3b8-bcce2b605ce6/image.png" alt=""></p>
<p>위 그림 처럼 Client에서 Server로 데이터 요청을할 때 처리 시간이 약 1분 이상 소요되고 있다면, 해당 연결을 끊거나 유지를 해야 할 필요가 있다.
연결이 강제로 끊긴다면? - 사용자가 요청한 데이터에 대해 원하는 결과를 얻지 못 할 수 있다.
연결을 유지 한다면? - 사용자가 요청한 데이터에 대해 원하는 결과를 얻을 수 있다.</p>
<p>만약 사용자가 요청한 데이터가 오래 걸린다면, Keep Alive를 이용해 Client와 Server간의 연결이 유효한지 계속 확인을 하면서 연결이 끊어지지 않게 요청한 데이터를 응답할 수 있도록 할 수 있다.
<img src="https://velog.velcdn.com/images/dan-te/post/52eaf51f-b98d-49c9-a189-23052fe71999/image.png" alt=""></p>
<p>이렇게 Wireshark 도구를 사용해 Keep Alive를 통해 TCP 통신이 유지되는 것을 확인할 수 있다.
Keep Alive는 Client가 Server로 또는 Server가 Client로 <code>TCP Keep Alive</code> Packet를 보내서, 이에 대한 <code>Ack</code> 응답이 오면 정상, 응답이 안오면 몇 번 재시도 후 해당 연결을 끊는다.</p>
<pre><code>sudo sysctl -a | grep keepalive
net.ipv4.tcp_keepalive_intvl = 10
net.ipv4.tcp_keepalive_probes = 3
net.ipv4.tcp_keepalive_time = 60</code></pre><p>리눅스 시스템 환경에서는 Keep Alive에 대한 커널 파라미터가 기본적으로 설정이 되어있고, 각 운영체제마다 약간 상이하다.
리눅스 Keep Alive에 대한 커널 파라미터 설명은 <a href="https://tldp.org/HOWTO/TCP-Keepalive-HOWTO/usingkeepalive.html">링크</a> 에서 확인이 가능하다.</p>
<h3 id="istio-ingress-gateway-keep-alive-적용-검토">Istio ingress gateway Keep Alive 적용 검토</h3>
<p>결론은 이걸 왜 적용을 했냐면, Client가 Server로 10분 이상 소요되는 API 호출할 때마다 자꾸 5분 이내로 연결이 종료되는 문제가 있어 Istio ingress gateway에 <code>Envoy Filter</code>를 적용하여 해결을 하였다.</p>
<p>통신 흐름은 <code>Client -&gt; Loadbalance -&gt; Istio ingress gateway -&gt; Service Application</code> 이러한 흐름으로 통신을 하고 있었다. 
<img src="https://velog.velcdn.com/images/dan-te/post/c0dc602c-e0ee-4943-8a20-3551e7e1dcdb/image.png" alt="">
대강 보면, 15시 2분에 HTTP POST 요청을 받고 5분 뒤인 15시 7분에 연결이 종료됐다.
Client가 TCP 헤더 플래그에 <code>FIN, ACK</code> 설정하여 Server한테 연결 종료 
요청을 한 것 이다.</p>
<p>도대체 왜? 라는 생각에 Istio ingress gateway가 올라간 노드에서 <code>tcpdump</code> 도구를 통해 패킷 캡처를 진행했다.
<img src="https://velog.velcdn.com/images/dan-te/post/486ea4de-59dc-4345-a740-b3937dd6653a/image.png" alt=""></p>
<p>뭔가 이상한 느낌이 들었다. 이건 뭔지..?
<img src="https://velog.velcdn.com/images/dan-te/post/71c79b66-6405-4145-865b-90ce71d0dc5f/image.png" alt=""></p>
<p>Istio ingress gateway에서 패킷 덤프를 뜬 결과를 보고 머리가 복잡해졌다.
Istio ingress gateway로 트래픽이 들어오면, <code>virtual service</code>에 정의 된 Service로 전달을 해주는 역할이라고 이해하고 있었다.</p>
<p>하지만, 해당 어플리케이션의 Sidecar인 <code>istio-proxy</code> 컨테이너가 Istio ingress gateway의 <code>TCP 8080 Port</code>로 <code>3-way-handshake</code> 요청을 하고, Client가 보낸 HTTP POST 요청을 보냈다.
이 후 Istio ingress gateway는 해당 어플리케이션에 <code>3-way-handshake</code> 요청을 하고, Client가 보낸 HTTP POST 요청을 보냈다.
<img src="https://velog.velcdn.com/images/dan-te/post/0b81c5d0-2a43-4a7e-a106-a05be7ee8e82/image.png" alt=""></p>
<p>대략 흐름을 표현하면 이렇고
<img src="https://velog.velcdn.com/images/dan-te/post/31917d56-1f9c-4481-83cd-d9cb58f55e1d/image.png" alt="">
와이어샤크를 통해 합쳐서 보면 이렇다.
(해당 패킷 플로우를 보면, 10.233.121.64는 어플리케이션이 올라간 노드의 vxlan IP이고, 10.233.91.53은 Istio ingress gateway의 아이피이다. 
왜 istio-proxy sidecar 컨테이너의 아이피가 아니라 vxlan IP인지 아직도 생각중이다. 과연 istio-proxy일까..? 
istio 심화 내용은 <a href="https://www.notion.so/gasidaseo/Istio-Life-of-a-packet-6ad9808e14594296bf854dcc203cab71?pvs=4">여기서</a> 다시 보자)
무튼, 누가 통신을 끊는지 알겠고 이 사이에 <code>Keep Alive</code>를 적용하면, 10분 이상 소요되는 API 호출할 때 10분 뒤에 정상적으로 응답을 받을 수 있겠구나 라고 생각했다.</p>
<h3 id="적용-하기-전에">적용 하기 전에!</h3>
<p>Istio ingress gateway의 EnvoyFilter에 Keep Alive를 적용하기 전에 몇몇 테스트를 해 보았다.</p>
<pre><code>apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
spec:
  gateways:
    - istio-system/istio-gw
  hosts:
    - test.test.com
  http:
      name: service-application
      route:
        - destination:
            host: service-application
            port:
              number: 8087
       timeout: 10s</code></pre><p><code>Virtual Service</code>에 timeout을 적용하면 어떻게 될까 궁금했다.
<img src="https://velog.velcdn.com/images/dan-te/post/30f91e9a-983b-46e2-b9df-a43394a05593/image.png" alt="">
<code>time curl -X POST test.test.com/~~~</code> 이렇게 테스트 해보니 10초되자 마자 <code>504 Gateway Timeout</code> 메시지를 받았다.
Virtual Service에 시간을 아무리 오래 줘도 어차피 5분 뒤에 끊기는건 동일하다고 생각했다.</p>
<pre><code>apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
spec:
  host: service-application
  subsets:
    - labels:
        app: service-application
      name: service-application
  trafficPolicy:
    connectionPool:
      tcp:
        connectTimeout: 30ms
        tcpKeepalive:
          interval: 75s
          time: 3600s
    tls:
      mode: DISABLE</code></pre><p><code>Destination Rule</code>에 Keep Alive를 적용하면 어떻게 될까 궁금했다.
하지만, Keep Alive 패킷을 볼 수 없었다.</p>
<h3 id="istio-ingress-gateway-keep-alive-적용하기">Istio ingress gateway Keep Alive 적용하기</h3>
<p>돌고돌아 Istio ingress gateway에 Keep Alive를 적용해야했다. 하지만, 어떻게 설정을 해야 좋을지 막막했다.
다행히 구글 검색 하다 F5의 글을 볼 수 있었고 여기에 해답이 있었다.
<a href="https://my.f5.com/manage/s/article/K00026550">K00026550: Istio Ingress Gateway TCP keepalive</a>
내용은 Envoyfilter에 Istio ingress proxy 컨테이너가 리눅스 커널 파라미터에 정의 된 Keep Alive를 사용할 수 있게 설정 해줘야 한다는 것 이다.</p>
<pre><code>istioctl dashboard envoy -n istio-system istio-ingressgateway-68fd8758d4-95lrj</code></pre><p>istioctl 도구를 이용해 현재 envoy에 대한 설정을 확인해볼 수 있다.</p>
<pre><code>nsenter -n -t 19495 -- sudo netstat -antp --timer | grep 8080
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      19495/envoy          off (0.00/0/0)
tcp        0      0 10.233.116.242:8080     10.233.115.0:4534       ESTABLISHED 19495/envoy          off (0.00/0/0)</code></pre><p>Envoyfilter 적용 전에 Istio ingress gateway가 올라간 노드에서 istio-ingress의 PID를 찾고, 해당 컨테이너의 network Namespace에 동작하고 있는 envoy 프로세스의 Keep Alive가 <code>off</code>로 되어있는 것을 확인할 수 있다.</p>
<pre><code>apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
spec:
  configPatches:
    - applyTo: LISTENER
      match:
        context: GATEWAY
        listener:
          name: 0.0.0.0_8080
          portNumber: 8080
      patch:
        operation: MERGE
        value:
          socket_options:
            - description: enable keep-alive
              int_value: 1
              level: 1
              name: 9
              state: STATE_PREBIND
            - description: idle time before first keep-alive probe is sent
              int_value: 7
              level: 6
              name: 4
              state: STATE_PREBIND
            - description: keep-alive interval
              int_value: 5
              level: 6
              name: 5
              state: STATE_PREBIND
            - description: keep-alive probes count
              int_value: 2
              level: 6
              name: 6
              state: STATE_PREBIND</code></pre><p>Envoyfilter 적용 후 Istio ingress gateway Pod를 재시작 해야한다.</p>
<p>해당 설정은 istio-ingress의 HTTP 프로토콜 통신에 설정에 적용이 된다.
만약 istio-ingress에서 HTTPS 프로토콜 통신일 경우 8080이 아닌 8443으로 설정을 해야한다.</p>
<pre><code>istioctl dashboard envoy -n istio-system istio-ingressgateway-546cc9d9f6-6wzt9

OR

istioctl pc listener -n istio-system istio-ingressgateway-546cc9d9f6-6wzt9 --port 8080 -oyaml</code></pre><p>다시 istioctl 도구를 이용해 Istio ingress gateway에 Envoyfilter가 적용됐는지 확인한다.</p>
<pre><code>       &quot;socket_options&quot;: [
        {
         &quot;description&quot;: &quot;enable keep-alive&quot;,
         &quot;level&quot;: &quot;1&quot;,
         &quot;name&quot;: &quot;9&quot;,
         &quot;int_value&quot;: &quot;1&quot;
        },
        {
         &quot;description&quot;: &quot;idle time before first keep-alive probe is sent&quot;,
         &quot;level&quot;: &quot;6&quot;,
         &quot;name&quot;: &quot;4&quot;,
         &quot;int_value&quot;: &quot;7&quot;
        },
        {
         &quot;description&quot;: &quot;keep-alive interval&quot;,
         &quot;level&quot;: &quot;6&quot;,
         &quot;name&quot;: &quot;5&quot;,
         &quot;int_value&quot;: &quot;5&quot;
        },
        {
         &quot;description&quot;: &quot;keep-alive probes count&quot;,
         &quot;level&quot;: &quot;6&quot;,
         &quot;name&quot;: &quot;6&quot;,
         &quot;int_value&quot;: &quot;2&quot;
        }
       ],</code></pre><p>이렇게 Keep Alive가 정상적으로 적용 됐고,</p>
<pre><code>netstat -antp --timer | grep 8080 | grep keep
tcp        0      0 10.233.121.77:8080      10.233.91.0:23687       ESTABLISHED 19/envoy             keepalive (1.46/0/0)
tcp        0      0 10.233.121.77:8080      10.233.90.192:19032     ESTABLISHED 19/envoy             keepalive (3.07/0/0)</code></pre><p>Istio ingress gateway의 envoy 프로세스 또한 Keep Alive time이 표출되고 있다.</p>
<h3 id="확인">확인</h3>
<p><img src="https://velog.velcdn.com/images/dan-te/post/7029812c-a436-4deb-8fcd-bbefb50f741f/image.png" alt=""><code>22:53:03</code> 에 Client는 Server로 10분이 걸리는 API를 보내고,<img src="https://velog.velcdn.com/images/dan-te/post/c219cf99-feda-4776-9f2d-51e09e121212/image.png" alt="">중간중간에 TCP Keep Alive 패킷을 보내면서 양간의 통신 상태가 정상인지 확인하며, 
<img src="https://velog.velcdn.com/images/dan-te/post/b309083a-0c88-4344-8da6-0b06aee02cc2/image.png" alt="">마침내, 10분 뒤에 Server로 부터 응답을 받을 수 있게되었다.</p>
<h3 id="참조-링크">참조 링크</h3>
<ul>
<li><a href="https://my.f5.com/manage/s/article/K00026550">https://my.f5.com/manage/s/article/K00026550</a></li>
<li><a href="https://istio.io/latest/docs/reference/config/networking/envoy-filter/">https://istio.io/latest/docs/reference/config/networking/envoy-filter/</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIP] Kubernetes에 Powershell pod 생성하기]]></title>
            <link>https://velog.io/@dan-te/TIPS-Kubernetes%EC%97%90-Powershell-pod-%EC%83%9D%EC%84%B1%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@dan-te/TIPS-Kubernetes%EC%97%90-Powershell-pod-%EC%83%9D%EC%84%B1%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 02 Nov 2023 13:06:02 GMT</pubDate>
            <description><![CDATA[<p>작년 10월에 스택오버플로우에서 흥미로운 질문 글을 보았다.
Kubernetes에 Windows Powershell pod를 띄어보는거 였는데, 작성자님은 pod를 생성하면 계속 <code>CrashLoopBackOff</code>이 발생한다고 해서 도움을 받기 위해 stackoverflow에 글을 올리셨다.</p>
<p><a href="https://stackoverflow.com/questions/74054955/powershell-pod-failing-in-kubernetes-cluster">(powershell pod failing in kubernetes cluster)
</a>
흔히 사람들이 <code>busybox</code> pod를 많이 사용하는데, 해당 pod를 생성할 때 <code>command</code> 에 sleep 명령어를 추가하여 생성한다.
powershell도 비슷한 개념으로 pod를 생성하면 <code>Running</code> 상태로 유지할 것 같아 이 내용을 참고하여 답변을 달았다.</p>
<h3 id="create-powershell-pod">Create Powershell pod</h3>
<pre><code>apiVersion: v1
kind: Pod
metadata:
  name: powershell
spec:
  containers:
  - name: powershell
    image: mcr.microsoft.com/powershell:latest
    command: [&quot;pwsh&quot;]
    args: [&quot;-Command&quot;, &quot;Start-Sleep&quot;, &quot;3600&quot;]
</code></pre><h3 id="run-powershell-pod">Run powershell pod</h3>
<pre><code>[root@master1 ~]# kubectl get pod powershell
NAME         READY   STATUS    RESTARTS   AGE
powershell   1/1     Running   0          3m32s
[root@master1 ~]# kubectl exec -it powershell -- pwsh
PowerShell 7.2.6
Copyright (c) Microsoft Corporation.

https://aka.ms/powershell
Type &#39;help&#39; to get help.

PS /&gt; date
Thu Oct 13 12:50:24 PM UTC 2022
PS /&gt;</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[TIP] Istio Operator Install 설정 팁]]></title>
            <link>https://velog.io/@dan-te/tip-Istio-Operator-Install-%EC%84%A4%EC%A0%95-%ED%8C%81</link>
            <guid>https://velog.io/@dan-te/tip-Istio-Operator-Install-%EC%84%A4%EC%A0%95-%ED%8C%81</guid>
            <pubDate>Tue, 08 Aug 2023 02:22:42 GMT</pubDate>
            <description><![CDATA[<p><a href="https://istio.io/latest/docs/setup/install/operator/">https://istio.io/latest/docs/setup/install/operator/</a></p>
<p>해당 istio 공식문서 가이드에 따라 istio를 설치 할 경우 istio는 잘 설치 되나 특정 요구사항을 충족시키기엔 좀 어렵다.</p>
<p>필자의 경우 특정 노드에 배포 하고 싶거나 ingress-gateway pod를 2개 이상 배포하고 싶었는데 어떻게 설정을 했는지 공유하고자 한다.</p>
<p>아래 설정코드는 istioctl 명령어로 istio operator를 사용하여 istio를 설치하는 코드인데 기본값으로 설정 할 경우 ingress-gateway pod나 istiod 배포 시 HAP resource도 같이 배포가 되어 deployment resource에서 replicas 사이즈를 조정을 해도 다시 롤백이 되는 현상이 발생한다.
해당 이슈는 <code>autoscaleEnabled</code> 값을 비활성화 하여 해결할 수 있다.</p>
<p>추가로 nodeSelector를 통해 특정 노드에 pod를 생성하도록 지정할 수 있다.</p>
<pre><code>apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
  namespace: istio-system
spec:
  tag: 1.16.1
  components: 
    # Istio Gateway feature
    ingressGateways:
    - name: istio-ingressgateway
      enabled: true
      k8s:
        replicaCount: 3
        nodeSelector:
          node-role.kubernetes.io/ingress: &quot;true&quot;
    pilot:
      k8s:
        replicaCount: 1
        nodeSelector:
          node-role.kubernetes.io/ingress: &quot;true&quot;
        hpaSpec:
          minReplicas: 1
          maxReplicas: 1
  values:
    global:
      defaultNodeSelector:
        node-role.kubernetes.io/ingress: &quot;true&quot;
    base:
      enableCRDTemplates: false
      validationURL: &#39;&#39;
    defaultRevision: &#39;&#39;
    gateways:
      istio-ingressgateway:
        autoscaleEnabled: false # when it sets &quot;true&quot;, crate HPA resource 
        env: {}
        name: istio-ingressgateway
        replicaCount: 3
        secretVolumes:
          - mountPath: /etc/istio/ingressgateway-certs
            name: ingressgateway-certs
            secretName: istio-ingressgateway-certs
          - mountPath: /etc/istio/ingressgateway-ca-certs
            name: ingressgateway-ca-certs
            secretName: istio-ingressgateway-ca-certs
        type: NodePort</code></pre><h3 id="설치-및-삭제-방법">설치 및 삭제 방법</h3>
<pre><code>
# 설치
istioctl_v1.16.1 install --set profile=default -f ./istio_v1.16.1.yaml

# 삭제(istio 관련 리소스들이 다 삭제되니 주의 필요)
istioctl_v1.16.1 uninstall --purge   </code></pre><h3 id="istio-hpa-관련-내용">istio hpa 관련 내용</h3>
<p>istio operator로 설치하면 기본적으로 <code>autoscaleEnabled</code>이 활성화되어 있는데, 위에서 언급한 것 처럼 deployment에서 replicas를 조정하면 다시 원복되는 현상이 발생한다.
<code>kube-controller-manager</code> pod에서 관련 로그를 확인할 수 있다.</p>
<pre><code># kube-controller-manager 로그
&gt; I0426 00:02:34.426771       1 event.go:294] &quot;Event occurred&quot; object=&quot;istio-system/istio-ingressgateway&quot; 
fieldPath=&quot;&quot; kind=&quot;HorizontalPodAutoscaler&quot; apiVersion=&quot;autoscaling/v2&quot; type=&quot;Normal&quot; 
reason=&quot;SuccessfulRescale&quot; message=&quot;New size: 1; reason: All metrics below target&quot;</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[ETC] TCP 통신 테스트 방법]]></title>
            <link>https://velog.io/@dan-te/ETC-TCP-%ED%86%B5%EC%8B%A0-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@dan-te/ETC-TCP-%ED%86%B5%EC%8B%A0-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Wed, 19 Jul 2023 16:36:22 GMT</pubDate>
            <description><![CDATA[<h3 id="시작">[시작]</h3>
<p>대부분의 사람들은 A지사에서 사용하고 있는 PC1에서 B지사에서 운영중인 Server1로 통신이 원활하게 되는지 확인하려면 PING 프로그램을 이용해서 확인한다. PING 프로그램은 ICMP 프로토콜을 이용하며 ICMP Request(Type-8)를 보내면 ICMP Reply(Type-0)를 전달받고 이 결과로 정상적으로 양방향 통신이 되는 것을 확인할 수 있다.
<img src="https://velog.velcdn.com/images/dan-te/post/17f5b6ce-e3eb-4763-8e2e-1b00095f0d29/image.png" alt=""></p>
<p>하지만, Windows 시스템 경우 기본적으로 내장된 방화벽이 활성화 되어있어 ICMP 통신이 불가하고, 방화벽단에서 ICMP 통신을 Block 하는 경우가 많다. 이런 경우 PING 프로그램을 이용하여 정상적으로 통신이 되는지 확인하기 어렵다.
본 글에서는 ICMP 프로토콜을 이용하는 PING 프로그램이 아닌 TCP 프로토콜을 사용하는 다른 프로그램들을 사용하여 양방향 통신이 원활하게 되는지 확인하고자 한다.</p>
<h3 id="psping---windows-전용">[PsPing - Windows 전용]</h3>
<p>PsPing 프로그램은 Microsoft사에서 제공해주는 프로그램이다. 해당 프로그램을 이용하면 TCP ping, 레이턴시, 대역폭을 확인할 수 있다.
[다운로드 주소: <a href="https://docs.microsoft.com/en-us/sysinternals/downloads/psping%5D">https://docs.microsoft.com/en-us/sysinternals/downloads/psping]</a>
아래 그림과 같이 TCP 프로토콜을 이용하여 양방향 통신이 되는 것을 확인할 수 있다.
<img src="https://velog.velcdn.com/images/dan-te/post/eba2058e-cf6b-42a0-9e1f-93a2a6ad2517/image.png" alt=""></p>
<h3 id="tcping">[tcping]</h3>
<p>tcping도 psping과 같이 TCP 프로토콜을 사용하여 통신 되는 것을 확인할 수 있다.
[다운로드 주소: <a href="https://www.elifulkerson.com/projects/tcping.php%5D">https://www.elifulkerson.com/projects/tcping.php]</a>
아래 그림과 같이 TCP 프로토콜을 이용하여 양방향 통신이 되는 것을 확인할 수 있다. 기본적으로 TCP Port를 지정해주지 않으면, TCP 80 Port이 기본값으로 설정된다.
<img src="https://velog.velcdn.com/images/dan-te/post/02d1ceb5-2e8e-49f9-84f9-1ffcd01a9283/image.png" alt=""></p>
<h3 id="netcat">[netcat]</h3>
<p>netcat(nc)이라는 프로그램도 존재하는데, 해당 프로그램은 바이러스로 인식하는 경우가 있어 Windows 시스템에서 사용하기 어렵다. 해당 프로그램은 Linux 시스템에서 테스트를 진행하고자 한다.
netcat 프로그램에서 Server IP와 Port를 지정해주면 아래와 같이 아무런 결과 없이 유지되는 것을 확인할 수 있다. 통신이 안될 경우 (Ncat: Connection timed out.) 메시지가 출력된다.
<img src="https://velog.velcdn.com/images/dan-te/post/a12295bd-b6fc-4e70-9049-6a34ec5a6282/image.png" alt=""></p>
<p>출력되는 내용을 확인하고 싶으면 아래 그림 같이 명령어를 실행하면 된다.(사실 HTTP 테스트는 curl 명령어로 해도 된다.)
<img src="https://velog.velcdn.com/images/dan-te/post/0859caac-7da0-4d0b-887d-f329823fbd29/image.png" alt=""></p>
<p>netcat 프로그램은 아래와 같이 서버에서 리스닝 할 포트를 지정하고 클라이언트가 해당 포트로 접속하게 할 수 있게 가능하다.
<img src="https://velog.velcdn.com/images/dan-te/post/ff5df599-4372-4ade-a438-dc96937050ee/image.png" alt=""></p>
<h3 id="nmap">[nmap]</h3>
<p>nmap 프로그램은 보통 서버 정보나 Listening되어 있는 Port를 확인하고자 할 때 많이 이용한다. 해당 프로그램은 악의적인 목적으로 많이 사용되므로, 사용하는 것을 권장하지 않는다.
물론, 해당 프로그램도 &quot;netcat&quot;과 같이 Windows 시스템에서는 &quot;Windows Defender&quot;로 인해 차단되지만, Linux 시스템에서는 다운로드 받아서 사용할 수 있다.
아래와 같이 해당 호스트에 대한 open되어 있는 TCP Port를 확인할 수 있다.
<img src="https://velog.velcdn.com/images/dan-te/post/3ebceee5-d32c-4c32-ab25-e8f585175c09/image.png" alt=""></p>
]]></description>
        </item>
    </channel>
</rss>