<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>hyunsu_prog.log</title>
        <link>https://velog.io/</link>
        <description>개발자 스터디 블로그</description>
        <lastBuildDate>Sun, 14 Apr 2024 07:55:43 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>hyunsu_prog.log</title>
            <url>https://velog.velcdn.com/images/hyunsu_prog/profile/00ac5587-0c4c-499e-8bcd-e25c78a05f90/social_profile.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. hyunsu_prog.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/hyunsu_prog" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Kubernetes Custom Scheduler]]></title>
            <link>https://velog.io/@hyunsu_prog/Kubernetes-Custom-Scheduler</link>
            <guid>https://velog.io/@hyunsu_prog/Kubernetes-Custom-Scheduler</guid>
            <pubDate>Sun, 14 Apr 2024 07:55:43 GMT</pubDate>
            <description><![CDATA[<h3 id="scheduler를-개선-방법-5가지">Scheduler를 개선 방법 5가지</h3>
<h4 id="source-code-modification">Source code modification</h4>
<p>그냥 코드단위로 스케줄러 변경</p>
<h4 id="extender-mechanism">Extender mechanism</h4>
<p>HTTP로 추가적인 프로세스를 실행시켜 filtering과 scoring을 진행한다.</p>
<h4 id="custom-scheduler">Custom Scheduler</h4>
<p>여러개의 custom scheduler를 만들어서 pod마다 다른 scheduler를 실행시킬 수 있다.</p>
<h4 id="scheduling-framework">Scheduling framework</h4>
<p>scheduling 과정에 있는 여러 개의 plugin들을 추가/제거해 filtering과 scoring 방식을 바꿀 뿐만 아니라 pod queue에 정렬되는 기준들을 변경할 수도 있다.</p>
<h4 id="input-to-the-scheduler-from-another-component">Input to the scheduler from another component</h4>
<p>Custom logic을 만들어서 affinity label등을 추가할 수 있다.</p>
<h3 id="custom-scheduler의-트렌드">Custom Scheduler의 트렌드</h3>
<p>초기의 custom scheduler들은 2017년에 나왔다. 걑은 종류의 자원을 두고 경쟁하는 pod들에 대해 QoS(Quality of Service) class를 제공해서 자원 할당 정도를 조정하는 것 등이 나왔다.</p>
<p>2019년에 나온 custom scheduler는 GPU sharing을 구현하고 utilization 정도를 올리기 위해 scheduler를 제작하였다.</p>
<p>2019년 이후부터는 크게 두 분류의 custom scheduler가 개발됐다. 첫 번째는 fog/edge computing을 지원해주는 custom scheduler를 개발했다. 기존의 K8s scheduler는 fog/edge의 노드들에 대한 topology를 신경쓰지 않았기 때문에 이것을 지원하기 위한 scheduler를 개발했다.
두 번째는 GPT-2나 GPT-3등의 NLP 기반 작업에서 효율성을 높이는 방향으로 custom scheduler를 개발하였다.</p>
<h3 id="classification-methodology">Classification methodology</h3>
<h4 id="workload-속도-최적화">workload 속도 최적화</h4>
<ul>
<li><p>Interference and colocation : 같은 resource를 사용하는 multiple workload를 한 노드에 넣으면 resource conflict가 일어난다.</p>
</li>
<li><p>QoS support 부족 : CPU, memory, local storage등의 resource는 scheduling시 고려되지만, network bandwidth에 대한 고려는 이루어지지 않고 있다.</p>
</li>
<li><p>Topology-awareness : edge/fog 상에서 node들 간의 topology가 고려되지 않는 scheduling은 latency를 증가시킨다. 예를 들어 연결되는 작업을 하는 두 pod이 먼 node상에 있을 경우 통신시간이 증가한다.</p>
</li>
<li><p>No support for co-scheduling : 연결된 작업을 하는 여러 pod의 그룹들을 scheduling할 때 동시에 하지 못하고 하나하나씩 차례로 scheduling해야 한다. 따라서 마지막 pod이 스케줄링되지 전까지 작업을 시작하지 못한다.</p>
</li>
<li><p>No support for batch scheduling : batch scheduling이 없기 때문에 multi-priority queuing, fairness, and advanced preemption, multiple schedulers 등으로 대신하고 있다.</p>
</li>
<li><p>No support for data locality awareness : data locality를 인식하도록 개선이 필요하다.</p>
</li>
</ul>
<h4 id="resource의-사용효율-증가">resource의 사용효율 증가</h4>
<ul>
<li><p>Lack of real load awareness : pod이 스케줄링될 때 request만큼의 여유 resource를 가진 node로 할당되는데, 이 때 실행중인 pod의 resource 소비량은 실제 소비량이 아닌 해당 pod들의 request를 기준으로 계산된다. 따라서 실제 사용량을 기준으로 계산하면 더 효율적인 resource 사용이 가능해진다.</p>
</li>
<li><p>GPU sharing : GPU의 할당량은 정수로밖에 지원되지 않으므로, custom scheduler를 만들어서 여러 pod들이 한 GPU를 사용할 수 있도록 custom scheduler를 개발할 수 있다.</p>
</li>
</ul>
<h4 id="negative-environmental-impact-감소">Negative environmental impact 감소</h4>
<p>환경을 보존하자!</p>
<h3 id="scheduler-심화">Scheduler 심화</h3>
<p>scheduler의 특징은 다음으로 나눌 수 있다.</p>
<ul>
<li><p>Objective : 앞에서 본 3개</p>
</li>
<li><p>Target environment : cloud 환경인지, 아니면 edge/fog 환경인지 나누고, cloud라면 ML/DL 위주인지 체크한다.</p>
</li>
<li><p>Target workloads
(1) AI/ML 환경에서 training or inference
(2) Serverless 환경
(3) Big data Analytics
(4) Stateful apps (ex. DB)
(5) Virtual network functions
(6) Network intensive
(7) Delay sensitive
(8) Heterogeneous</p>
</li>
<li><p>어떤 operation을 건들지
(1) Sorting
(2) Filtering
(3) Scoring</p>
</li>
<li><p>custom 방식
(1) 앞에서 본 5개</p>
</li>
<li><p>성능 평가 방식
(1) Real Cluster
(2) Simulator
(3) None</p>
</li>
</ul>
<h2 id="custom-scheduler-예제">Custom Scheduler 예제</h2>
<h3 id="interference--colocation">Interference &amp; Colocation</h3>
<p>workload들이 같은 자원을 두고 경쟁하지 못하도록 scheduling하는 것을 목표로 한다.</p>
<ol>
<li>어떤 제안자는 자원 분산을 위해 딥러닝의 강화학습을 기반으로 한 Harmony라는 모델을 제안한다. Harmony 모델은 클러스터 상태와 request resource를 입력으로 받고 pod을 알맞은 노드에 배치한다. 그 후 log로 interference 정도를 추출해 보상의 정도를 정하고 자원을 효율적으로 이용할 수 있다.</li>
</ol>
<p>출처 - Deep Learning-based Job Placement in Distributed
Machine Learning Clusters</p>
<ol start="2">
<li>어떤 제안자는 기존처럼 딥러닝 워크로드의 GPU 사용량을 실시간으로 평가하는 대신 딥러닝 모델을 통해 정보를 추출하고 GPU의 활용률을 예측해서 보여준다.</li>
</ol>
<p>출처 - Towards GPU Utilization Prediction for Cloud Deep Learning</p>
<h3 id="lack-of-support-for-network-qos">Lack of support for Network QoS</h3>
<ol>
<li><p>Kubernetes에서는 network를 자원의 단위로 간주하지 않으므로 NBW guard라는 network bandwidth 관리 system를 추가한다. NBW guard는 Linux 기반의 network management tool을 사용해서 traffic을 제한한다. 즉 network bandwidth를 할당해줌으로써 pod의 traffic이 특정 수치를 넘지 않도록 조절한다.</p>
</li>
<li><p>Remote DMA(네트워크 상에서 사용되는 DMA)를 관여한다. pod에서 RDMA bandwidth에 대한 request와 limit을 설정하도록 한다. 그리고 한 pod에서 multiple RDMA interface가 할당될 수 있도록 한다. 이를 통해 data transfer의 bandwidth를 조절할 수 있다.</p>
</li>
<li><p>latency-sensitive하고 data-intensive한 edge/fog 환경에서 실시간의 network status 정보를 확인하기 위해서 network-aware-scheduler(NAS)를 개발한다. NAS 상에서 fog에 해당하는 노드는 RTT(round trip time, 패킷 왕복 시간)으로 labeling된다. 또한 available bandwidth를 설정해서 노드에서 할당 가능한 대역폭을 넘기면 filtering시키는 과정을 거친다.</p>
</li>
</ol>
<h3 id="topology-awareness">Topology-awareness</h3>
<p>edge/fog에 제한되는 내용이므로 넘어가자.</p>
<h3 id="no-support-for-co-scheduling">No Support for Co-scheduling</h3>
<ol>
<li><p>Serverless workload상에서는 여러 개의 pod이 스케줄링될 때 각 부분의 이미지를 가지는 pod들에 대해서(ex. replicaset등을 말하는것 같다) 노드 탐색을 반복적으로 수행하므로 overhead가 발생한다. 따라서 동일한 이미지를 가지는 pod들을 한번에 스케줄링하는 방식을 사용하면 시간이 절약된다.</p>
</li>
<li><p>Kubernetes의 베타 기능으로 SIG(Special Interest Group)이 있다. pod spec에서 pod이 속한 group을 지정하고 pod 그룹의 우선순위를 비교해서 ready queue에서 정렬작업을 한다.</p>
</li>
</ol>
<h3 id="no-support-for-batch-scheduling">No Support for Batch Scheduling</h3>
<ol>
<li><p>multi-tenant 클라우드 환경에서 tenant간의 fairness를 보장해야 한다. Kube-batch에서는 fairness 보장 수단이 DRF(Domain Resource Fariness)밖에 존재하지 않으므로, 저자는 Kube-sphere라는 demand-aware와 demand-DRF-aware 2개를 추가로 고려하는 custom scheduler를 제작한다. demand-aware의 경우 많은 resource를 요구하는 유저를 우선하고, demand-DRF-aware는 starvation을 막기 위해 유저의 demand와 dominant resource share를 둘다 고려한다.</p>
</li>
<li><p>두가지의 scheduler를 제안한다. 첫번째는 busy hour에 사용하는, resource requirements를 기반으로 한 queue sorting을 사용해서 fragmentation 문제를 완화한다. 두번째는 GPU-intensive 작업을 위해 사용하는데, 그들의 waiting time과 estimated running time을 잘 고려해서 priority를 동적으로 조절한다.</p>
</li>
<li><p>Kube-batch는 AL/ML 등의 데이터와 CPU 작업이 많이 필요한 작업들을 위해 batch 스케줄링을 목료로 한다. Kube-batch는 다양한 우선순위 class들과 gang scheduling을 지원하며, Kubeflow나 Volcano등에서 사용한다. Apache Yunikorn는 YARN을 같이 사용해서 batch-scheduling을 지원하는 tool이다. stateless workload + statedful service같은 혼합된 workload를 사용가능하게 할 수 있다. hierarchical resource queues, multi-policy job queuing를 사용해서 fairness를 개선하는 한편 scheduling throughput을 향상시킬 수 있다.</p>
</li>
</ol>
<p>gang scheduling이란? 한 process의 여러 thread들을 따로따로 CPU에 실행시킴. pararell programming에서 사용 가능하다.</p>
<h3 id="no-support-for-data-locality-awareness">No support for Data locality Awareness</h3>
<h3 id="lack-of-real-load-awareness">Lack of Real load awareness</h3>
<p>pod을 scheduling할 때 reqeust값이 아닌 실제 사용량을 기반으로 scheduling plan을 만든다.</p>
<ol>
<li><p>edge-computing 환경에서 실시간의 resource consumption을 기반으로 scheduling한다. 실시간의 scheduling 정보(ex. load, temperature, liveness)등을 node로부터 모은 후 node score를 계산해서 schdeuling한다.</p>
</li>
<li><p>modified PSO(particle swarm optimization) 알고리즘을 사용해 scheduling한다. node의 사용량을 CPU와 memory 뿐만 아니라 affinity를 가지고 계산한다.</p>
</li>
<li><p>IBM에서 개발된 Trimaran이라는 load-aware scheduler plugin이 있다. 이 plugin은 pod resource의 request와 실제 사용량 사이의 불일치를 탐지하는데, 이것에 TargetLoadPacking와 LoadVariationRiskBalancing라는 두 가지 plugin을 사용한다. TargetLoadPacking는 각 node에서 실제 resource 사용량을 기준으로 점수를 매긴다.
LoadVariationRiskBalancing는 자원 사용의 평균과 표준편차를 구해서 점수를 매긴다.</p>
</li>
<li><p>Intel에서는 실시간의 telemetry 정보를 이용하는 TAS(Telemetry-aware scheduler)를 사용한다. 이 scheduler에서는 extender mechanism을 사용해 node의 power, CPU, memory등의 사용량을 체크한다.</p>
</li>
</ol>
<h3 id="gpu-sharing">GPU Sharing</h3>
<ol>
<li><p>GAIA는 GPU sharing을 제안한 scheduler이다. GPU cluster를 communication cost를 기반으로 tree 구조로 설계하고 얼마나 사용중인지의 상태를 표시한다. GAIA에서는 이 tree 구조에서 얼마나 GPU를 할당해줄 것인지 확인한다. 그리고 GAIA에서는 device plugin을 사용해서 GPU를 fractional한 virtual GPU들로 나눌 수 있다.</p>
</li>
<li><p>pod이 필요한 GPU 사용량보다 적은 GPU를 가진 node은 filtering한다. GPU 할당을 CPU와 memory처럼 하기 위해 두 개의 Custom Resource를 개발하는데, RESOURCE-MEM은 사용 가능한 VRAM의 크기이고 RESOURCE-COUNT는 사용 가능한 GPU의 수이다. 그리고 NVIDIA device plugin을 사용해서 GPU를 kubelet에서 인지하도록 한다.</p>
</li>
<li><p>KubeShare라는 프레임워크로 GPU sharing을 제안한다. SharePod이라는 Custom Resource를 제안하고, vGPU라는 custom shared device를 붙인다. 그리고 vGPU를 적절하게 continaer에 붙여주는 KubeShare-Sched와 vGPU pool을 관리하는 KubeShare-DevMgr라는 Custom controller를 만든다.</p>
</li>
<li><p>어떤 작업이 CPU나 GPU에서 둘 다 수행 가능할 경우, CPU를 할당받을 때와 GPU를 할당받을 때의 예상 완료 시간을 비교해 더 나은 쪽으로 자원을 할당해준다.</p>
</li>
</ol>
<h3 id="specific-contributions---etc">Specific Contributions - etc</h3>
<p>새로운 알고리즘 사용하기</p>
<ol>
<li><p>SpeCon이라는 scheduler는 DL training의 application specefic의 효율성을 높이기 위해 제안되었다. DL 작업의 여러 단계들은 각각 자원의 필요량이 차이가 난다. 따라서 DL 작업을 progressing, watching, converge 3분류로 나눈다. 작업 속도가 느린 단계에서 리소스를 빼와서 작업 속도가 빠른 단계에 집중시킨다. 이로부터 DL 수행시간을 줄일 수 있다.</p>
</li>
<li><p>Prediction을 사용해서 CPU노드와 GPU노드 모두에 대한 작업 소요시간을 예상한다. Prediction은 instrcution수, floating point 계산수, 사용하는 resource량 등으로 예측하고, workload들의 우선순위를 조절하고 더 적절한 노드에 할당한다.</p>
</li>
</ol>
<h2 id="summary">Summary</h2>
<p>Annotation, Label, Extended Resource, CRD, Device Plugin을 추가해서 스케줄러를 확장할 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Custom Scheduler Configuration]]></title>
            <link>https://velog.io/@hyunsu_prog/Custom-Scheduler-Configuration</link>
            <guid>https://velog.io/@hyunsu_prog/Custom-Scheduler-Configuration</guid>
            <pubDate>Wed, 27 Mar 2024 11:00:42 GMT</pubDate>
            <description><![CDATA[<p>Kubernetes에는 taint, tolerence, affinity 등으로 구성된 기본적인 스케줄러가 존재한다. <a href="https://velog.io/@hyunsu_prog/Scheduling-in-Kubernetes">여기</a>
이 기본 스케줄러 대신 추가적인 기능들을 구현한 <code>Custom scheduler</code>를 만들어 볼 수 있다.</p>
<hr>
<h2 id="기본-scheduler의-작동방식">기본 Scheduler의 작동방식</h2>
<p>Scheduler가 pod을 배치하는 것은 크게 <code>Scheduling cycle</code>, <code>Binding cycle</code>로 나뉜다. cycle 안의 각각의 단계들은 <code>plugin</code>에 의해 동작한다.</p>
<p><img src="https://velog.velcdn.com/images/hyunsu_prog/post/c53d88ed-04a4-448f-852b-149ffc704545/image.png" alt=""></p>
<h3 id="preenqueue">PreEnqueue</h3>
<p>scheduling되려는 pod이 가장 처음 들어오는 queue이다. 안에 있는 모든 <code>PreEnqueue Plugin</code>이 Success를 return하면 pod들이 active queue로 들어가기 시작한다.</p>
<h3 id="scheduling-cycle">Scheduling cycle</h3>
<p>pod에 적합한 node를 선택하는 과정이다. 기본적으로 아래의 순서대로 진행된다.</p>
<h4 id="prefilter">PreFilter</h4>
<p>pod에 대한 정보를 전처리하거나, pod이 만족해야 하는 필수사항을 체크한다. 만족하지 못하면 pod을 unscheduled로 만든다.</p>
<h4 id="filter">Filter</h4>
<p>여러 개의 filter를 통해 pod에 적합하지 않은 node를 제거한다. Taint와 Tolerence가 여기서 적용된다. node가 모두 filter를 통과하지 않으면 postFilter 단계로 넘어간다.</p>
<h4 id="postfilter">PostFilter</h4>
<p>pod이 실행 가능한 node가 모두 filtering되었을 때 pod pre-emption등의 작업을 거쳐 node가 조건을 만족하도록 바꿔준다. 이래도 해결되지 않을 경우 pod을 unscheduled로 만든다.</p>
<h4 id="score">Score</h4>
<p>filtering되지 않은 node들에 대해 적합도를 매긴다. NodeAffinity가 여기서 적용된다. 적합도는 여러 기준을 사용할 수 있다. 그 후 적합도가 가장 높은 node를 선택한다.</p>
<h4 id="reserve">Reserve</h4>
<p>race condition등을 방지하기 위해 pod에서 필요한 resource들을 예약해 둔다.</p>
<h4 id="permit">Permit</h4>
<p>Binding cycle에 들어가기 전에 대기할 수 있다.</p>
<h3 id="binding-cycle">Binding cycle</h3>
<p>pod를 실제로 node에 바인딩하는 단계이다.</p>
<hr>
<h2 id="custom-scheduler">Custom scheduler</h2>
<p>기본 scheduler에서 기본적으로 제공하는 plugin들은 <a href="https://kubernetes.io/ko/docs/reference/scheduling/config/#scheduling-plugins">여기</a>. 여기서 몇 가지의 plugin제거하거나 custom plugin을 추가해서 <code>custom scheduler</code>를 만들 수 있다.</p>
<p>예를 들어 Scoring 단계에서 custom plugin을 적용해 custom resource에 대한 가중치를 추가할 수 있다.</p>
<h3 id="적용하는-법">적용하는 법</h3>
<p>다음과 같이 Custom Plugin을 만들 수 있다.</p>
<pre><code class="language-go">type Plugin interface {
    Name() string
}

type QueueSortPlugin interface {
    Plugin
    Less(*v1.pod, *v1.pod) bool
}

type PreFilterPlugin interface {
    Plugin
    PreFilter(context.Context, *framework.CycleState, *v1.pod) error
}</code></pre>
<p>Custom Plugin 또는 Kubernetes에서 배포하는 확장 플러그인을 적용하려면 다음의 yaml 파일을 작성하면 된다.
예시에서는 score 단계에서 사용할 <code>plugin</code>중 PodTopologySpread plugin을 비활성화하고 custom plugin A, B를 추가하였다.</p>
<pre><code class="language-yaml">apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
profiles:
  - plugins:
      score:
        disabled:
        - name: PodTopologySpread
        enabled:
        - name: MyCustomPluginA
          weight: 2
        - name: MyCustomPluginB
          weight: 1</code></pre>
<p>또는 다음과 같이 하면 MyPlugin이 적용 가능한 익스텐션 포인트들에 한번에 적용된다.</p>
<pre><code class="language-yaml">apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
profiles:
  - schedulerName: non-multipoint-scheduler
    plugins:
      multiPoint:
        enabled:
        - name: &#39;MyPlugin&#39;
      preScore:
        disabled:
        - name: &#39;*&#39;
      score:
        disabled:
        - name: &#39;*&#39;</code></pre>
<p>이렇게 만들어진 <code>custom scheduler</code>와 기본 scheduler를 같이 사용하고 싶다면 다음과 같이 한다.</p>
<pre><code class="language-yaml">apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
profiles:
  - schedulerName: default-scheduler
  - schedulerName: no-scoring-scheduler
    plugins:
      preScore:
        disabled:
        - name: &#39;*&#39;
      score:
        disabled:
        - name: &#39;*&#39;</code></pre>
<hr>
<p>출처</p>
<p><a href="https://kubernetes.io/docs/concepts/scheduling-eviction/scheduling-framework/">https://kubernetes.io/docs/concepts/scheduling-eviction/scheduling-framework/</a></p>
<p><a href="https://kubernetes.io/ko/docs/reference/scheduling/config/">https://kubernetes.io/ko/docs/reference/scheduling/config/</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Scheduling in Kubernetes]]></title>
            <link>https://velog.io/@hyunsu_prog/Scheduling-in-Kubernetes</link>
            <guid>https://velog.io/@hyunsu_prog/Scheduling-in-Kubernetes</guid>
            <pubDate>Tue, 26 Mar 2024 04:36:03 GMT</pubDate>
            <description><![CDATA[<h2 id="taints--tolerations">Taints &amp; Tolerations</h2>
<h3 id="taints">Taints</h3>
<p>node에 pod이 scheduling되지 않도록 설정한다. control plane의 master node는 기본적으로 이 설정이 적용되어 있다. Taint의 effect는 다음 3가지가 있다.
<code>NoSchedule</code>: Schedule 제한
<code>PreferNoSchedule</code>: Schedule 안하도록 권장
<code>NoExecute</code>: 이미 Schedule되었을 경우 preemption</p>
<p>다음과 같이 <code>taint</code>를 추가할 수 있다.</p>
<pre><code>kubectl taint nodes node1 key1=value1:NoSchedule</code></pre><p>그리고 다음과 같이 <code>taint</code>를 제거할 수 있다.</p>
<pre><code>kubectl taint nodes node1 key1=value1:NoSchedule-</code></pre><h3 id="tolerations">Tolerations</h3>
<p>node의 taint를 무시하고 scheduling되도록 설정한다. Taint의 operator는 다음과 같이 2개가 있다.
<code>Equal</code>: key, value가 겹칠 경우 적용
<code>Exist</code>: key가 겹칠 경우 적용
특수한 케이스로 <code>Exist</code>에 키가 비어있을 경우 모든 Taint를 무시한다.</p>
<p>다음과 같이 <code>toleration</code>을 추가할 수 있다.</p>
<pre><code>tolerations:
- key: &quot;key1&quot;
  operator: &quot;Equal&quot;
  value: &quot;value1&quot;
  effect: &quot;NoSchedule&quot;</code></pre><h2 id="node-affinity">Node affinity</h2>
<p>taint와 반대로 pod을 해당 node에 배치하도록 한다.</p>
<p>다음과 같이 하면 조건을 만족하는 node에만 스케줄링된다.</p>
<pre><code>apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: disktype
            operator: In
            values:
            - ssd            
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent</code></pre><p>필드 설명은 다음과 같다.
<code>requiredDuringScheduling</code>: pod이 node에 반드시 배치되어야 한다.
<code>...IgnoredDuringExecution</code>: 이미 실행되고 있는 pod의 경우 pre-emption하지 않는다.
<code>nodeSelectorTerms</code>: affinity의 조건을 지정한다. 여기서는 ssd를 사용하는 label을 선호한다는 뜻이다.</p>
<p>다음과 같이 하면 조건을 만족하는 node에 우선순위를 높인다.</p>
<pre><code>apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  affinity:
    nodeAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        preference:
          matchExpressions:
          - key: disktype
            operator: In
            values:
            - ssd          
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent</code></pre><p>필드 설명은 다음과 같다.
<code>preferredDuringScheduling...</code>: pod이 node에 배치되도록 권장한다.
<code>preference</code>: affinity의 조건을 지정한다.</p>
<p>또한 weight를 지정할 수 있는데, 여러 조건들이 있을 때 우선순위 반영 비율을 정하는 것이다.</p>
<h3 id="node-anti-affinity">Node anti-affinity</h3>
<p>반대로 pod이 해당 node에 선호되지 않도록 할 수 있다. Taint와의 차이점은, pod이 현재 배치되어 있는 정보도 고려할 수 있다. 예를 들어 이미 같은 pod이 들어간 node에 scheduling되지 않도록 권장할 수 있다.</p>
<pre><code>podAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchExpressions:
            - key: security
              operator: In
              values:
              - S2
          topologyKey: topology.kubernetes.io/zone</code></pre><p>&nbsp;</p>
<p>출처</p>
<p><a href="https://kubernetes.io/ko/docs/concepts/scheduling-eviction/taint-and-toleration/#%EC%BB%A8%EB%94%94%EC%85%98-condition-%EC%9D%84-%EA%B8%B0%EC%A4%80%EC%9C%BC%EB%A1%9C-%EB%85%B8%EB%93%9C-%ED%85%8C%EC%9D%B8%ED%8A%B8%ED%95%98%EA%B8%B0">https://kubernetes.io/ko/docs/concepts/scheduling-eviction/taint-and-toleration/#%EC%BB%A8%EB%94%94%EC%85%98-condition-%EC%9D%84-%EA%B8%B0%EC%A4%80%EC%9C%BC%EB%A1%9C-%EB%85%B8%EB%93%9C-%ED%85%8C%EC%9D%B8%ED%8A%B8%ED%95%98%EA%B8%B0</a></p>
<p><a href="https://kubernetes.io/ko/docs/tasks/configure-pod-container/assign-pods-nodes-using-node-affinity/">https://kubernetes.io/ko/docs/tasks/configure-pod-container/assign-pods-nodes-using-node-affinity/</a></p>
<p><a href="https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity">https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Autoscaling in Kubernetes]]></title>
            <link>https://velog.io/@hyunsu_prog/Pod-autoscaler</link>
            <guid>https://velog.io/@hyunsu_prog/Pod-autoscaler</guid>
            <pubDate>Tue, 26 Mar 2024 02:11:16 GMT</pubDate>
            <description><![CDATA[<h2 id="cpu-based-hpa">CPU based HPA</h2>
<p>HPA(Horizontal Pod Autoscaling)은 3단계로 나뉘어진다.</p>
<h3 id="pod-metrics-obtaining">Pod metrics obtaining</h3>
<p>각 node의 Kubelet에 있는 <code>cAdvisor</code>에서 <code>pod metrics</code>와 <code>node metrics</code>를 수집한다. 수집한 metrics는 cluster 단위에 있는 <code>Heapster</code>가 통합한다. HPA가 REST API로 query를 보내어 가져온다.</p>
<p><code>Pod, node</code> -&gt; <code>cAdvisor</code> -&gt; <code>Heapster</code> -&gt; <code>HPA</code></p>
<h3 id="caluating-the-number-of-pods">Caluating the number of pods</h3>
<p>가져온 metrics를 가지고 pod이 얼마나 필요한지 계산한다. pod을 얼마나 늘려야 desired CPU utilization, QPS에 도달하는지 간단하게 알아볼 수 있다.</p>
<p><code>pod 수 = ceil[현재 pod 수 * ( current metric / desired metric )]</code></p>
<p><strong>Ex)</strong> Pod 1, 2, 3에서 CPU 사용량이 각각 60%, 70%, 80%라고 하자. CPU 사용량을 50%로 맞추고 싶다면 <code>ceil[(60 + 70 + 80) / 50] = 5</code>이다. 그러면 Pod당 평균 사용량은 <code>(60 + 70 + 80) / 5 = 42%</code>가 된다.</p>
<p>pod의 ready 상태등의 문제로 인한 누락된 metric이 있는 경우, pod updating이 적게 일어나도록 예측한다.
위의 예시에서 Pod 4의 metric이 누락됐다면, scale up을 최소화하기 위해 Pod 4는 0%의 CPU utilization값을 가진다고 가정한다.</p>
<h3 id="updating-the-number-of-pod">Updating the number of Pod</h3>
<p>앞의 예시에서 Pod의 현재 개수는 3이고 필요한 pod의 개수는 5이므로 pod을 2개 추가한다. 2개의 pod을 추가해달라는 요청을 워크로드 리소스(Deployments, Statefulsets, ...)에게 보낸다.</p>
<h2 id="구현-예제">구현 예제</h2>
<p>다음은 HPA를 정의하는 yaml이다.</p>
<pre><code>apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: php-apache
spec:
  scaleTargetRef:                // scaling하려는 워크로드 리소스
    apiVersion: apps/v1            
    kind: Deployment
    name: php-apache
  minReplicas: 1                // 최소, 최대 replica 개수
  maxReplicas: 10
  metrics:                        // desired state
  - type: Resource                // 여기에선 CPU 사용량 50%를 목표로 함
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 50
status:
  observedGeneration: 1
  lastScaleTime: &lt;some-time&gt;
  currentReplicas: 1
  desiredReplicas: 1
  currentMetrics:
  - type: Resource
    resource:
      name: cpu
      current:
        averageUtilization: 0
        averageValue: 0</code></pre><p> 또한 이렇게 간단하게 만들 수도 있다.</p>
<pre><code> kubectl autoscale deployment php-apache --cpu-percent=50 --min=1 --max=10</code></pre><h2 id="hpa-based-on-others">HPA based on others</h2>
<h3 id="memory-based-autoscaling">Memory based Autoscaling</h3>
<p>Kubernetes 1.8에 소개되었는데, memory는 scaling up시 기존 pod들의 memory release가 일어나야 하므로, 더 구현하기 어렵다. 관련자료를 찾아보려고 하는데 보이지 않는다..</p>
<h3 id="pod-based-autoscaling">Pod based Autoscaling</h3>
<p><code>Pod based autoscaling</code>을 하기 위해 기준이 되는 resource를 정의해야 한다. 이 경우<code>Utilization</code> 대신 <code>QPS(Query per second, 초당 요청량)</code>이나 <code>packets-per-second</code>등을 사용한다. 마찬가지로 다음과 같이 정의하면 된다.</p>
<pre><code>spec:
 metrics:
 - type: Pods
 resource:
 metricName: qps
 targetAverageValue: 100</code></pre><h3 id="object-based-autoscaling">Object based Autoscaling</h3>
<p>동일한 namespace 내의 어떤 Object를 이용해 기준 resource를 정의한다.
<code>Object based Autoscaling</code>의 경우 기존과 달리 모든 pod에서 metric을 가져오는 게 아니라, 하나의 <code>single object</code>만에서 metric을 가져와 계산한다.</p>
<pre><code>type: Object
object:
  metric:
    name: requests-per-second
  describedObject:
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    name: main-route
  target:
    type: Value
    value: 2k</code></pre><h3 id="external-resource-based-autoscaling">External resource based autoscaling</h3>
<p>외부에서 가져온 다른 리소스를 기반으로 autoscaling할 수도 있다. 다음 예제의 경우 30개의 message queue(미해결된 요청 큐)당 하나씩 pod을 추가하는 작성법이다.</p>
<pre><code>- type: External
  external:
    metric:
      name: queue_messages_ready
      selector:
        matchLabels:
          queue: &quot;worker_tasks&quot;
    target:
      type: AverageValue
      averageValue: 30</code></pre><h2 id="vpa-vertical-pod-autoscaling">VPA (Vertical pod autoscaling)</h2>
<p> request와 limit을 늘리는 방법을 적어놓았다. <a href="https://velog.io/@hyunsu_prog/Resource-Management">여기에서</a> resizing 항목으로 가면 적용할 수 있다.</p>
<p> 출처</p>
<p> Kubernetes in Action</p>
<p> <a href="https://kubernetes.io/ko/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/">https://kubernetes.io/ko/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Resource Management]]></title>
            <link>https://velog.io/@hyunsu_prog/Resource-Management</link>
            <guid>https://velog.io/@hyunsu_prog/Resource-Management</guid>
            <pubDate>Mon, 25 Mar 2024 13:49:50 GMT</pubDate>
            <description><![CDATA[<h2 id="request">Request</h2>
<p>pod이 resource마다 <code>request</code>를 지정하면, kube-scheduler는 <code>request</code>만큼의 여유공간이 존재하는 node에 스케줄링한다. 만약 해당하는 node가 없다면 스케줄하지 않고 Event를 발생시킨다.</p>
<p>scheduler의 스케줄링 방식으로는 가볍게 2가지가 있다.
<code>LeastRequestedPriority</code>: 자원 여유 많은 node에 스케줄링
<code>MostRequestedPriority</code>: 자원 여유 적은 node에 스케줄링</p>
<p><code>request</code> 필드는 pod들 간의 우선순위도 담당한다. 
Pod A의 <code>CPU request</code>가 1이고 Pod B의 <code>CPU request</code>가 3일 경우, 한 노드 안에서 Pod A와 Pod B의 작업 수행시간은 1:3으로 주어진다.</p>
<h3 id="qos">Qos</h3>
<p>node에 자원이 과도하게 사용될 경우 pod을 강제 종료시키는데, 이 때 종료시킬 pod의 우선순위를 세 그룹으로 나눈다. 그룹은 다음과 같다.</p>
<p><strong>BestEffort (lowest)</strong>
pod에 따로 request나 limit을 걸어두기 않았을 경우 분류되는 그룹이다.</p>
<p><strong>Burstable</strong>
request &lt; limit으로 명시될 경우 분류되는 그룹이다.</p>
<p><strong>Guaranteed (highest)</strong>
모든 resource에 대해 request == limit일 경우 분류되는 그룹이다.</p>
<p>간단히 말하면 <code>request / limit</code>이 작은 순서대로 pod를 preemption한다.</p>
<h2 id="limits">Limits</h2>
<p><code>limit</code>을 지정하면 kubelet이 해당 <code>limit</code>을 container runtime에 전달한다. container runtime은 해당 리소스만큼 격리한 후 프로세스가 제한을 초과하는지 감시한다. 프로세스가 더 많은 자원을 요청할 경우 OOM(Out of Memory) 상태롤 출력하고 종료시킨다.</p>
<h3 id="resourcequota">*ResourceQuota</h3>
<p><code>limit</code>은 또한 namespace 단위로 걸 수도 있는데, 이 때 <code>ResourceQuota</code>를 사용한다.
namespace별로 resource 뿐만 아니라 <code>requests.storage</code> 또는 <code>persistentvolumeclaims</code> 등을 정의해서 Volume 등 다양한 resource에 제한을 걸 수 있다.</p>
<pre><code>apiVersion: v1
kind: ResourceQuota
metadata:
 name: objects
spec:
 hard:
 pods: 10
 replicationcontrollers: 5
 secrets: 10
 configmaps: 10
 persistentvolumeclaims: 4
 services: 5
 services.loadbalancers: 1
 services.nodeports: 2
 ssd.storageclass.storage.k8s.io/persistentvolumeclaims: 2 </code></pre><h2 id="적용-방법">적용 방법</h2>
<p><code>spec.containers[].resources</code> 필드에서 limits와 requests를 설정할 수 있다.
정의하는 자원은 보통 <code>cpu</code> / <code>memory</code> / <code>hugepages-&lt;size&gt;</code> / <code>ephemeral-storage</code> 가 있다.</p>
<p><strong>hugepage)</strong> CPU가 사용하는 메모리가 있는 RAM의 부분 (운영체제)
<strong>ephemeral-storage)</strong> 캐싱, 로그등에 사용되는 RAM으로 지원되는 임시공간</p>
<p>&nbsp;</p>
<p>아래는 yaml 적용 예제이다.</p>
<pre><code>...
spec:
  containers:
  - name: app
    image: images.my-company.example/app:v4
    resources:
      requests:
        memory: &quot;64Mi&quot;
        cpu: &quot;250m&quot;
      limits:
        memory: &quot;128Mi&quot;
        cpu: &quot;500m&quot;</code></pre><h2 id="extended-resource">Extended Resource</h2>
<h3 id="node-level">node level</h3>
<p>node level로 <code>extended resource</code>가 만들어지면 cluster 운영자는 API server에 HTTP request를 보내서 node별로 사용량을 정할 수 있다.
예를 들어 <code>GPU resource</code>를 추가로 정의해 실행하는 GPU 개수 등을 지정할 수 있다.</p>
<h3 id="cluster-level">cluster level</h3>
<p>scheduler extender에 의해 관리된다.</p>
<h3 id="extended-resource-consumption">Extended resource consumption</h3>
<p>scheduler가 resource accounting 방식을 사용하여 기존 자원처럼 스케줄링 시 resource 여유공간을 넘기지 않도록 감시한다.</p>
<p>pod 차원에서는 일반적인 resource처럼 정의하면 된다.
(예제에서 example.com/foo)</p>
<pre><code>apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
  - name: my-container
    image: myimage
    resources:
      requests:
        cpu: 2
        example.com/foo: 1
      limits:
        example.com/foo: 1</code></pre><h2 id="resource-resizing">Resource resizing</h2>
<p>Kubernetes의 1.27에 추가된 기능으로 기존에 immutable했던 request를 변경할 수 있는 기능이다. <code>spec.containers[].resizePolicy</code>에서 resizing 시 어떻게 할지 정의 가능하다. (기본은 <code>NotRequired</code>)</p>
<pre><code>spec:
  containers:
  - name: qos-demo-ctr-5
    image: nginx
    resizePolicy:
    - resourceName: cpu
      restartPolicy: NotRequired
    - resourceName: memory
      restartPolicy: RestartContainer
    ...</code></pre><p><code>NotRequired</code> : container running 중에 자원 추가
<code>RestartContainer</code> : 재시작 후 더 많은 자원으로 교체</p>
<p>&nbsp;
아래와 같은 명령어를 입력하여 resize가 가능하다.</p>
<pre><code>kubectl -n {namespaceName} patch pod {podName} --patch &#39;{&quot;spec&quot;:{&quot;containers&quot;:[{&quot;name&quot;:&quot;qos-demo-ctr-5&quot;, &quot;resources&quot;:{&quot;requests&quot;:{&quot;cpu&quot;:&quot;800m&quot;}, &quot;limits&quot;:{&quot;cpu&quot;:&quot;800m&quot;}}}]}}</code></pre><p>&nbsp;
&nbsp;</p>
<p>출처</p>
<p><a href="https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/">https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/</a></p>
<p><a href="https://kubernetes.io/docs/tasks/configure-pod-container/resize-container-resources/">https://kubernetes.io/docs/tasks/configure-pod-container/resize-container-resources/</a></p>
<p>Kubernetes_in_Action</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Workload Management API 정리]]></title>
            <link>https://velog.io/@hyunsu_prog/11.-Kubernetes-%EC%9B%8C%ED%81%AC%EB%A1%9C%EB%93%9C-%EB%A6%AC%EC%86%8C%EC%8A%A4-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@hyunsu_prog/11.-Kubernetes-%EC%9B%8C%ED%81%AC%EB%A1%9C%EB%93%9C-%EB%A6%AC%EC%86%8C%EC%8A%A4-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Wed, 20 Mar 2024 01:28:06 GMT</pubDate>
            <description><![CDATA[<p>Kubernetes in Action, Second Edition MEAP V15 정리중</p>
<h1 id="service-object">Service object</h1>
<p>Kubernetes에서는 Service object를 사용하여 pod을 여러개 복제하고, 유저가 여러 pod들을 하나의 IP로 연결하도록 통합시킨다. 또한 여러 pod들이 Flat network이라는 공간에서 서로 통신한다.</p>
<pre><code class="language-yaml">apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app.kubernetes.io/name: MyApp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376</code></pre>
<h1 id="workload-management-api">Workload Management API</h1>
<h2 id="replicaset">Replicaset</h2>
<p>Pod의 복제본 수를 지정해놓고, pod가 종료되면 그만큼의 pod을 새로 할당해주고 pod이 너무 많아지면 pod을 죽여서 개수를 유지한다.</p>
<p><img src="https://velog.velcdn.com/images/hyunsu_prog/post/d535cd1f-fc1e-4cb4-956a-af4eca19f468/image.png" alt=""></p>
<p>각 pod마다 label을 두고 replicaset object에는 label selector를 두어 자기 관할인 pod만 지정할 수 있다. 또한 pod은 해당 replicaset이 소유한 것으로 취급된다. </p>
<p>다음과 같이 선언한다.</p>
<pre><code class="language-yaml">// rs.kiada.yaml

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: frontend
  labels:
    app: guestbook
    tier: frontend
spec:
  # 케이스에 따라 레플리카를 수정한다.
  replicas: 3
  selector:
    matchLabels:
      tier: frontend
  template:
    metadata:
      labels:
        tier: frontend
    spec:
      containers:
      - name: php-redis
        image: gcr.io/google_samples/gb-frontend:v3</code></pre>
<h3 id="replicaset-controller">replicaset controller</h3>
<p>replicaset과 그 아래 있는 pod을 관리하며, 관리 객체들의 state의 변경시 알맞게 조절해준다.
예를 들어 pod이 종료되어 명세된 개수보다 적어지면 pod을 다시 생성한다.</p>
<p><img src="https://velog.velcdn.com/images/hyunsu_prog/post/3b863e2a-3eae-47b6-a5aa-7dadc3497c1d/image.png" alt=""></p>
<p>다음과 같이 replica의 수를 늘리거나 줄일 수 있다.</p>
<pre><code>$ kubectl scale rs kiada --replicas 6
replicaset.apps/kiada scaled</code></pre><p>replica의 수를 줄일 경우 가장 지워도 되는 pod부터 선택해서 제거한다.</p>
<p>pod의 label을 바꾸면 해당 replicaset controller의 통제를 벗어날 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/hyunsu_prog/post/cc0d42c9-477c-4348-9b45-424bfd3a260c/image.png" alt=""></p>
<h2 id="deployment">Deployment</h2>
<p>application의 desired state를 정의하여 상태를 조절한다. 선언시에 replicaSet을 이용하여 pod의 개수를 정의할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/hyunsu_prog/post/cbe07bcf-3af8-40be-864c-c0cb0c03e991/image.png" alt=""></p>
<p>다음과 같이 선언할 수 있다.</p>
<pre><code class="language-yaml">// deploy.kiada.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80
 ...</code></pre>
<h3 id="pod-updating-in-deployment">pod updating in deployment</h3>
<p>pod을 update할 때, deployment object에서는 <code>rolling update</code>라는 것을 지원한다.
pod을 모두 한번에 멈춰버리면 서버가 다운되므로, pod을 천천히 하나씩 종료하고 업데이트한다.
<img src="https://velog.velcdn.com/images/hyunsu_prog/post/6103ae4f-022a-4ed2-be2a-b4c847d8b235/image.png" alt=""></p>
<p>다음과 같이 선언할 수 있다.</p>
<pre><code class="language-yaml">apiVersion: apps/v1
kind: Deployment
metadata:
   name: nginx
spec:
   strategy:
   type: RollingUpdate
   rollingUpdate: 
   maxSurge: 0 
   maxUnavailable: 1 
   minReadySeconds: 10
   replicas: 3
   selector:</code></pre>
<p><code>maxSurge</code>, <code>maxUnavailable</code> 두 필드가 중요하다.
<code>maxSurge</code>: update중 원래 size를 초과하여 pod를 생성할 수 있는 최대 개수
<code>maxUnavailable</code>: update중 실행 가능하지 않은 pod의 최대 개수</p>
<p><code>maxSurge: 0</code>, <code>maxUnavailable: 1</code>
<img src="https://velog.velcdn.com/images/hyunsu_prog/post/f8856f02-018c-4b2e-af0e-50d2942bf3eb/image.png" alt=""></p>
<p><code>maxSurge: 1</code>, <code>maxUnavailable: 0</code>
<img src="https://velog.velcdn.com/images/hyunsu_prog/post/3b921229-2358-4c92-8bd6-84f1a8e34a4e/image.png" alt=""></p>
<p><strong>그 외에도 여러 update strategy도 있는데 간단한 설명은 다음과 같다. 더 궁금하면 나중에 찾아보자.</strong></p>
<p><code>Recreate</code>: service의 일시적인 중단을 무시하고 pod을 모두 동시에 업데이트한다.
<code>Canary</code>: 적은 수의 canary pod만 남겨두고 모두 동시에 업데이트한다.
<code>A/B testing</code>: 두 종류의 deployment를 만들고, Ingress object를 만들어 유저 특징별로 어떤 deployment에 들어갈 것인지 결정하고 redirect한다.
<code>Blue/Green</code>: 기존에 pod들(blue label)로 서비스하면서 새로운 pod들(green label)을 만든다. 다 완성되면 선택하는 label을 바꿔서 새로운 pod들로 연결한다.
<code>Shadowing</code>: 새 버전이 정상적으로 작동할지 확신이 없을 때, 새 버전을 먼저 만들어 놓고 Ingress object를 만들어 traffic을 기존 버전과 새 버전에게 모두 전달한다. 새 버전의 결과는 test용도로만 쓰고 버린다.</p>
<h2 id="statefulset">StatefulSet</h2>
<p>상태를 저장해야 하는 application(ex. DB)를 배포하기 위해 존재한다.</p>
<p>Statefulset은 각 pod마다 지정된 ID와 Persistent Volume, 그리고 안정적인 IP address를 가진다.
<strong>즉 pod의 순서와 고유성을 보장한다.</strong></p>
<p><img src="https://velog.velcdn.com/images/hyunsu_prog/post/b7f0ddb6-e10f-4c44-b06b-ebb567ee64e4/image.png" alt=""></p>
<p>다음과 같이 선언할 수 있다.</p>
<pre><code class="language-yaml">apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  selector:
    matchLabels:
      app: nginx # .spec.template.metadata.labels 와 일치해야 한다
  serviceName: &quot;nginx&quot;
  replicas: 3 # 기본값은 1
  minReadySeconds: 10 # 기본값은 0
  template:
    metadata:
      labels:
        app: nginx # .spec.selector.matchLabels 와 일치해야 한다
    spec:
      terminationGracePeriodSeconds: 10
      containers:
      - name: nginx
        image: registry.k8s.io/nginx-slim:0.8
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: www
    spec:
      accessModes: [ &quot;ReadWriteOnce&quot; ]
      storageClassName: &quot;my-storage-class&quot;
      resources:
        requests:
          storage: 1Gi</code></pre>
<p>StatefulSet의 세부기능은 나중에 추가로 봐야겠다...</p>
<h2 id="daemonset">DaemonSet</h2>
<p>K8s의 모든 worker node에서 단 하나의 해당 pod을 실행하도록 한다.
system 레벨의 서비스를 제공하는 application(ex. 로그, device plugin)에 주로 사용한다. 예를 들어서 Kube proxy component는 kube-system namespace를 가지고 <code>DaemonSet</code>으로 배포된다.</p>
<p><img src="https://velog.velcdn.com/images/hyunsu_prog/post/383c3cd9-67eb-4529-a710-828e12f6e65e/image.png" alt=""></p>
<p>또는 <code>node selecter</code>를 통해 꼭 모든 node가 아니라 특정 조건을 만족하는 node에만 pod을 scheduling할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/hyunsu_prog/post/00c12bef-f800-4ca7-a54c-7d731b6d6686/image.png" alt=""></p>
<p><code>node selecter</code>는 이렇게 정의할 수 있다.</p>
<pre><code class="language-yaml">apiVersion: apps/v1
kind: DaemonSet
metadata:
   name: demo
   labels:
     app: demo
spec:
   selector:
     matchLabels:
       app: demo
   template:
     metadata:
       labels:
         app: demo
     spec:
       nodeSelector: 
         gpu: cuda 
       containers:
       - name: demo
         image: busybox
         command:
         - sleep
         - infinity</code></pre>
<p> 해당하는 node에는 다음과 같이 선언한다.</p>
<pre><code> $ kubectl label node kind-worker2 gpu=cuda</code></pre><p><code>DaemonSet</code> 또한 label selector를 가지고 label에 맞는 pod만 관리한다.</p>
<p>DaemonSet의 선언은 다음과 같다.</p>
<pre><code class="language-yaml">apiVersion: apps/v1 
kind: DaemonSet 
metadata:
     name: demo 
spec:
   selector: 
     matchLabels: 
         app: demo 
   template: 
     metadata: 
       labels: 
            app: demo 
     spec: 
       containers: 
       - name: demo 
            image: busybox 
            command: 
            - sleep 
            - infinity </code></pre>
<p>DaemonSet은 status를 가지고 있는데, 확인하려면 다음과 같다. 각 status가 의미하는 것은 너무 자명하므로 생략한다.</p>
<pre><code>$ kubectl get ds demo -o yaml
...
status:
 currentNumberScheduled: 2
 desiredNumberScheduled: 2
 numberAvailable: 2
 numberMisscheduled: 0
 numberReady: 2
 updatedNumberScheduled: 2</code></pre><h3 id="daemonset만의-기능">DaemonSet만의 기능</h3>
<p> container에게 system상의(OS kernel) 접근 권한이나 node의 filesystem이나 network등의 접근 권한을 받을 수 있다.</p>
<h3 id="daemonset-pod과의-통신">DaemonSet pod과의 통신</h3>
<pre><code class="language-yaml">apiVersion: apps/v1
kind: DaemonSet
metadata:
 name: node-agent
 ...
spec:
 template:
   spec:
     containers:
     - name: node-agent
       image: luksa/node-agent:0.1
       args: 
       - --listen-address 
       - :80 
       ...
       ports: 
       - name: http
         containerPort: 80 
         hostPort: 11559 </code></pre>
<p>이렇게 하면 각 node의 pod에서는 port 11559로 접근시 port 80에서 듣고 있는 DaemonSet pod으로 전해진다.</p>
<p>이것도 자세한건 나중에...</p>
<h2 id="job-cronjob">Job, CronJob</h2>
<p><code>Job</code>은 특수한 작업을 진행하는 동안만 pod을 유지시키고 이후에 pod을 종료하는 리소스이다.
<code>CronJob</code>은 주기적으로 <code>Job</code>을 실행시키는 리소스로, 주로 n분 단위 시스템 감시 &amp; 자동 업데이트 등에 사용된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[PersistentVolume]]></title>
            <link>https://velog.io/@hyunsu_prog/8.-PersistentVolume</link>
            <guid>https://velog.io/@hyunsu_prog/8.-PersistentVolume</guid>
            <pubDate>Mon, 18 Mar 2024 02:40:11 GMT</pubDate>
            <description><![CDATA[<p>Kubernetes in Action, Second Edition MEAP V15 정리중</p>
<p>Kubernetes는 이상적으로 어떤 환경에서도 실행과 배포가 가능해야 한다. 따라서 클라우드 스토리지의 실행 환경이나 파일 절대주소등을 넣지 않고도 사용할 방법이 필요하다.</p>
<p><strong>--&gt; PersistentVolume을 사용하자!</strong></p>
<p>&nbsp;</p>
<h2 id="persistentvolume-구조">PersistentVolume 구조</h2>
<h4 id="persistent-volume">Persistent Volume</h4>
<p>network storage와 pod 사이의 중간과정을 만들어주어 Persistent Volume object에서 pod의 데이터들을 저장한다.</p>
<p>PV에 데이터가 있으므로 pod이 변경돼도 데이터를 보관할 수 있다.</p>
<h4 id="persistent-volume-claim">Persistent Volume Claim</h4>
<p>pod에서 Persistent volume의 데이터가 필요할 경우 PVC를 통해서 exclusive하게 데이터를 읽을 권한을 받는다.</p>
<p>PVC를 이용해서 접근하므로 Persistent Volume의 세부 저장환경에 구애받지 않고 PV의 이름만으로 연결해서 데이터를 가져온다.</p>
<p><img src="https://velog.velcdn.com/images/hyunsu_prog/post/ba5aa3e7-4c57-4f50-9204-607593bca4a8/image.png" alt=""></p>
<p>DB의 운영자가 세부 실행환경을 맞추어 Persistent Volume을 설계하고, 이용자는 이것의 고려 없이 자유롭게 application의 데이터를 저장할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/hyunsu_prog/post/8f55ff58-91d6-427a-bcd8-b36b0c113a07/image.png" alt=""></p>
<h2 id="access-mode">Access mode</h2>
<p><code>ReadWriteOnce</code>: 하나의 node에서 RW로 마운트 가능
<code>ReadOnlyMany</code>: 다수의 node에서 읽기 전용으로 마운트 가능
<code>ReadWriteMany</code>: 다수의 node에서 RW로 마운트 가능
<code>ReadWriteOncePod</code>: 노드의 단일 pod에서 RW로 마운트 가능</p>
<h2 id="dynamic-provisioning">Dynamic provisioning</h2>
<h3 id="정적-provisioning의-단점">정적 provisioning의 단점</h3>
<p>물리적 volume을 연결한 이후에 PersistentVolume object를 새로 만들어 주어야 하므로,
물리적 volume이 바인딩되고 해제될 때마다 해당 volume에 대한 PersistentVolume object를 계속 생산/삭제 해주어야함 -&gt; volume의 수가 많아질수록 Kubernetes의 자동화에 악영향</p>
<h3 id="to-solve---dynamic-provisioning">To solve -&gt; dynamic provisioning</h3>
<p>우선 cluster admin이 storage class에 따라 PV Provisioner를 만든다. 유저가 PVC object를 먼저 만들면, cluster admin이 요청을 받아 PV Provisioner로부터 적합한 PV를 제공해준다. 제공된 PV와 PVC를 연결하는 것이다.</p>
<p><img src="https://velog.velcdn.com/images/hyunsu_prog/post/a4aade95-dd0a-419b-b7dd-1c1183b4f330/image.png" alt=""></p>
<p><strong>주의)</strong> cluster admin이 cloud같은 외부서버일 경우 Provisioner는 이미 구현되어 있지만, on-premise일 경우 custom provisioner를 직접 만들어줘야 한다.</p>
<h3 id="dynamic-provisioning의-lifecycle">Dynamic provisioning의 lifecycle</h3>
<p>위에서 설명했던 내용과 같다. 유저가 PVC를 생성하면 PV Provisioner가 비동기적으로 PV를 만들어 준 후 바인딩한다.
<img src="https://velog.velcdn.com/images/hyunsu_prog/post/806d806e-1417-4c64-a789-c47839f5ea96/image.png" alt=""></p>
<h2 id="node-local-persistent-volume">Node-local persistent volume</h2>
<p>네트워크 스토리지말고 로컬 스토리지의 DB들을 이용하면 접근 속도를 향상시킬 수 있다. 이전 장의 Hostpath 볼륨과 다른 점은 다음과 같다.</p>
<ol>
<li>hostpath 볼륨은 pod이 다른 node로 rescheduling될 경우 해당 node 권한에 따라 데이터 접근이 안될 수 있다. 그러나 node-local PV의 경우 scheduler 차원에서 PV의 node별 접근권한을 확인해 적절한 node로 pod을 보낼 수 있다.</li>
<li>PV는 cluster manager에 의해 관리되므로 보안상 더 안전하다.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[Storage Volume]]></title>
            <link>https://velog.io/@hyunsu_prog/7.-Storage-Volume</link>
            <guid>https://velog.io/@hyunsu_prog/7.-Storage-Volume</guid>
            <pubDate>Fri, 15 Mar 2024 01:43:08 GMT</pubDate>
            <description><![CDATA[<p>Kubernetes in Action, Second Edition MEAP V15 정리중</p>
<h2 id="volume이란">Volume이란?</h2>
<p>container들이 파일시스템을 사용하도록 마운팅할 수 있는 저장공간</p>
<p>Volumn은 pod에 마운팅되고 pod과 같은 수명을 갖는다. 따라서 container가 재시작되어도 volumn의 정보는 그대로 남기 때문에 다시 가져와서 작업하면 된다.</p>
<p>물론 container가 crash되어 종료된 후 restart시 volume의 모든 정보를 다시 가져오면 또 crash날 확률이 높으므로 가져올 정보는 구분하자.</p>
<p><img src="https://velog.velcdn.com/images/hyunsu_prog/post/0027937f-3296-434a-8de8-77016fa88715/image.png" alt=""></p>
<p>하나의 container에서 여러 개의 Volume에 마운트할 수 있다.
<img src="https://velog.velcdn.com/images/hyunsu_prog/post/3e7a754c-b8d7-4299-8970-2e6687a6066a/image.png" alt=""></p>
<p>또는 r/w 권한을 부여하여 한 volume을 통해 container들끼리 데이터를 주고받을 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/hyunsu_prog/post/f417765d-1d0e-4d20-98d7-d823aa28f1fd/image.png" alt=""></p>
<h3 id="external-storage에-volume-마운트">External Storage에 Volume 마운트</h3>
<p>pod에 한정된 Volume을 로컬 파일시스템이나 등의 외부 네트워크 저장소등과 연결해서 데이터를 주고받을 수 있다.
<img src="https://velog.velcdn.com/images/hyunsu_prog/post/0e2c09c9-5c61-4919-96a3-ae8061b3a6ca/image.png" alt=""></p>
<p>External storage 또한 여러 pod에서 동시에 접근할 수 있다.
<img src="https://velog.velcdn.com/images/hyunsu_prog/post/b77eff85-fc6e-45ac-bd25-290922a66d34/image.png" alt=""></p>
<h2 id="volume-유형">Volume 유형</h2>
<p>여러 유형이 있어서 더 많은 건 그때그때 확인해야겠지만, 중요한 것만 간단하게 써보려고 한다.</p>
<h4 id="emptydir">emptyDir</h4>
<p>가장 간단한 Volume 형태로, 외부에서 마운트하지 않고 pod이 시작될 때 생성되어 pod의 lifecycle동안 데이터를 저장한다.</p>
<p>주로 container가 재시작되어도 데이터가 보존되어 있어야 하거나, 두 container가 서로 데이터를 공유할 때 사용한다.</p>
<h4 id="gcepersistentdisk-awselasticblockstore-">gcePersistentDisk, awsElasticBlockStore, ...</h4>
<p>클라우드 스토리지를 pod에 마운트할 때 사용한다. 여러 pod에서 사용할 수 있다는 장점이 있다.</p>
<p>주의사항은 cluster가 어떤 환경에서 실행되느냐에 따라 사용할 수 있는 저장소가 달라진다.</p>
<h4 id="hostpath">hostPath</h4>
<p>node의 파일 시스템에서 pod로 마운트할 때 사용한다.</p>
<p>pod이 항상 동일한 node에서 실행되도록 보장되는건 아니기 때문에, pod이 다른 node로 rescheduled되면 데이터에 접근할 수 없는 위험이 있다.</p>
<p>일반적으로 hostPath 볼륨은 노드의 파일 시스템에서 읽거나 쓰는 파일이 필요한 경우에 사용된다. 예를 들어, 시스템 수준의 로그와 같이 노드에서 실행되는 프로세스가 읽거나 생성하는 파일에 대한 것이다.</p>
<h4 id="configmap-secret---">configMap, secret, ... -</h4>
<p>특수한 Volume 형태로, Kubernetes 객체에 대한 정보를 파일을 통해 볼 수 있는 볼륨이다.</p>
<h4 id="csi">csi</h4>
<p>Container Storage Interface로 자신만의 저장소 드라이버를 만들어서 연결 가능한 볼륨</p>
<h4 id="persistentvolumeclaim">persistentVolumeClaim</h4>
<p>외부 저장소를 pod으로 가져올 때 사용한다. 다음 장에서 자세히 설명한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Pod & Container lifecycle]]></title>
            <link>https://velog.io/@hyunsu_prog/6%EA%B0%95</link>
            <guid>https://velog.io/@hyunsu_prog/6%EA%B0%95</guid>
            <pubDate>Thu, 14 Mar 2024 03:06:49 GMT</pubDate>
            <description><![CDATA[<p>Kubernetes in Action, Second Edition MEAP V15 정리중</p>
<h1 id="container의-lifecycle">container의 lifecycle</h1>
<p>container가 생성된 이후부터 작업을 마치고 종료될 때까지의 state의 순서이다.</p>
<p><img src="https://velog.velcdn.com/images/hyunsu_prog/post/3a61d8da-7124-461b-a9f5-d62a1bdc6214/image.png" alt=""></p>
<p>적당히 그림보고 알아듣자.</p>
<p>contiainer의 lifecycle은 다음과 같이 알아낸다.</p>
<pre><code>$ kubectl describe po kiada
...
Containers:
 kiada:
 Container ID: docker://c64944a684d57faacfced0be1af44686...
 Image: luksa/kiada:0.1
 Image ID: docker-pullable://luksa/kiada@sha256:3f28...
 Port: 8080/TCP
 Host Port: 0/TCP
 State: Running 
 Started: Sun, 02 Feb 2020 12:43:03 +0100 
 Ready: True 
 Restart Count: 0 
 Environment: &lt;none&gt;
...</code></pre><h2 id="container-auto-restart-policy">Container auto-restart policy</h2>
<p>container는 기본적으로 종료되었을때 성공/실패 여부에 관계없이 자동재시작된다. 해당 사항은 pod의 spec의 restartPolicy에 적혀 있다. 기본은 Always이다.</p>
<p><img src="https://velog.velcdn.com/images/hyunsu_prog/post/2841806f-e6d5-45fc-b297-b85959cb115b/image.png" alt=""></p>
<p>Container가 재시작될 시 처음은 바로 시작하지만, 그 이후엔 시간간격을 10s, 20s, 40s, ..., 300s (max)식으로 시간간격을 늘려서 시작한다.
<img src="https://velog.velcdn.com/images/hyunsu_prog/post/2d8343ba-af8d-494f-aae6-4ce3bafec208/image.png" alt=""></p>
<p>재시작된 이유를 보려면 다음과 같이 하면 된다.</p>
<pre><code>$ kubectl get po kiada-ssl -o json | jq .status.containerStatuses
...
&quot;state&quot;: {
 &quot;waiting&quot;: {
 &quot;message&quot;: &quot;back-off 40s restarting failed container=envoy ...&quot;,
 &quot;reason&quot;: &quot;CrashLoopBackOff&quot;</code></pre><h3 id="liveness-probe">liveness probe</h3>
<p>container가 살아있는지 확인은 어떻게 할까? 정상적으로 종료되거나 에러를 방출하면 알아낼 수 있지만, 무한루프나 과부하됐을 때는 알아낼 방법이 없다.</p>
<p>이를 해결하기 위해 Kubernetes는 container에 지속적으로 query를 날려 응답을 체크한다. 이것을 liveness probe라고 한다.</p>
<p>liveness probe에는 HTTP GET, TCP 연결, exec 실행의 3가지의 request 요청 방식이 있다. 세부적인 작동방식은 다음과 같다.</p>
<p>우선 container 실행되고 InitialDelatSeconds만큼 기다림
-&gt; periodSeconds 주기로 request 보냄
-&gt; timeoutSeconds만큼 응답 없을 시 failure로 취급
-&gt; failureThreshold만큼 실패하면 container 종료
<img src="https://velog.velcdn.com/images/hyunsu_prog/post/bfa7554b-4c3f-4e28-bdba-07fffe87d237/image.png" alt=""></p>
<h3 id="startup-probe">startup probe</h3>
<p>liveness probe가 실행되기 전에 container가 제대로 시작했는지 알아보는 것으로, 실패하면 container를 종료시키고 성공하면 liveness probe단계로 넘어간다.
<img src="https://velog.velcdn.com/images/hyunsu_prog/post/c4a95073-6bb3-45e2-a85a-e784421d3198/image.png" alt=""></p>
<h2 id="post-start--pre-stop-hook">Post-start &amp; Pre-stop hook</h2>
<p>container가 시작된 직후나 종료되기 직전 따로 작업을 실행시킬 수 있는데, 이를 각각 <code>post-start hook</code>, <code>pre-stop hook</code> 이라고 한다.</p>
<p>이것을 이용해서 각각 시작하기 전 파일들 받아오기, container 정상종료를 수행할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/hyunsu_prog/post/2b9bf3be-9519-44f9-8d4a-3696bb050e2c/image.png" alt=""></p>
<h1 id="pod의-lifecycle">pod의 lifecycle</h1>
<p>pod도 container와 마찬가지로 lifecycle를 가진다.</p>
<p><img src="https://velog.velcdn.com/images/hyunsu_prog/post/1204eff1-ed54-4dad-985b-83f8837aea24/image.png" alt=""></p>
<ol>
<li><code>Pending</code>: pod이 처음 만들어 진 직후의 상태</li>
<li><code>Running</code>: node에서 image를 받고 pod를 할당할 때 running state로 넘어간다.</li>
<li><code>Succeeded</code>: pod가 모든 작업을 수행하고 성공적으로 종료되었을 때</li>
<li><code>Failed</code>: pod안의 어떤 container가 에러를 띄웠을 때</li>
<li><code>Unknown</code>: kubelet이 알수없는 이유로 API서버에 리포트를 보내고 있지 않을 때</li>
</ol>
<p>&nbsp;
pod의 phase는 다음 명령어로 볼 수 있다.</p>
<pre><code>$ kubectl get po kiada -o yaml | grep phase
phase: Running</code></pre><h2 id="pod의-conditions">pod의 conditions</h2>
<p>Pod이 어떤 condition들을 만족했는지 보여주는 지표이다.</p>
<p><img src="https://velog.velcdn.com/images/hyunsu_prog/post/d6ca2b0a-4f98-4d3f-8b1f-c5ebd3e4cd77/image.png" alt=""></p>
<p><code>PodScheduled</code>: pod이 node에 할당되었는지 여부
<code>Initialized</code>: pod의 Initial container가 성공적으로 작동했는지
<code>ContainersReady</code>: pod 안의 모든 container가 ready 상태인지
<code>Ready</code>: pod이 모든 실행준비를 끝냈는지</p>
<p>&nbsp;
pop의 condition은 다음 명령어로 볼 수 있다.</p>
<pre><code>$ kubectl describe po kiada
...
Conditions:
 Type Status
 Initialized True 
 Ready True 
 ContainersReady True 
 PodScheduled True 
...</code></pre><h2 id="pod의-stage">pod의 stage</h2>
<p>pod에는 3가지의 stage가 있다.</p>
<p><img src="https://velog.velcdn.com/images/hyunsu_prog/post/ab3451e8-0741-4d2e-8e46-2a599634f391/image.png" alt=""></p>
<h3 id="initialization-stage">initialization stage</h3>
<p>init container image를 node에 받아오고 pod의 init container들이 실행시키는 단계이다.</p>
<p>image를 받아오면 첫번째 init node부터 차례로 실행시킨다. 중간에 실패할 경우 재시작하지 않으면 pod은 error 상태가 된다.
<img src="https://velog.velcdn.com/images/hyunsu_prog/post/1d37a325-d516-4ae9-bd6b-d5d81041ceac/image.png" alt=""></p>
<h3 id="run-stage">run stage</h3>
<p>마찬가지로 container별로 image를 node에 받아오고 container들을 실행한다.</p>
<p>container가 종료될 때 container에서는 종료 로직을 실행하고 TERM 시그널을 보낸다. 일정시간이 지나도 종료되지 않으면 강제로 종료한다.</p>
<p><img src="https://velog.velcdn.com/images/hyunsu_prog/post/c629119f-9895-4b72-928e-9c98cc318702/image.png" alt=""></p>
<h3 id="termination-stage">termination stage</h3>
<p>pod을 제거할때 발생하는 단계로, 안에 있는 모든 노드에 delete signal를 보낸다. 마찬가지로 container의 종료를 기다리고, 종료되지 않으면 강제로 종료한다.</p>
<p><img src="https://velog.velcdn.com/images/hyunsu_prog/post/d527d0c9-1501-4b92-a707-4e53f73ce220/image.png" alt=""></p>
<h1 id="summary">Summary</h1>
<p>앞에서 알아본 container와 pod의 lifecycle를 요약하면 다음과 같다.</p>
<p><img src="https://velog.velcdn.com/images/hyunsu_prog/post/08fb4312-6e38-40a9-aab1-6b54d3f03353/image.png" alt="">
<img src="https://velog.velcdn.com/images/hyunsu_prog/post/e8d29e64-8c8c-4fce-b161-84f8d0376af1/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Application 실행하기]]></title>
            <link>https://velog.io/@hyunsu_prog/5.-Application-%EC%8B%A4%ED%96%89%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@hyunsu_prog/5.-Application-%EC%8B%A4%ED%96%89%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 12 Mar 2024 02:27:58 GMT</pubDate>
            <description><![CDATA[<p>Kubernetes in Action, Second Edition MEAP V15 정리중</p>
<h2 id="remind-pods">Remind Pods</h2>
<p><code>pod</code>이란 Container들을 여러 개 모아 한꺼번에 실행시키는 집합으로, 한 <code>pod</code>의 구성 container들은 모두 같은 node에 담겨 있다.</p>
<p><code>pod</code>을 사용하는 이유?
-&gt; 여러 프로세스를 사용하기 위해서</p>
<p>한 container 안에 여러 프로세스를 실행시키지 않고 프로세스별로 container를 분할하는 이유?
-&gt; container 자체가 하나의 프로세스만을 위해 디자인됨. container 안의 프로세스가 여러개 있어도 구분 X</p>
<p><img src="https://velog.velcdn.com/images/hyunsu_prog/post/2214ee4d-446a-4abb-b67b-d7cd16d64d91/image.png" alt=""></p>
<blockquote>
<p>pod를 사용함으로써 각각의 프로세스가 container 안에서 독립적으로 실행할 수 있다. 또한 같은 namespace들을 공유함으로써 프로세스끼리 통신을 단일 컴퓨터 안에서처럼 가능하게 한다.</p>
</blockquote>
<p>&nbsp;
하나의 <code>pod</code> 안에는 하나의 application을 넣는 것을 권장한다.
<strong>why?)</strong> pod의 단위별로 node에 배치되고 horizontal scaling이 일어나기 때문
<img src="https://velog.velcdn.com/images/hyunsu_prog/post/dde50f87-153a-434f-8c98-2d1d00d5c6d0/image.png" alt=""></p>
<h4 id="sidecar-패턴">sidecar 패턴</h4>
<p>따라서 pod의 구조는 보통 메인 기능을 하는 1개의 primary container와 메인 기능 보조나 추가 기능을 하는 여러 개의 sidecar container로 분리된다.
<img src="https://velog.velcdn.com/images/hyunsu_prog/post/3a4c998b-f28b-46c7-ac3d-80a3efed9bb6/image.png" alt=""></p>
<h2 id="pod-실습">Pod 실습</h2>
<h4 id="pod-만들기">Pod 만들기</h4>
<p>다음과 같이 yaml을 만들고 apply를 해서 pod을 만들 수 있다.</p>
<pre><code>// kubia.yaml
apiVersion: v1 
kind: Pod 
metadata:
 name: kubia
spec:
 containers:
 - name: kubia
 image: luksa/kubia:1.0
 ports:
 - containerPort: 8080</code></pre><pre><code>$ kubectl apply -f pod.kiada.yaml
pod &quot;kiada&quot; created</code></pre><p>이렇게 만들어진 pod의 정보를 보자.</p>
<pre><code>$ kubectl get pod kiada
NAME READY STATUS RESTARTS AGE
kiada 1/1 Running 0 32s

$ kubectl describe pod kiada
Name: kiada
Namespace: default
Priority: 0
Node: worker2/172.18.0.4
Start Time: Mon, 27 Jan 2020 12:53:28 +0100
...</code></pre><h4 id="request-보내기">Request 보내기</h4>
<p>pod 자체의 고유 IP주소가 있지만 이것은 내부에서 다른 pod들이 접근할때 사용됨 -&gt; 다른 방법 필요</p>
<pre><code>$ kubectl get pod kiada -o wide
NAME     READY     STATUS     RESTARTS     AGE    IP             NODE     ...
kiada     1/1     Running    0             35m 10.244.2.4     worker2 ...</code></pre><p>IP를 확인했으니 이제 port 번호만 pod definition에서 확인하면 주소가 확정된다.
알아낸 주소로 보내면 응답이 온다.</p>
<pre><code>$ curl 10.244.2.4:8080
Kiada version 0.1. Request processed by &quot;kiada&quot;. Client IP: ::ffff:10.244.2.1</code></pre><p>&nbsp;</p>
<p>로컬에서 확인할 경우, <code>kubectl port-forward</code>를 사용하여 통신하는 방법이 있다. 로컬로 연결되는 proxy를 사용하여 통신한다.</p>
<pre><code>$ kubectl port-forward kiada 8080
... Forwarding from 127.0.0.1:8080 -&gt; 8080
... Forwarding from [::1]:8080 -&gt; 8080

$ curl localhost:8080
Kiada version 0.1. Request processed by &quot;kiada&quot;. Client IP: ::ffff:127.0.0.1</code></pre><p>이것을 그림으로 나타내면 다음과 같다.</p>
<p><img src="https://velog.velcdn.com/images/hyunsu_prog/post/9e8579a0-0309-4fe5-a49e-3792be96e5fb/image.png" alt=""></p>
<h4 id="request-log-확인">Request log 확인</h4>
<p>node.js application은 stdout으로 log를 보내기 때문에, 다음과 같이 확인할 수 있다.</p>
<pre><code>$ kubectl logs kiada
Kiada - Kubernetes in Action Demo Application
---------------------------------------------
Kiada 0.1 starting...
Local hostname is kiada
Listening on port 8080
Received request for / from ::ffff:10.244.2.1 #A
Received request for / from ::ffff:10.244.2.5 #B
Received request for / from ::ffff:127.0.0.1 #C</code></pre><p>또는 이렇게 하면 로그를 실시간으로 볼 수 있다.</p>
<pre><code>$ kubectl logs kiada -f </code></pre><h4 id="file-copy">File copy</h4>
<pre><code>$ kubectl cp kiada:html/index.html /tmp/index.html</code></pre><h4 id="명령어-실행">명령어 실행</h4>
<pre><code>$ kubectl exec kiada -- ps aux</code></pre><h4 id=""></h4>
]]></description>
        </item>
        <item>
            <title><![CDATA[Kubernetes API objects]]></title>
            <link>https://velog.io/@hyunsu_prog/4.-Kubernetes-API-objects</link>
            <guid>https://velog.io/@hyunsu_prog/4.-Kubernetes-API-objects</guid>
            <pubDate>Fri, 01 Mar 2024 17:17:57 GMT</pubDate>
            <description><![CDATA[<p>Kubernetes in Action, Second Edition MEAP V15 정리중</p>
<h2 id="kubernetes-api란">Kubernetes API란?</h2>
<p>Kubernetes cluster 안의 정보들을 CRUD하기 위한 http based RESTful API</p>
<p><img src="https://velog.velcdn.com/images/hyunsu_prog/post/c5ec9950-35ef-4c72-b94b-80e1d08e472a/image.png" alt=""></p>
<p>REST API를 통해 CRUD할 수 있는 cluster의 구성정보들을 resource나 object라고 부른다.
resource는 <strong>/apis/apps</strong>/v1/<strong>namespaces</strong>/myns/<strong>deployments</strong>/mydeploy 이런 느낌으로 카테고리 &gt; 세부문서 &gt; 카테고리 &gt; 세부문서 로 파싱 가능하다.</p>
<h3 id="object의-구성요소-4가지">object의 구성요소 4가지:</h3>
<p><strong>1. Metadata</strong> - object의 type을, type이 속한 그룹, 버전들을 나타낸다.
<strong>2. Object Metadata</strong> - object의 이름, 생성 날짜, 소유자 등을 나타낸다.
<strong>3. Spec</strong> - object가 되기를 바라는 상태<strong>(desired state)</strong>를 나타낸다. Pod의 경우 이는 Pod의 컨테이너, 저장공간 크기 등이다.
<strong>4. Status</strong> - object의 실제 상태<strong>(actual state)</strong>를 나타낸다. Pod의 경우 이는 Pod의 상태, 각 컨테이너의 상태, IP 주소, 실행 중인 노드 등과 같이 Pod에 대한 현재 상황을 나타내는 정보이다.</p>
<p>Kubernetes Control plane은 각각의 type에 맞는 type controller를 사용해 Spec의 내용을 읽어와 desired state가 되도록 수행하고, 결과를 Status에 저장하여 보내준다.
<img src="https://velog.velcdn.com/images/hyunsu_prog/post/36537be3-d8da-4974-9fcd-28aa4613217d/image.png" alt=""></p>
<h2 id="kubernetes-api-예제">Kubernetes API 예제</h2>
<h3 id="node-배치-확인">Node 배치 확인</h3>
<p>예를 들어서 <code>kubectl get nodes</code> 명령시 다음과 같은 결과가 나왔다고 해보자.</p>
<pre><code>$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
kind-control-plane Ready master 1h v1.18.2
kind-worker Ready &lt;none&gt; 1h v1.18.2
kind-worker2 Ready &lt;none&gt; 1h v1.18.2 </code></pre><p>그러면 Kubernetes API는 그림과 같이 구성된다. API 안의 node object들은 각각 실제 node(즉 실제 컴퓨터)와 대응된다.
<img src="https://velog.velcdn.com/images/hyunsu_prog/post/eab9ee77-0c98-479f-b23a-12dc86b397a5/image.png" alt=""></p>
<h3 id="kubectl-get-node">kubectl get node</h3>
<p>node object의 정보를 자세히 확인하려면 <code>kubectl get node &lt;node-name&gt; -o yaml</code> 명령을 입력한다. object의 4가지 구성요소가 있는것을 확인할 수 있다.</p>
<pre><code>$ kubectl get node kind-control-plane -o yaml
apiVersion: v1
kind: Node
metadata:
 annotations: ...
 creationTimestamp: &quot;2020-05-03T15:09:17Z&quot; 
 labels: ...
 managedFields: ...
 name: kind-control-plane
 resourceVersion: &quot;3220054&quot;
 selfLink: /api/v1/nodes/kind-control-plane
 uid: 16dc1e0b-8d34-4cfb-8ade-3b0e91ec838b 
spec:
 podCIDR: 10.244.0.0/24
 podCIDRs:
 - 10.244.0.0/24
 taints:
 - effect: NoSchedule
 key: node-role.kubernetes.io/master 
status:
 addresses:
 - address: 172.18.0.2 
 type: InternalIP
 - address: kind-control-plane
 type: Hostname 
 allocatable: ...
 capacity:
 cpu: &quot;8&quot; 
 ephemeral-storage: 401520944Ki
 hugepages-1Gi: &quot;0&quot; 
 hugepages-2Mi: &quot;0&quot;
 memory: 32720824Ki 
 pods: &quot;110&quot; 
 conditions: 
 - lastHeartbeatTime: &quot;2020-05-17T12:28:41Z&quot;
 lastTransitionTime: &quot;2020-05-03T15:09:17Z&quot;
 message: kubelet has sufficient memory available 
 reason: KubeletHasSufficientMemory
 status: &quot;False&quot;
 type: MemoryPressure
 ...
 daemonEndpoints:
 kubeletEndpoint:
 Port: 10250 
 images:
 - names:
 - k8s.gcr.io/etcd:3.4.3-0
 sizeBytes: 289997247
 ...
 nodeInfo:
 architecture: amd64 
 bootID: 233a359f-5897-4860-863d-06546130e1ff 
 containerRuntimeVersion: containerd://1.3.3-14-g449e9269
 kernelVersion: 5.5.10-200.fc31.x86_64
 kubeProxyVersion: v1.18.2
 kubeletVersion: v1.18.2 
 machineID: 74b74e389bb246e99abdf731d145142d
 operatingSystem: linux
 osImage: Ubuntu 19.10
 systemUUID: 8749f818-8269-4a02-bdc2-84bf5fa21700</code></pre><p>사실 너무 길어서 처음부터 무슨말인지 알아보기 힘들다..</p>
<h4 id="conditions">conditions</h4>
<p>node의 status 필드의 한 예시로 <code>conditions</code>라는 부분이 있다. <code>conditions</code>란 object가 현재 처한 상황들을 배열로 저장해놓은 것이다. 디버깅할 때 많이 쓰이므로, 각 구성요소만 짧게 알아보자.
<code>lastTransitionTime</code>: conditions가 마지막으로 업데이트된 시점
<code>lastHeartbeatTime</code>: conditions 업데이트가 마지막으로 controller에게 전달된 시점
<code>message</code>, <code>reason</code>: 현재 상태
<code>type</code>: 어느 영역에서 해당 conditions가 나타나는지
<code>status</code>: conditions를 True, False, Unknown으로 알려줌</p>
<h3 id="kubectl-explain">kubectl explain</h3>
<p>필드들에 대한 자세한 설명은 <code>kubectl explain &lt;kind&gt;</code> 아니면 <code>kubectl explain &lt;kind&gt;.&lt;subkind&gt;</code> 이런식으로 입력하면 각 object들의 field에 대한 설명이 나온다.</p>
<pre><code>$ kubectl explain nodes
KIND: Node
VERSION: v1
DESCRIPTION:
 Node is a worker node in Kubernetes. Each node will have a unique
 identifier in the cache (i.e. in etcd).
FIELDS:
 apiVersion &lt;string&gt;
 APIVersion defines the versioned schema of this representation of an
 object. Servers should convert recognized schemas to the latest...
 kind &lt;string&gt;
 Kind is a string value representing the REST resource this object
 represents. Servers may infer this from the endpoint the client...
 metadata &lt;Object&gt;
 Standard object&#39;s metadata. More info: ...
 spec &lt;Object&gt;
 Spec defines the behavior of a node...
 status &lt;Object&gt;
 Most recently observed status of the node. Populated by the system.
 Read-only. More info: ... </code></pre><h3 id="kubectl-describe">kubectl describe</h3>
<p><code>kubectl describe</code>라는 명령도 입력해볼 수 있다. 이것은 아까 했던 <code>kubectl get node &lt;node-name&gt; -o yaml</code>를 조금 간략하게 정리해주고, 자원 할당량과 최근 이벤트들을 표시한다.</p>
<pre><code>$ kubectl describe node kind-worker-2
Name: kind-worker2
Roles: &lt;none&gt;
Labels: beta.kubernetes.io/arch=amd64
 beta.kubernetes.io/os=linux
 kubernetes.io/arch=amd64
 kubernetes.io/hostname=kind-worker2
 kubernetes.io/os=linux
Annotations: kubeadm.alpha.kubernetes.io/cri-socket: /run/contain...
 node.alpha.kubernetes.io/ttl: 0 
  volumes.kubernetes.io/controller-managed-attach-deta...
CreationTimestamp: Sun, 03 May 2020 17:09:48 +0200
Taints: &lt;none&gt;
Unschedulable: false
Lease:
 HolderIdentity: kind-worker2
 AcquireTime: &lt;unset&gt;
 RenewTime: Sun, 17 May 2020 16:15:03 +0200
Conditions:
 Type Status ... Reason Message
 ---- ------ --- ------ -------
 MemoryPressure False ... KubeletHasSufficientMemory ...
 DiskPressure False ... KubeletHasNoDiskPressure ...
 PIDPressure False ... KubeletHasSufficientPID ...
 Ready True ... KubeletReady ...
Addresses:
 InternalIP: 172.18.0.4
 Hostname: kind-worker2
Capacity:
 cpu: 8
 ephemeral-storage: 401520944Ki
 hugepages-1Gi: 0
 hugepages-2Mi: 0
 memory: 32720824Ki
 pods: 110
Allocatable:
 ...
System Info:
 ...
PodCIDR: 10.244.1.0/24
PodCIDRs: 10.244.1.0/24
Non-terminated Pods: (2 in total)
 Namespace Name CPU Requests CPU Limits ... AGE
 --------- ---- ------------ ---------- ... ---
 kube-system kindnet-4xmjh 100m (1%) 100m (1%) ... 13d
 kube-system kube-proxy-dgkfm 0 (0%) 0 (0%) ... 13d
Allocated resources:
 (Total limits may be over 100 percent, i.e., overcommitted.)
 Resource Requests Limits
 -------- -------- ------
 cpu 100m (1%) 100m (1%)
 memory 50Mi (0%) 50Mi (0%)
 ephemeral-storage 0 (0%) 0 (0%)
 hugepages-1Gi 0 (0%) 0 (0%)
 hugepages-2Mi 0 (0%) 0 (0%)
Events:
 Type Reason Age From Message
 ---- ------ ---- ---- -------
 Normal Starting 3m50s kubelet, kind-worker2 ...
 Normal NodeAllocatableEnforced 3m50s kubelet, kind-worker2 ...
 Normal NodeHasSufficientMemory 3m50s kubelet, kind-worker2 ...
 Normal NodeHasNoDiskPressure 3m50s kubelet, kind-worker2 ...
 Normal NodeHasSufficientPID 3m50s kubelet, kind-worker2 ...
 Normal Starting 3m49s kube-proxy, kind-worker2 ... </code></pre><h3 id="event-object">event object</h3>
<p>controller가 current state과 desired state를 맞춰가기 위해 작업한 목록들을 적어놓은 object이다. <code>Normal</code> 타입의 이벤트는 정상적으로 처리된 것, <code>Warning</code> 타입은 뭔가가 방해한 것이다.
<code>event object</code>는 controll plane의 <code>etcd</code>에 저장되고, 생성되고 1시간 후에 지워진다.</p>
<p><img src="https://velog.velcdn.com/images/hyunsu_prog/post/2ca6aa4b-0e02-43a5-abe4-ee09476b7f1c/image.png" alt=""></p>
<p><code>event object</code>들도 <code>kubectl get</code> 커맨드로 볼 수 있다.
Type이 Warning인 것만 보려면, <code>kubectl get ev --field-selector type=Warning</code> 이렇게 검색하면 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Kubernetes 활용 예제]]></title>
            <link>https://velog.io/@hyunsu_prog/3.-Kubernetes-%ED%99%9C%EC%9A%A9-%EC%98%88%EC%A0%9C</link>
            <guid>https://velog.io/@hyunsu_prog/3.-Kubernetes-%ED%99%9C%EC%9A%A9-%EC%98%88%EC%A0%9C</guid>
            <pubDate>Wed, 28 Feb 2024 05:42:25 GMT</pubDate>
            <description><![CDATA[<p>Kubernetes in Action, Second Edition MEAP V15 정리중</p>
<h2 id="kubernetes-사용법">Kubernetes 사용법</h2>
<h3 id="prerequisites-docker">(prerequisites) docker</h3>
<p>Kubernetes cluster는 docker를 통해 실행시킬 수 있다.</p>
<p>docker에서 환경설정 -&gt; Kubernetes -&gt; Enable Kubernetes</p>
<p><img src="https://velog.velcdn.com/images/hyunsu_prog/post/95eab9e7-df19-4c68-8304-359445c4d188/image.png" alt=""></p>
<p>docker의 container는 다음과 같은 구조를 갖는다.</p>
<p><img src="https://velog.velcdn.com/images/hyunsu_prog/post/b00ca7eb-93e6-49f9-a3f9-edc310891bd5/image.png" alt=""></p>
<h3 id="minikube">Minikube</h3>
<ol>
<li><a href="https://github.com/kubernetes/minikube">https://github.com/kubernetes/minikube</a> 들어간다.</li>
<li>Readme의 Installation 들어가서 파일 다운받는다.</li>
<li>minikube start</li>
</ol>
<pre><code>C:\Windows\system32&gt;minikube start
* minikube v1.32.0 on Microsoft Windows 10 Education 10.0.19045.4046 Build 19045.4046
* Automatically selected the docker driver. Other choices: hyperv, virtualbox, ssh
* Using Docker Desktop driver with root privileges
* Starting control plane node minikube in cluster minikube
* Pulling base image ...
* Downloading Kubernetes v1.28.3 preload ...
    &gt; preloaded-images-k8s-v18-v1...:  403.35 MiB / 403.35 MiB  100.00% 27.43 M
    &gt; gcr.io/k8s-minikube/kicbase...:  453.90 MiB / 453.90 MiB  100.00% 25.04 M
* Creating docker container (CPUs=2, Memory=4000MB) ...
* Preparing Kubernetes v1.28.3 on Docker 24.0.7 ...
  - Generating certificates and keys ...
  - Booting up control plane ...
  - Configuring RBAC rules ...
* Configuring bridge CNI (Container Networking Interface) ...
* Verifying Kubernetes components...
  - Using image gcr.io/k8s-minikube/storage-provisioner:v5
* Enabled addons: storage-provisioner, default-storageclass
* Done! kubectl is now configured to use &quot;minikube&quot; cluster and &quot;default&quot; namespace by default</code></pre><p>minikube의 구조는 다음과 같다.</p>
<p><img src="https://velog.velcdn.com/images/hyunsu_prog/post/828a2ee7-ecd3-46f1-85aa-2d6527c97a88/image.png" alt=""></p>
<h3 id="kind-kubernetes-in-docker">Kind (Kubernetes in docker)</h3>
<p>kind는 minikube와 달리 한 cluster에 여러 개의 node가 들어가 있다. VM 환경이 따로 지원되지 않아, 컨테이너는 host OS와 같은 환경에서 실행되고 따라서 컨테이너 내부에서 같은 컴파일 환경이나 프로그램 동작등을 지원할 수 있다.</p>
<p>다음은 kind의 작동 방식이다.</p>
<p><img src="https://velog.velcdn.com/images/hyunsu_prog/post/4afa6265-d1a9-4c3b-956e-df9f775d5c2d/image.png" alt=""></p>
<h3 id="gke-google-kubernetes-engine">GKE (Google Kubernetes Engine)</h3>
<p>Google에서 Kubernetes의 기능들을 google cloud로 지원해 주어 복잡한 초기 설정 없이 인터넷 환경에서 바로 이용하게 해주는 것이다. 구조는 다음과 같다.</p>
<p><img src="https://velog.velcdn.com/images/hyunsu_prog/post/ed588599-1bfa-4bed-9409-69eb44c8dd97/image.png" alt=""></p>
<h3 id="직접-엔진-만들기">직접 엔진 만들기</h3>
<p>직접 Kubernetes 서비스의 구조를 만들어 볼 수도 있다.
<a href="https://github.com/kelseyhightower/Kubernetes-the-hard-way">https://github.com/kelseyhightower/Kubernetes-the-hard-way</a></p>
<p>나중에 써먹을지도..?</p>
<p>&nbsp;</p>
<h2 id="kubernetes-cli">Kubernetes cli</h2>
<h3 id="kubectlkube-controller">kubectl(kube controller)</h3>
<p>kubectl은 Control plane에 요청할 수 있는 cli tool이다. 다음과 같은 구조로 유저가 kubectl를 통해 API Server에 전달하면, Control plane이 요청에 맞는 작업을 수행한다.</p>
<p><img src="https://velog.velcdn.com/images/hyunsu_prog/post/45cb6518-1bf6-4281-a6fb-f314ec56538a/image.png" alt=""></p>
<p>kubectl의 기본적인 명령어들은 다음과 같다.</p>
<ul>
<li>Kubernetes의 현재 cluster 상태 정보 확인</li>
</ul>
<pre><code>$ kubectl cluster-info
Kubernetes control plane is running at https://127.0.0.1:53107
CoreDNS is running at https://127.0.0.1:53107/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy</code></pre><ul>
<li>현재 모든 node들 list up 하기</li>
</ul>
<pre><code>$ kubectl get nodes
NAME                 STATUS   ROLES           AGE    VERSION
kind-control-plane   Ready    control-plane   102m   v1.29.2</code></pre><ul>
<li>선택한 node 정보 자세히 알아보기</li>
</ul>
<pre><code>$ kubectl describe node kind-control-plane
Name:               kind-control-plane
Roles:              control-plane
...</code></pre><h3 id="kube-dashboard">kube dashboard</h3>
<p>GUI로 현재 상태를 확인할 수 있는 대시보드 또한 존재한다.</p>
<p>&nbsp;</p>
<h2 id="kubernetes-핵심-개념">Kubernetes 핵심 개념</h2>
<h3 id="pod">pod</h3>
<p>pod란 container들을 묶어서 같은 namespace를 공유하고 한번에 실행할 수 있게 하느 단위로, 같은 pod은 IP(network namespace)와 system hostname(UTS namespace)같은걸 공유할 수 있고 서로 더 쉽게 통신할 수 있다.</p>
<p>즉 pod이란 하나의 application를 실행하는 논리적인 컴퓨터라고 할 수 있다. application에서는 한개 또는 여러개의 container를 필요로 할 수도 있다.</p>
<p><img src="https://velog.velcdn.com/images/hyunsu_prog/post/28f3510a-aca3-4134-89c8-cb31de4aa7b2/image.png" alt=""></p>
<h3 id="deployment">deployment</h3>
<p>deployment는 pod을 정해진 <strong>replica</strong> 수만큼 생성하고 id를 부여하는 object이다. pod이 갑자기 삭제되거나 pod이 존재하는 노드의 이상 등으로 문제가 생길 때, deployment는 replica의 수를 일정하게 만들어주기 위해 추가로 pod을 만들어준다. </p>
<h3 id="service">service</h3>
<p>service는 실행중인 pod들이 외부와 통신할 수 있도록 연결해주는 object이다. 외부에서 요청이 들어오면 service는 traffic에 따라 pod들에게 적절히 load-balancing해주고, pod이 삭제되고 재생성될 경우, 변경된 IP주소등 pod의 정보를 갱신한다.</p>
<p>이것들의 논리적 구조는 다음과 같다.
<img src="https://velog.velcdn.com/images/hyunsu_prog/post/f2dcf72a-bfef-40b6-9794-c4d8604785eb/image.png" alt=""></p>
<p>&nbsp;</p>
<h2 id="kubernetes-실습">Kubernetes 실습</h2>
<p>kubernetes cluster에 application을 넣어본다. 미리 요약하자면 <code>kubectl create deployment</code> 명령어를 통해 pod을 만들고, <code>kubectl expose deployment</code>를 통해 외부로 노출시키면 된다.</p>
<h4 id="1-luksakubia10라는-container를-사용하여-kubia라는-deployment를-만든다">1. luksa/kubia:1.0라는 container를 사용하여 kubia라는 deployment를 만든다.</h4>
<pre><code>$ kubectl create deployment kubia --image=luksa/kubia:1.0
deployment.apps/kubia created </code></pre><p>deployment object용 container들의 상태를 확인해보면 방금 만든게 나올 것이다.</p>
<pre><code>$ kubectl get deployments
NAME     READY     UP-TO-DATE     AVAILABLE     AGE
kubia     0/1     1             0             6s </code></pre><p>UP-TO_DATE가 1이므로 이 application은 1개의 instance를 갖는다. 또한 AVAILABLE이 0이므로 application이 아직 사용할수 없음을 나타낸다.</p>
<h4 id="2-deployment로-만들어진-pod의-정보를-확인한다-생성한-container가-들어있는-pod을-확인할-수-있다">2. deployment로 만들어진 pod의 정보를 확인한다. 생성한 container가 들어있는 pod을 확인할 수 있다.</h4>
<pre><code>$ kubectl get pods
NAME                     READY     STATUS     RESTARTS    AGE
kubia-587b7cd6b7-85zbh     0/1     Pending    0             1m </code></pre><p>pod이 Ready 상태인데, 이것은 pod이 할당된 worker node가 container image를 다운받고 있는 중이기 때문이다. 모두 다운받으면 Running state로 넘어간다.</p>
<p>pod의 로그등 자세한 정보를 확인하려면 다음과 같이 한다.</p>
<pre><code>$ kubectl describe pod
Name:             kubia-587b7cd6b7-85zbh
Namespace:        default

...

Events:
  Type    Reason          Age   From     Message
  ----    ------          ----  ----     -------
  Normal  SandboxChanged  21m   kubelet  Pod sandbox changed, it will be killed and re-created.
  Normal  Pulled          21m   kubelet  Container image &quot;luksa/kubia:1.0&quot; already present on machine
  Normal  Created         21m   kubelet  Created container kubia
  Normal  Started         21m   kubelet  Started container kubia</code></pre><p>이 과정을 그림으로 나타내면 다음과 같다.</p>
<p><img src="https://velog.velcdn.com/images/hyunsu_prog/post/bd6c6047-b1a3-46aa-8a78-1318a57f82a9/image.png" alt=""></p>
<h4 id="3-service-object를-만든다-load-balancer-service라는-service-object를-만들어-이를-통해-외부와-통신할-수-있다">3. service object를 만든다. load balancer service라는 service object를 만들어, 이를 통해 외부와 통신할 수 있다.</h4>
<pre><code>$ kubectl expose deployment kubia --type=LoadBalancer --port 8080
service/kubia exposed</code></pre><p>생성된 service 객체를 확인하면 다음과 같다.</p>
<pre><code>$ kubectl get svc
NAME         TYPE           CLUSTER-IP    EXTERNAL-IP   PORT(S)          AGE
kubernetes   ClusterIP      10.96.0.1     &lt;none&gt;        443/TCP          18h
kubia        LoadBalancer   10.96.245.7   &lt;pending&gt;     8080:30953/TCP   3m7s</code></pre><p>load balancer service까지 만들게 되면, kubernetes는 외부의 cloud 서비스에게 load-balancer를 제공하도록 요청한다. 그러면 cloud provider가 load-balancer를 만들고 사용자의 traffic을 잘 쪼개어 worker node들에 보내준다.</p>
<p><img src="https://velog.velcdn.com/images/hyunsu_prog/post/08804618-74c1-4b97-9a36-6d893cb86b75/image.png" alt=""></p>
<h4 id="4-load-balancer가-만들어지면-external-ip가-생성되고-이것을-통해-요청을-보낼-수-있다">4. load-balancer가 만들어지면 EXTERNAL-IP가 생성되고 이것을 통해 요청을 보낼 수 있다.</h4>
<p><strong>+</strong> minikube를 사용하는 경우 load balaner를 제공해주지 않는데, 이 경우 <code>minikube service kubia --url</code> 명령으로 외부주소를 찾아내면 된다.</p>
<h4 id="5-더-많은-traffic에-대비해-horizontal-scaling-out을-진행한다">5. 더 많은 traffic에 대비해 horizontal scaling out을 진행한다.</h4>
<pre><code>$ kubectl scale deployment kubia --replicas=3
deployment.apps/kubia scaled </code></pre><p>이렇게 하면 다음과 같이 pod가 확장된다.</p>
<pre><code>$ kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
kubia 3/3 3 3 18m 

$ kubectl get pods
NAME READY STATUS RESTARTS AGE
kubia-9d785b578-58vhc 1/1 Running 0 17s
kubia-9d785b578-jmnj8 1/1 Running 0 17s
kubia-9d785b578-p449x 1/1 Running 0 18m </code></pre><p>각 pod가 어떤 node에 담겼는지 확인하려면 다음과 같이 한다.</p>
<pre><code>$ kubectl get pods -o wide
NAME ... IP NODE
kubia-9d785b578-58vhc ... 10.244.1.5 worker1 #A
kubia-9d785b578-jmnj8 ... 10.244.2.4 worker2 #B
kubia-9d785b578-p449x ... 10.244.2.3 worker2 #B </code></pre><p>pod을 여러개 만들어 node들에 뿌릴 경우, 요청들에 대한 흐름도는 적절한 load-balancing을 통해 pod들로 뿌려진다.
<img src="https://velog.velcdn.com/images/hyunsu_prog/post/0571cc8c-fff2-402b-8ab3-6aec0d338b8d/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Container 이해]]></title>
            <link>https://velog.io/@hyunsu_prog/2.-Container-%EC%9D%B4%ED%95%B4</link>
            <guid>https://velog.io/@hyunsu_prog/2.-Container-%EC%9D%B4%ED%95%B4</guid>
            <pubDate>Thu, 22 Feb 2024 19:48:45 GMT</pubDate>
            <description><![CDATA[<p>Kubernetes in Action, Second Edition MEAP V15 정리중</p>
<h2 id="container와-virtual-machine-비교">Container와 Virtual machine 비교</h2>
<p>Container는 VM과 다르게 하나의 OS 위에서 process 단위로만 나눈다
-&gt; VM보다 훨씬 가벼움
하나의 Container위에서는 무조건 하나의 application만 동작!
<img src="https://velog.velcdn.com/images/hyunsu_prog/post/f0d25e4c-53e1-4c32-b688-fe096277d71f/image.png" alt=""></p>
<p>system call등을 단일 kernel 하나로만 처리함. 하지만 container들끼리는 다른 container를 무시하고 자신만 kernel과 통신하는 것으로 취급됨. 하지만 논리적으로 완벽한 분리는 아니므로 VM보다 안정적으로 독립성 보장은 X.
<img src="https://velog.velcdn.com/images/hyunsu_prog/post/b44262a2-aa7a-4656-9ff7-447b4727ccc6/image.png" alt=""></p>
<h2 id="docker-알아보기">Docker 알아보기</h2>
<p>application을 패키징하여 distributing, running하는 플랫폼으로 도커를 사용하면 application을 필요한 환경(DLL, OS의 부분 등)과 하나로 묶어 다른 OS를 가진 어떤 컴퓨터 위에서든 실행 가능</p>
<p>Docker의 핵심 개념 3가지
<strong>Image</strong> - application과 필요한 환경을 하나로 묶어 zip해 놓은 패키지 단위
<strong>Registry</strong> - Image의 저장소이고, 다른사람과 공유 가능. git같은 개념인듯
<strong>Container</strong> - Image를 instance화 하여 제한된 리소스 하에서 실행하는 공간</p>
<p><strong>Image layer</strong>
application을 실행하기 위한 요구사항들을 layer로 쌓아서 관리함
Q. 그러면 container 공통으로 쓰이는 file들에 대해서는 자원의 변경사항을 공유하는 것 아닌가?
A. container 각각의 read-write layer에서 file을 수정하므로 read-only layer에 있는 원본에는 변화 X
<img src="https://velog.velcdn.com/images/hyunsu_prog/post/4358ab83-88d0-49e1-af7f-4fe3ea8b6415/image.png" alt=""></p>
<h3 id="docker의-한계">Docker의 한계</h3>
<p>Docker에서는 자체적인 kernel를 가지고 있지 않으므로 application이 요구하는 kernel 버전이나 kernel module이 없으면 실행 불가능
-&gt; hardware architecture이 다르면(ex. x86과 ARM) 실행 불가능
<img src="https://velog.velcdn.com/images/hyunsu_prog/post/b7f74689-ab22-4d29-ae76-215ac22293bf/image.png" alt=""></p>
<p>Docker자체는 process를 격리하지 않고, 실제 container 격리는 linux kernel 수준에서 이루어진다.</p>
<h2 id="docker-실습">Docker 실습</h2>
<h3 id="컨테이너-다운받기">컨테이너 다운받기</h3>
<p><strong>busybox</strong> - echo, ls등 linux 명령어들 모아놓은 단일파일</p>
<blockquote>
<p>$ docker run busybox echo &quot;Hello World&quot;</p>
</blockquote>
<p>실행하면 다음과 같이 나온다.</p>
<blockquote>
<p>Unable to find image &#39;busybox:latest&#39; locally
latest: Pulling from library/busybox
7c9d20b9b6cd: Pull complete
Digest: sha256:fe301db49df08c384001ed752dff6d52b4…
Status: Downloaded newer image for busybox:latest
Hello World</p>
</blockquote>
<p>이것의 작동 원리는 다음과 같다.
<img src="https://velog.velcdn.com/images/hyunsu_prog/post/684b9226-f1b3-4dd5-96b0-5103e8242393/image.png" alt=""></p>
<ol>
<li>Docker CLI에서 Docker daemon에 명령 전달</li>
<li>Docker daemon이 로컬에서 해당 image 있는지 확인</li>
<li>없으므로 registry에서 image 가져옴</li>
<li>Docker에서 container 만든 후 echo &quot;Hello World&quot; 커맨드 실행</li>
</ol>
<h3 id="파일-직접-패키징하여-업로드하기">파일 직접 패키징하여 업로드하기</h3>
<ol>
<li>파일 하나 만든다.<pre><code>// app.js
</code></pre></li>
</ol>
<p>const http = require(&#39;http&#39;);
const os = require(&#39;os&#39;);
const listenPort = 8080;
36
©Manning Publications Co. To comment go to liveBook
console.log(&quot;Kubia server starting...&quot;);
console.log(&quot;Local hostname is &quot; + os.hostname());
console.log(&quot;Listening on port &quot; + listenPort);
var handler = function(request, response) {
 let clientIP = request.connection.remoteAddress;
 console.log(&quot;Received request for &quot;+request.url+&quot; from &quot;+clientIP);
 response.writeHead(200);
 response.write(&quot;Hey there, this is &quot;+os.hostname()+&quot;. &quot;);
 response.write(&quot;Your IP is &quot;+clientIP+&quot;. &quot;);
 response.end(&quot;\n&quot;);
};
var server = http.createServer(handler);
server.listen(listenPort);</p>
<pre><code>
2. Dockerfile이라는 것을 만들어야 한다.</code></pre><p>// Dockerfile</p>
<p>FROM node:12
ADD app.js /app.js
ENTRYPOINT [&quot;node&quot;, &quot;app.js&quot;]</p>
<pre><code>
3. Docker cli로 실행시켜준다.
&gt; $ docker build -t kubia:latest .

4. 완성된 image는 docker images 명령어로 확인해보면 다음과 같이 나온다.
&gt; kubia        latest    ca0deb942e03   About a minute ago   918MB

빌드의 원리는 다음과 같다.


![](https://velog.velcdn.com/images/hyunsu_prog/post/338e83ae-33ea-420a-84c2-812dddcd4bef/image.png)

1. Docker cli가 명령어를 가지고 파일들을 Linux에 있는 Docker daemon으로 보내준다.
2. Docker Daemon이 node:12 이미지를 가져온다.
3. Dockerfile의 명령어 한줄씩 layer를 추가해준다.


이미지를 실행하려면 다음 명령어를 입력한다.
&gt; $ docker run --name kubia-container -p 1234:8080 -d kubia

kubia 이미지로부터 kubia-container라는 이름의 컨테이너를 만들고 local 컴퓨터의 1234포트를 컨테이너의 8080과 연결하여 실행한다.
![](https://velog.velcdn.com/images/hyunsu_prog/post/e10afce3-f296-49f0-92e4-67e7e342cdc2/image.png)

### 이미지 배포하기

1. 이미지에 tag(이미지의 다른 이름 + 버전정보)를 붙여준다.
&gt; $ docker tag kubia luksa/kubia:1.0 

2. docker에 로그인한 후 업로드한다.
&gt; $ docker login -u yourid -p yourpassword docker.io
$ docker push yourid/kubia:1.0

3. 다른 컴퓨터에서 이미지를 받아 쓰려면 다음을 입력한다.
&gt; $ docker run -p 1234:8080 -d yourid/kubia:1.0 

### 컨테이너 삭제하기

1. 컨테이너를 종료시킨다.
&gt; $ docker stop kubia-container

2. 컨테이너와 이미지를 삭제한다.
&gt; $ docker rmi kubia:latest 

&amp;nbsp;
## 컨테이너가 Isolation을 유지하는 방법

### Linux Namespace
OS의 자원들을 분할해주는 단위, process는 각각의 자원별로(파일, 네트워크, 시스템 이름 등) 자기만의 namespace를 설정하여 그 안의 자원만 참조한다.
**but)** 가끔씩 프로세스가 같은 namespace를 공유하게 하고 싶을 수도 있다.

#### Ex1) Network namespace
어떤 network interface들을 사용할 것인지 정의해 놓는 namespace. 하나의 network interface는 하나의 network namespace에만 소속될 수 있다.
![](https://velog.velcdn.com/images/hyunsu_prog/post/968d933c-0569-4884-a613-8bca72145f56/image.png)

#### Ex2) UTS namespace
프로세스가 system host name과 domain name을 뭐라고 보는지 정의하는 namespace.
두 프로세스의 UTS namespace가 다르면 서로 다른 컴퓨터 환경에서 돌아가는 것이라고 여기게 된다.

### Linux Control Groups
Linux namespace에서는 같은 OS 자원을 얼마만큼 사용할지는 정의 X
Linux Control Groups를 통해 사용하는 cpu, memory 등의 할당량 설정 가능.

### Previlege
프로세스가 어떤 system call 실행 등의 시스템 자원을 건드릴 수 있는지 권한을 설정함으로써 커널 내부의 데이터들이 이상하게 바뀌는 것 방지
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[Introducing Kubernetes]]></title>
            <link>https://velog.io/@hyunsu_prog/1.-Introducing-Kubernetes</link>
            <guid>https://velog.io/@hyunsu_prog/1.-Introducing-Kubernetes</guid>
            <pubDate>Wed, 21 Feb 2024 21:34:08 GMT</pubDate>
            <description><![CDATA[<p>Kubernetes in Action, Second Edition MEAP V15 정리중
<br /></p>
<h2 id="kubernetes란"><strong>Kubernetes란?</strong></h2>
<p>기반이 되는 hardware들 위에 abstraction layer를 제공하여 이용자들이 low-level에 신경쓰지 않고 프로그램을 쉽게 deploy하도록 도와주는 프레임워크
<br>
아래의 사진에서 나와있듯이 개발자는 application을 networt나 computer에 대한 고려 없이 Kubernetes level 위에서 실행시킬 수 있다. </p>
<p><img src="https://velog.velcdn.com/images/hyunsu_prog/post/e424aac9-ae5b-494e-9506-8146df5e6de7/image.png" alt=""></p>
<br/>
Kubernetes는 declarative model을 사용하는데, 실행하고자 하는 application을 잘 서술해주면 내부에서 이것을 실행시켜준다. 또한 reconfigure이나 restart등의 기능도 제공한다.

<p><img src="https://velog.velcdn.com/images/hyunsu_prog/post/daca40fa-b74b-48ab-8fd4-9da2348065b5/image.png" alt=""></p>
<h2 id="kubernetes는-왜-필요한가">Kubernetes는 왜 필요한가?</h2>
<h3 id="1-microservices">1. Microservices</h3>
<p>기존의 Monolithic application -&gt;
하나의 쪼갤 수 없는 단위, horizontally scaling(여러 대의 컴퓨터로 실행하는 것) 불가능
Microservices로 옮겨가며 application을 분할할 필요성 증가
but) Microservices의 경우 여러 OS의 여러 버전의 library를 관리하기 까다로움
-&gt; 분산 컴퓨팅 프레임워크
<img src="https://velog.velcdn.com/images/hyunsu_prog/post/3bf63cf1-e0d7-476c-b9b4-f61a5cdf42ad/image.png" alt=""></p>
<h3 id="2-devops-paradigm">2. DevOps Paradigm</h3>
<p><strong>DevOps란 ?</strong>
소프트웨어를 만드는 <strong>development team</strong>과 완성된 제품을 가지고 deploy하는 <strong>management team</strong>으로 나뉘는 구조
Kubernetes를 사용하면 더 실시간으로 소프트웨어를 개선시킬 수 있다.</p>
<h3 id="3-cloud화-진행">3. Cloud화 진행</h3>
<p>기존의 local에 있었던 코드는 옮기는데 비용 많이 듦 -&gt; 코드를 cloud에 배포
Kubernetes API를 통해 AWS, Google Cloud등 여러 Cloud에 쉽게 접근 가능
<br/></p>
<h2 id="kubernetes-이해하기">Kubernetes 이해하기</h2>
<p>Kubernetes와 OS의 비교)
OS가 Scheduler를 통해 CPU를 할당해 주고 interface를 지원해 주는 것처럼 Kubernetes는 Server들을 Scheduling해 주고 interface를 제공해 사용자가 다음과 같은 infrastructure를 몰라도 되도록 해준다.</p>
<h3 id="infrastructure-kubernetes의-주-기능">Infrastructure (Kubernetes의 주 기능)</h3>
<p><strong>service discovery</strong> - 어떤 application이 다른 application의 서비스를 이용하게 해주는 것
<strong>horizontal scaling</strong> - traffic이 증가했을 때 application의 개수를 복제하여 부담을 분할시키는 것
<strong>load-balancing</strong> - 복제된 application의 load(부담)이 치우치지 않게 해주는 것
<strong>self-healing</strong> - application이 죽었을 때 자동으로 restart해주고 healty node로 옮겨주는 것
<strong>leader election</strong> - 어떤 instance를 active시킬지, active된 instance가 죽었을 때 어떤 instance로 옮겨갈 것인지 설정
<img src="https://velog.velcdn.com/images/hyunsu_prog/post/1621b19a-3a07-4b7d-adb6-4ff86883eaf4/image.png" alt=""></p>
<p>Kubernetes상에서 machine은 크게 Master node, Worker node 2가지로 나뉘어진다.
&nbsp;
<strong>Master node</strong> - system과 cluster들을 제어, 보통 최소 3개는 필요함.
<strong>Worker node</strong> - application을 실행하는 machine으로 application의 개수를 맞춰간다.
<img src="https://velog.velcdn.com/images/hyunsu_prog/post/7e785911-f751-48c2-aa9c-ddae3419ff91/image.png" alt=""></p>
<p>Kubernetes 프레임워크가 만들어지면 Kubernetes 내부에서 자동으로 application을 적절한 node들로 배치하고 이동시켜 주므로, 유저는 Control Plane에서 제공하는 Kubernetes API만으로 Workload Plane의 application을 제어할 수 있게 된다. </p>
<h3 id="cluster">Cluster</h3>
<p>Cluster란, Control plane과 Workload Plane이 모여서 만들어진 큰 단위이다.
<img src="https://velog.velcdn.com/images/hyunsu_prog/post/e7d84b78-dc7e-4603-9a1a-8c72db9e7a76/image.png" alt=""></p>
<h4 id="control-plane">Control plane</h4>
<p><strong>API Server</strong> - REST API형식으로 요청을 받아서 object를 생성한다.
<strong>etcd</strong> - API를 통해 만든 object들을 persistent datastore에 저장한다. why? API Server 자체는 stateless하기 때문
<strong>Scheduler</strong> - 어떤 application을 어떤 worker node에서 실행할 것인지 결정한다.
<strong>Controllers</strong> - 생성된 object을 관리한다.
<img src="https://velog.velcdn.com/images/hyunsu_prog/post/67aa6089-6add-42fb-9981-55b1d350c62f/image.png" alt=""></p>
<h4 id="worker-node">Worker node</h4>
<p><strong>Kubelet</strong> - API Server와 통신하고 application과 node의 상태를 감시하고 관리한다.
<strong>Container Runtime</strong> - Kubelet에 지시를 받아 application을 실행한다. 일반적으로 Docker같은 것.
<strong>Kube Proxy</strong> - application들 사이의 network traffic을 load-balance 해준다.
<img src="https://velog.velcdn.com/images/hyunsu_prog/post/5912f805-2167-4148-b034-263c8fdbe38e/image.png" alt=""></p>
<h4 id="add-on">Add-on</h4>
<p>DNS 서버, 네트워크 플러그인, 로그 기록들을 추가한다. 보통 Worker node에서 실행된다.</p>
<h3 id="kubernetes-작동-방식">Kubernetes 작동 방식</h3>
<p>Kubernetes에서는 object를 기본 단위로 한다. 하나의 소프트웨어에는 deployment하는 object, instance running 하는 object, 서비스를 나타내는 object등 다양한 object들이 있다.
전체 object들의 description은 yaml이나 json으로 관리된다. 이것들은 보통 kubetcl(K8s의 cli)로 object단위로 쪼개지고, PUT이나 POST 요청으로 API서버에 전해진다.</p>
<h4 id="kubernetess-내부-과정">Kubernetess 내부 과정</h4>
<ol>
<li>object들의 정보를 담은 application menifest를 API서버에 보낸다. API서버는 이것을 etcd에 저장한다.</li>
<li>각 type에 object에 대응하는 Controller가 새로운 object들을 실제로 생성한다.</li>
<li>Scheduler가 object들을 node에 할당한다.</li>
<li>object가 할당된 node의 Kubelet이 Container Runtime에게 instance(할당된 object)를 실행시킨다.</li>
<li>Kube proxy가 instance가 사용 준비됨을 알리고 load-balancing 한다.</li>
<li>Kubelet과 Controller가 시스템을 정상적으로 돌아가도록 관리한다. 또한 주기적으로 상태를 알려준다.</li>
</ol>
<p><img src="https://velog.velcdn.com/images/hyunsu_prog/post/8ea9e564-6a4c-46b8-92f1-dcdcf2152c28/image.png" alt=""></p>
<h4 id="kubernetes-사용-상황">Kubernetes 사용 상황</h4>
<p><strong>On-Premises</strong> - 로컬로 시스템 작동, HPA하기 힘들다.
<strong>Cloud</strong> - Cloud 서버로 시스템 작동, HPA 유연하다.
<strong>Hybrid</strong> - 평소에는 로컬로 저장, peak일 때 instance추가로 받는다</p>
]]></description>
        </item>
    </channel>
</rss>