<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>천천히 꾸준히 조용히</title>
    <link>https://13months.tistory.com/</link>
    <description>천천히 꾸준히 조용히..
i3months 블로그</description>
    <language>ko</language>
    <pubDate>Sun, 23 Aug 2026 10:18:40 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>i3months</managingEditor>
    <image>
      <title>천천히 꾸준히 조용히</title>
      <url>https://tistory1.daumcdn.net/tistory/4775559/attach/1d8003f60bce4c3d85d7c4c06bf1ab80</url>
      <link>https://13months.tistory.com</link>
    </image>
    <item>
      <title>[Kubernetes] kubectl 연습 - namespace와 Secret</title>
      <link>https://13months.tistory.com/855</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;namespace는 클러스터 내부의 구역을 의미한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클러스터 안의 리소스(Pod, Deployment, Service)를 논리적으로 묶는 라벨으로 생각하면 됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클러스터는 하나고, 그 안의 리소스를 그룹으로 구분한다. 노드를 구분하는 것도 아님. 노드와 namespace는 완전히 다른 축이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAm4yP/dJMcagM9xQZ/DaQhRQzwupGkOejWSVkh71/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAm4yP/dJMcagM9xQZ/DaQhRQzwupGkOejWSVkh71/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAm4yP/dJMcagM9xQZ/DaQhRQzwupGkOejWSVkh71/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAm4yP%2FdJMcagM9xQZ%2FDaQhRQzwupGkOejWSVkh71%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;629&quot; height=&quot;354&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클러스터 안에 두 개의 노드가 있고 (Control Plane, Worker Node)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 노드 안에는 Pod가 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;namespace는 저렇게 물리적으로 구분하는게 아니고 같은 클러스터 안을 논리적으로 구분한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저걸 쓰는 이유는 C++의 namespace를 사용하는 이유와 똑같음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;my-web 이라는 deployment를 여러 군데에서 사용할 때 namespace만 다르게 지정해주면 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발 / 운영 리소스를 따로 설정할 때도 유용한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1784620642028&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;13months@13monthsBook k8s % kubectl get namespaces
NAME              STATUS   AGE
default           Active   131m
kube-node-lease   Active   131m
kube-public       Active   131m
kube-system       Active   131m
13months@13monthsBook k8s %&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;namespace를 따로 설정하지 않으면 default로 들어간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kube-system은 쿠버의 핵심 부품이 들어가는 방이고, kube-public과 kube-node-lease는 잘 안쓴다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1784620692709&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;13months@13monthsBook k8s % k get pods -n kube-system
NAME                               READY   STATUS    RESTARTS   AGE
coredns-7d764666f9-kd4kp           1/1     Running   0          132m
etcd-minikube                      1/1     Running   0          132m
kube-apiserver-minikube            1/1     Running   0          132m
kube-controller-manager-minikube   1/1     Running   0          132m
kube-proxy-7vtvh                   1/1     Running   0          132m
kube-scheduler-minikube            1/1     Running   0          132m
storage-provisioner                1/1     Running   0          132m
13months@13monthsBook k8s %&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-n 옵션을 주면 kube-system namespace가 가진 리소스를 확인할 수 있다. (-A 옵션을 주면 모든 namespace를 다 볼 수 있음)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그냥 kubectl get pods만 하면 default가 가진 것만 확인할 수 있었음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;614&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EqGmM/dJMb99NSVC0/HpmfcgXxCD7Eh0DtqHL6Tk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EqGmM/dJMb99NSVC0/HpmfcgXxCD7Eh0DtqHL6Tk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EqGmM/dJMb99NSVC0/HpmfcgXxCD7Eh0DtqHL6Tk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEqGmM%2FdJMb99NSVC0%2FHpmfcgXxCD7Eh0DtqHL6Tk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;691&quot; height=&quot;331&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;614&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kube-system이 어떤 역할을 하는지 살펴보자.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. api-server&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클러스터의 유일한 출입구로 kubectl로 명령어를 보내면 무조건 api-server를 거친다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링의 디스패처 서블릿 같은것.. 보안 인증 검증을 api-server에서 통합 관리할 수 있어 편함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;얘가 죽으면 kubectl 자체가 안 먹힌다. kubectl이 반응이 없다면 api-server를 의심&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. etcd&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클러스터의 모든 상태를 저장하는 데이터베이스로 어느 노드에 뭐가 있는지, Service 설정은 어떻게 되어있는지, Pod가 몇 개 있어야 하는지 등 모든 정보가 etcd에 저장된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;declarative로 원하는 상태를 적어두는데 여기서 적은 내용이 etcd에 저장된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;얘가 죽으면 클러스터가 제대로 동작하지 않으니 etcd를 백업하고 복원하는게 정말 정말 중요하다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. scheduler&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로운 Pod를 어떤 노드에 배치할지를 결정한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버컴 n개 중 어디가 여유로운지를 판단해서 최적의 배치를 결정하는 역할을 수행함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결정만 하고 실제로 배치하지는 않는다. api-server에게 알려주고 띄우는건 api-server가..&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;얘가 죽으면 배치할 노드를 정하는 애가 없으니 새로운 Pod이 Pending 상태로 멈춰있는다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. controller-manager&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 상태가 정의된 상태인지 계속 확인한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계속 etcd를 감시하고 Pod 개수가 일치하지 않으면 etcd에게 개수 맞추라고 알려준다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;얘가 죽으면 자동 복구가 안 되니 Pod가 죽어도 새로 뜨지 않고 Replica를 바꿔도 반영되지 않는다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5. kubelet&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;노드에서 실제로 컨테이너를 띄우는 역할을 수행한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에 1번 ~ 4번 까지는 Control Plane이지만 kubelet은 모든 노드에 하나씩 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;api-server가 Pod를 띄우라고 지시하면 kubelet이 containerd에게 컨테이너를 실행하라고 시킨다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;얘가 죽으면 해당 노드가 NotReady 상태가 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kubectl create deployment my-web 명령어를 실행하면&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. kubectl이 명령을 api-server에게 보냄&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. api-server가 검증 후 Deployment 실행을 etcd에 저장&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. controller-manager가 Pod 생성을 지시&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. scheduler가 새 Pod를 minikube 노드에 넣자고 결정하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. kubelet이 containerd로 실제로 실행한다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 Worker Node 안에는 Pod가 배치된다 (물리적으로)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Deployment와 ReplicaSet은 노드 안에 없음. 그냥 실체가 없는 기록일 뿐이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저 두 개는 실제로 수행되는 프로그램이 아니고 etcd에 저장된 설정 정보일 뿐임.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, kube-system은 노드가 아니라 namespace. Control Plane 노드가 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 본 etcd / api-server / scheduler 등은 Control Plane의 부품이 Pod로 실행되고 있는 것.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿠버네티스가 자기 자신을 돌리기 위해 필요한 시스템리소스를 모아둔 namespace 라고 생각하자.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(개념 헷갈리면 힘드니까 제대로 읽고 정리하기)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Control Plane 노드에는 etcd / kube-apiserver / kube-scheduler / kube-controller-manager&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Worker Node를 포함한 모든 노드에는 kubelet / kube-proxy 를 가진다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Control Plane 노드에서도 api-server 같은 Pod를 띄워야 하고 Pod를 띄우는 건 kubelet이 수행하니까..&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;namespace와 노드는 서로 Orthogonal 관계라서 Pod는 특정 namespace에 속할 수도 있고 특정 노드에도 속할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1784687200574&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;13months@13monthsBook k8s % kubectl get pods -n kube-system -o wide
NAME                               READY   STATUS    RESTARTS   AGE   IP             NODE       NOMINATED NODE   READINESS GATES
coredns-7d764666f9-kd4kp           1/1     Running   0          20h   10.244.0.2     minikube   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
etcd-minikube                      1/1     Running   0          20h   192.168.49.2   minikube   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
kube-apiserver-minikube            1/1     Running   0          20h   192.168.49.2   minikube   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
kube-controller-manager-minikube   1/1     Running   0          20h   192.168.49.2   minikube   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
kube-proxy-7vtvh                   1/1     Running   0          20h   192.168.49.2   minikube   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
kube-scheduler-minikube            1/1     Running   0          20h   192.168.49.2   minikube   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
storage-provisioner                1/1     Running   0          20h   192.168.49.2   minikube   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
13months@13monthsBook k8s %&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-o는 출력 형식을 지정하고 wide는 더 많은 정보를 보여달라는걸 의미한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-o wide 옵션으로 IP와 NODE 컬럼을 추가로 확인할 수 있다. (-o yaml -o json -o name 옵션도 있음)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아이피 종류가 2개인데, 192.168.49.2 아이피는 minikube 자체의 아이피이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반 Pod은 Pod 전용 대역에서 IP를 받아서 사용한다. (10.244.x)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;etcd /&amp;nbsp; apiserver / controller 등 호스트 네트워크를 쓰는 Pod는 노드의 아이피를 그대로 받아서 사용한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심 구성요소들은 쿠버 네트워크에 의존하지 않고 노드 네트워크를 직접 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;minikube는 실습용 미니 쿠버네티스로 클러스터를 작게 축소해서 컴퓨터에 실습 환경을 구축할 떄 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;minikube start --driver=docker 로 실행했기에 노드 1개짜리 쿠버네티스 클러스터가 계속 돌고 있음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;etcd /&amp;nbsp; kubelet / kube-apiserver 등 쿠버 구성요소들은 리눅스에서 돌아가는 소프트웨어이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애초에 컨테이너 기술 자체가 리눅스 커널 기능이기도 함. 이 격리 기술은 맥이나 윈도우에는 없음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맥에서 도커를 쓸 때도 맥 안에 리눅스 VM을 하나 띄워두고 그 안에서 컨테이너를 돌린다. (Docker Desktop이 해줌)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 지금은 minikube를 사용하는데. 그러기에 Controle Plane 노드 한개만 돌아가고 있음. Control Plane과 Worker Node 겸용..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 클러스터에서는 Control Plane 노드에는 일반 Pod를 올리지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 노드 여러개 띄우고 실습 할 때는 minikube sstart --nodes=3 으로 설정해주면 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿠버에서 앱에 설정값을 넘겨줄 때는 ConfigMap과 Secret을 사용한다. (DB 접속 정보 등.. application.yml을 생각하기)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1784691912520&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;13months@13monthsBook k8s % k create configmap my-config --from-literal=APP_COLOR=blue --from-literal=APP_MODE=production
configmap/my-config created
13months@13monthsBook k8s % kubectl get configmap
NAME               DATA   AGE
kube-root-ca.crt   1      21h
my-config          2      14s
13months@13monthsBook k8s % kubectl describe configmap my-config
Name:         my-config
Namespace:    default
Labels:       &amp;lt;none&amp;gt;
Annotations:  &amp;lt;none&amp;gt;

Data
====
APP_COLOR:
----
blue

APP_MODE:
----
production


BinaryData
====

Events:  &amp;lt;none&amp;gt;
13months@13monthsBook k8s % vim config-test.yaml
13months@13monthsBook k8s % vim config-test.yaml
13months@13monthsBook k8s %&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1784691926661&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: v1
kind: Pod
metadata:
  name: config-test
spec:
  containers:
  - name: test
    image: busybox
    command: [&quot;sh&quot;, &quot;-c&quot;, &quot;echo COLOR=$APP_COLOR MODE=$APP_MODE; sleep 3600&quot;]
    envFrom:
    - configMapRef:
        name: my-config
~&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1784693943361&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;13months@13monthsBook k8s % kubectl apply -f config-test.yaml
pod/config-test created
13months@13monthsBook k8s % kubectl logs config-test 
COLOR=blue MODE=production
13months@13monthsBook k8s % kubectl exec -it config-test -- sh
/ # echo $APP_COLOR
blue
/ # env | grep APP
APP_MODE=production
APP_COLOR=blue
/ #&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지는 환경변수를 모르지만 쿠버가 실행 시점에 밖에서 값을 주입해준다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹개발에서 똑같은거 계속 하는데 그냥 쿠버에서는 어떻게 하는지? 를 보여주는거임&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링부트에서 yml 작성할 때 데이터베이스 접속정보를 평문으로 그대로 입력하지 않는 것 처럼 민감정보는 secret으로 따로 다룬다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1784694188912&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;13months@13monthsBook k8s % kubectl create secret generic my-secret --from-literal=DB_PASSWORD=mypassword123
secret/my-secret created
13months@13monthsBook k8s % kubectl describe secret my-secret
Name:         my-secret
Namespace:    default
Labels:       &amp;lt;none&amp;gt;
Annotations:  &amp;lt;none&amp;gt;

Type:  Opaque

Data
====
DB_PASSWORD:  13 bytes
13months@13monthsBook k8s % kubectl get secret my-secret -o yaml
apiVersion: v1
data:
  DB_PASSWORD: bXlwYXNzd29yZDEyMw==
kind: Secret
metadata:
  creationTimestamp: &quot;2026-07-22T04:20:59Z&quot;
  name: my-secret
  namespace: default
  resourceVersion: &quot;30742&quot;
  uid: ac1972e2-72d9-4406-a537-bd116753db8c
type: Opaque
13months@13monthsBook k8s % echo 'bXlwYXNzd29yZDEyMw==' | base64 -d
mypassword123%&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;secret이라서 암호화 돼서 못보는게 아닌가 싶긴 한데;; 사실 암호화가 아니다. 그냥 인코딩일 뿐임.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래도 평문으로 보이는 것 보다는 나으니까..?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 secret을 base64로 다루는 본질적인 이유는 바이너리 데이터를 다루기 위해서이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;secret을 secret처럼 다루려면 RBAC로 아무나 kubectl get secret을 수행하지 못하도록 권한을 통제하면 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1784694507957&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: v1
kind: Pod
metadata:
  name: secret-test
spec:
  containers:
  - name: test
    image: busybox
    command: [&quot;sh&quot;, &quot;-c&quot;, &quot;echo PW=$DB_PASSWORD; sleep 3600&quot;]
    env:
    - name: DB_PASSWORD
      valueFrom:
        secretKeyRef:
          name: my-secret
          key: DB_PASSWORD
          

13months@13monthsBook k8s % kubectl apply -f secret-test.yaml 
pod/secret-test created
13months@13monthsBook k8s % kubectl logs secret-test 
PW=mypassword123
13months@13monthsBook k8s %&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;envFrom 대신 valueFrom을 사용하면 특정 키를 골라서 넣을 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1784695211713&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: v1
kind: Pod
metadata:
  name: volume-test
spec:
  containers:
  - name: test
    image: busybox
    command: [&quot;sh&quot;, &quot;-c&quot;, &quot;ls /etc/config; cat /etc/config/APP_COLOR; sleep 3600&quot;]
    volumeMounts:
    - name: config-volume
      mountPath: /etc/config
  volumes:
  - name: config-volume
    configMap:
      name: my-config
      
13months@13monthsBook k8s % vim volume-test.yaml
13months@13monthsBook k8s % k apply -f volume-test.yaml 
pod/volume-test created
13months@13monthsBook k8s % k logs volume-test 
Error from server (BadRequest): container &quot;test&quot; in pod &quot;volume-test&quot; is waiting to start: ContainerCreating
13months@13monthsBook k8s % k logs volume-test
APP_COLOR
APP_MODE
13months@13monthsBook k8s % k get pod volume-test -o yaml | grep -A 5 command
      {&quot;apiVersion&quot;:&quot;v1&quot;,&quot;kind&quot;:&quot;Pod&quot;,&quot;metadata&quot;:{&quot;annotations&quot;:{},&quot;name&quot;:&quot;volume-test&quot;,&quot;namespace&quot;:&quot;default&quot;},&quot;spec&quot;:{&quot;containers&quot;:[{&quot;command&quot;:[&quot;sh&quot;,&quot;-c&quot;,&quot;ls /etc/config; cat /etc/config/APP_COLOR; sleep 3600&quot;],&quot;image&quot;:&quot;busybox&quot;,&quot;name&quot;:&quot;test&quot;,&quot;volumeMounts&quot;:[{&quot;mountPath&quot;:&quot;/etc/config&quot;,&quot;name&quot;:&quot;config-volume&quot;}]}],&quot;volumes&quot;:[{&quot;configMap&quot;:{&quot;name&quot;:&quot;my-config&quot;},&quot;name&quot;:&quot;config-volume&quot;}]}}
  creationTimestamp: &quot;2026-07-22T04:34:10Z&quot;
  generation: 1
  name: volume-test
  namespace: default
  resourceVersion: &quot;31394&quot;
--
  - command:
    - sh
    - -c
    - ls /etc/config; cat /etc/config/APP_COLOR; sleep 3600
    image: busybox
    imagePullPolicy: Always
13months@13monthsBook k8s % k exec -it volume-test -- sh
/ # ls -la /etc/config/
total 12
drwxrwxrwx    3 root     root          4096 Jul 22 04:34 .
drwxr-xr-x    1 root     root          4096 Jul 22 04:34 ..
drwxr-xr-x    2 root     root          4096 Jul 22 04:34 ..2026_07_22_04_34_10.2502450523
lrwxrwxrwx    1 root     root            32 Jul 22 04:34 ..data -&amp;gt; ..2026_07_22_04_34_10.2502450523
lrwxrwxrwx    1 root     root            16 Jul 22 04:34 APP_COLOR -&amp;gt; ..data/APP_COLOR
lrwxrwxrwx    1 root     root            15 Jul 22 04:34 APP_MODE -&amp;gt; ..data/APP_MODE
/ # cat /etc//config/APP_COLOR 
blue/ # exit
13months@13monthsBook k8s %&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kubectl logs volume-test 결과로 blue가 안 나왔다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 컨테이너가 만들어지는 중에 로그를 찍어보니 에러가 발생함. 자주 발생하는 에러임.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;command: [&quot;sh&quot;, &quot;-c&quot;, &quot;ls /etc/config; cat /etc/config/APP_COLOR; sleep 3600&quot;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;커맨드를 보면 ls만 출력됐고 cat 결과가 안 나왔으니 이 부분을 확인해보자.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;exec으로 컨테이너 안에 들어가서 cat 해보니 blue가 출력되긴 했음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 마지막 줄이 개행 없이 끝나서 화면에 안 보였던 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ConfigMap을 파일로 마운트하면 값이 바뀔 때 컨테이너 내부 파일도 자동으로 갱신된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ls 찍어봤을때 심볼릭 링크로 타고 타고 들어가고 있음을 확인할 수 있음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;링크 없이 진짜 파일을 참조하고 있었다면 Atomicity가 보장되지 않을 수 있으니 심볼릭 링크를 사용한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;환경변수는 컨테이너 시작할 때 한 번 주입되고 끝난다. ConfigMap 바꿔도 Pod에는 반영되지 않음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일 마운트로 처리하면 ConfigMap이 바뀌면 파일도 자동으로 바뀐다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 당연한 소리긴 함. 마운트 했다고 하더라도 그 안의 스프링부트가 다시 떠야지 마운트 된거를 새로 읽을거고..&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DevOps/Docker &amp;amp;&amp;amp; Kubernetes</category>
      <author>i3months</author>
      <guid isPermaLink="true">https://13months.tistory.com/855</guid>
      <comments>https://13months.tistory.com/855#entry855comment</comments>
      <pubDate>Thu, 20 Aug 2026 13:48:01 +0900</pubDate>
    </item>
    <item>
      <title>[Kubernetes] Certified Kubernetes Administrator 연습 (4)</title>
      <link>https://13months.tistory.com/873</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Q1. 인증 API를 staging namespace에 배포함. auth-api Pod이 잘 뜨도록 설정하고 prod namespace의 tester Pod에서 auth-svc로 접속되도록 하기.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cross-namespace 주소를 쓸 때는 namespace를 명시해 줘야 함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1785982412512&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;k exec tester -n prod -- wget -qO- auth-svc.staging
                                            └──┬──┘
                                        namespace 붙임&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Q2. init container가 설정 파일을 준비하고 nginx가 서빙하는 구조인데, Pod이 안 뜬다. web-init Pod가 정상 작동하도록 설정하고 nginx 페이지를 서빙할 것.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Init:0/1 STATUS는 컨테이너 1개 중 0개가 완료됨을 의미함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아직 init 단계에 있다는거임. init이 끝나야 메인 컨테이너가 시작되는데 init에서 막혔다는것.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 그냥 describe 해보면 다 나온다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Q3. 리포트 API 배포했는데 안됨. report-api Pod 정상작동하도록 설정, app-sa 계정이 staging에서 ConfigMap 조회할 수있도록 설정, report-svc로 접속 가능해야 함, Pod는 minikube-m02 에서만 실행되도록 하기.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;didn't match node affinity/selector 는 node의 selector를 확인해야 한다. Service Selector와 nodeSelector는 다른거임. 저 메세지는 특정 label이 달려있는 노드를 찾는다는건데 그 라벨이 달린 노드가 없어서 발생하는 오류임.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;READY 0/1 도 정상 상태는 아니다. Readiness probe문제니까 edit deployment로 수정해주면 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포트번호나 Health Check 주소를 바꿔주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;권한을 점검할 때는 일단 어디가 틀렸는지를 먼저 확인해야 함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 진짜 안되는지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;k&amp;nbsp;auth&amp;nbsp;can-i&amp;nbsp;get&amp;nbsp;configmaps&amp;nbsp;--as=system:serviceaccount:staging:app-sa&amp;nbsp;-n&amp;nbsp;staging&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;k&amp;nbsp;auth&amp;nbsp;can-i&amp;nbsp;list&amp;nbsp;configmaps&amp;nbsp;--as=system:serviceaccount:staging:app-sa&amp;nbsp;-n&amp;nbsp;staging&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. Role이 뭘 주는지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;k&amp;nbsp;describe&amp;nbsp;role&amp;nbsp;cm-reader&amp;nbsp;-n&amp;nbsp;staging&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. RoleBinding은 뭐랑 연결되는지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;k&amp;nbsp;describe&amp;nbsp;rolebinding&amp;nbsp;app-sa-binding&amp;nbsp;-n&amp;nbsp;staging&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. Service Account 이름&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;k&amp;nbsp;get&amp;nbsp;sa&amp;nbsp;-n&amp;nbsp;staging&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1번 말고는 그냥 describe랑 get 쓰는거임&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;--as=system:serviceaccount:staging:app-sa&lt;br /&gt;앞에는 그냥 고정임 외워 + namespace + SA이름&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;k get role이랑 k get rolebinding으로 이름 알아낸 후 describe로 점검하고 edit으로 수정하면 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Q4. 큐 워커 배포했는데 동작하지 않음. queue-worker Pod 4개가 모두 정상 작동하도록 설정하고 QUEUE_NAME, MAX_RETRY 환경변수로 확인할 수 있어야 함&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Crash 뜨면 log를 봐야한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;k logs podname -n staging --previous&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;replicas가 4개인데 Pod이 2개밖에 안되면 만들어지지 못한다는 것. 이것도 큰 힌트가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이럴 떄는 ReplicaSet의 Events를 봐야 함!!! 항상 안보고 있었음. Pod 개수가 부족할 때는 ReplicaSet을 확인해야 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그냥 Pod의 log를 보면 그냥 제대로 작동한 것 같음. 단서가 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;request와 limit의 cpu와 메모리를 조작해주면 4개 모두 만들어지도록 설정할 수 있음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;commands에 무한루프 안걸어두면 작업 하고 죽어버리니 sleep infinity를 명시해주자. &amp;amp;&amp;amp;로 파이프라인 걸어두면 한 줄로 인식되도록 설정할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Q5. 정적 사이트를 배포했는데 서비스 접속이 안된다. static-web Pod이 3개가 되고 static-web-svc로 접속되도록 설정하기&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;containerPort는 그냥 메모일 뿐임. 엔진엑스는 80을 쓰니까 80으로 설정해야 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 listen 포트를 deploy 포트와 svc 포트를 맞춰야 함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그냥 앱의 기본 포트인 80을 여는게 편하긴 함. 아니면 컨테이너에서 확인하면 되긴 해&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Q6. Killercoda Playground에서 진행. controlplane노드에 접속한 상태에서 etcdctl 을 백업하고 복원해보기.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;/etc/kubernetes/manifests/ 여기에는 static pod이 배치됨. etcd.yaml, kube-apiserver.yaml 이건 외워야함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;data-dir은 etcd가 실제 데이터를 저장하는 폴더.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;cat&amp;nbsp;/etc/kubernetes/manifests/etcd.yaml&amp;nbsp;|&amp;nbsp;grep&amp;nbsp;data-dir&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저기다가 복원하지는 않음. 원본을 덮어쓰면 위험하니까..&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;etcdctl&amp;nbsp;snapshot&amp;nbsp;save&amp;nbsp;&amp;lt;저장할경로&amp;gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;etcdctl로 etcd를 백업한다. etcdctl은 도구이고 etcd는 백업 대상&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스냅샷을 저장할 때는 save, 복원할 때는 restore를 사용한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cat으로 얻은 정보를 바탕으로 etcdctl 커맨드를 작성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 백업 명령어는 docs에서 그대로 가져오면 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ETCDCTL_API=3&amp;nbsp;etcdctl&amp;nbsp;snapshot&amp;nbsp;save&amp;nbsp;/opt/etcd-backup.db&amp;nbsp;\&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&amp;nbsp;&amp;nbsp;--endpoints=https://127.0.0.1:2379&amp;nbsp;\&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&amp;nbsp;&amp;nbsp;--cacert=/etc/kubernetes/pki/etcd/ca.crt&amp;nbsp;\&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&amp;nbsp;&amp;nbsp;--cert=/etc/kubernetes/pki/etcd/server.crt&amp;nbsp;\&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&amp;nbsp;&amp;nbsp;--key=/etc/kubernetes/pki/etcd/server.key&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;백업경로는 문제에서 지정한대로 씀. 나머지 4개는 cat으로 읽은걸 사용한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 노드에서 실행하니 127.0.0.1을 사용함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;etcdctl&amp;nbsp;snapshot&amp;nbsp;restore&amp;nbsp;/opt/etcd-backup.db&amp;nbsp;--data-dir=/var/lib/etcd-restore&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스냅샷을 새 폴더에 풀어준다. 파일을 푸는 작업이니 인증서 옵션은 필요없음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아 그런데 etcd 3.6에서는 snapshot restore가 없어지고 etcdutl을 사용해서 복원한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;etcdctl은 실행 중인 etcd 서버와 통신하고, etcdutl은 파일을 직접 다루니 명령어를 구분해서 사용함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;etcdutl&amp;nbsp;snapshot&amp;nbsp;restore&amp;nbsp;/opt/etcd-backup.db&amp;nbsp;--data-dir=/var/lib/etcd-restore&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 명령어 실행 후 vim으로 yaml 수정해서 etcd-restore 바라보도록 설정해주면 됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;command 부분과 volumes, volumeMounts 부분 모두 바꿔야 함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바꿔주면 복원 끝. 근데 좀 기다려야 함&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Q7. kubeadm 클러스터 업그레이드하기.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 kubeadm upgrade plan을 찍어본다. 버전 업그레이드가 가능함을 확인할 수 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Control Plane 업그레이드는 kubeadm upgrade apply 가 알아서 해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 kubelet은 자동으로 안되고 직접 올려줘야 함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1786948292364&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;root@controlplane:~$ kubeadm upgrade plan
[preflight] Running pre-flight checks.
[upgrade/config] Reading configuration from the &quot;kubeadm-config&quot; ConfigMap in namespace &quot;kube-system&quot;...
[upgrade/config] Use 'kubeadm init phase upload-config kubeadm --config your-config-file' to re-upload it.
W0817 06:25:17.967022    4947 configset.go:77] Warning: No kubeproxy.config.k8s.io/v1alpha1 config is loaded. Continuing without it: configmaps &quot;kube-proxy&quot; not found
[upgrade] Running cluster health checks
[upgrade] Fetching available versions to upgrade to
[upgrade/versions] Cluster version: 1.35.1
[upgrade/versions] kubeadm version: v1.35.1
I0817 06:25:27.724414    4947 version.go:260] remote version is much newer: v1.36.3; falling back to: stable-1.35
[upgrade/versions] Target version: v1.35.7
[upgrade/versions] Latest version in the v1.35 series: v1.35.7

W0817 06:25:28.362557    4947 configset.go:77] Warning: No kubeproxy.config.k8s.io/v1alpha1 config is loaded. Continuing without it: configmaps &quot;kube-proxy&quot; not found
Components that must be upgraded manually after you have upgraded the control plane with 'kubeadm upgrade apply':
COMPONENT   NODE           CURRENT   TARGET
kubelet     controlplane   v1.35.1   v1.35.7
kubelet     node01         v1.35.1   v1.35.7

Upgrade to the latest version in the v1.35 series:

COMPONENT                 NODE           CURRENT   TARGET
kube-apiserver            controlplane   v1.35.1   v1.35.7
kube-controller-manager   controlplane   v1.35.1   v1.35.7
kube-scheduler            controlplane   v1.35.1   v1.35.7
kube-proxy                               1.35.1    v1.35.7
CoreDNS                                  v1.13.1   v1.13.1
etcd                      controlplane   3.6.6-0   3.6.6-0

You can now apply the upgrade by executing the following command:

        kubeadm upgrade apply v1.35.7

Note: Before you can perform this upgrade, you have to update kubeadm to v1.35.7.

_____________________________________________________________________


The table below shows the current state of component configs as understood by this version of kubeadm.
Configs that have a &quot;yes&quot; mark in the &quot;MANUAL UPGRADE REQUIRED&quot; column require manual config upgrade or
resetting to kubeadm defaults before a successful upgrade can be performed. The version to manually
upgrade to is denoted in the &quot;PREFERRED VERSION&quot; column.

API GROUP                 CURRENT VERSION   PREFERRED VERSION   MANUAL UPGRADE REQUIRED
kubeproxy.config.k8s.io   -                 v1alpha1            no
kubelet.config.k8s.io     v1beta1           v1beta1             no
_____________________________________________________________________

root@controlplane:~$&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;업그레이드 순서도 알려줬으니 따라하면 됨. docs 보고 따라하면 되긴 함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;apt update&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;apt-cache madison kubeadm | head -5&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;apt-mark uphold kubeadm&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;apt-get install -y kubeadm=1.35.7-1.1&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;apt-mark hold kubeadm&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버전만 바꾼다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;kubeadm upgrade apply v1.35.7&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kubeadm 을 깔았으니 업그레이드하자. 좀 오래걸림.. -y 옵션 주면 편하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서비스 중단 최소화를 위해 컴포넌트를 하나씩 교체한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;kubectl&amp;nbsp;drain&amp;nbsp;controlplane&amp;nbsp;--ignore-daemonsets&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 kubectl을 업그레이드하는데, 그전에 drain으로 Pod를 대피시킨다. DaemonSet Pod는 그 노드에 있어야 해서 못옮김. 무시하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 계속 문서 보고 치면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;apt-mark&amp;nbsp;unhold&amp;nbsp;kubelet&amp;nbsp;kubectl&lt;/b&gt;&lt;br /&gt;&lt;b&gt;apt-get&amp;nbsp;install&amp;nbsp;-y&amp;nbsp;kubelet=1.35.7-1.1&amp;nbsp;kubectl=1.35.7-1.1&lt;/b&gt;&lt;br /&gt;&lt;b&gt;apt-mark&amp;nbsp;hold&amp;nbsp;kubelet&amp;nbsp;kubectl&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;systemctl&amp;nbsp;daemon-reload&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;systemctl restart kubelet&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;kubectl&amp;nbsp;uncordon&amp;nbsp;controlplane&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;kubeadm -&amp;gt; upgrade apply -&amp;gt; drain -&amp;gt; kubelet/kubectl -&amp;gt; restart -&amp;gt; uncordon&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;순서 알아두고 명령어는 docs보고 치면 됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;워커노드도 업그레이드하자.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ssh node01로 접속함. 중요 작업은 워커 노드에서만 해야 한다. (kubeadm, kubelet) 이 있기 때문.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;kubeadm&amp;nbsp;upgrade&amp;nbsp;node&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나머지 명령어는 똑같은데 apply 대신 node 쓴다. 버전도 안씀&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;순서가 고정이니 문서만 쭉 따라치면 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Q8. node01이 NotReady니까 원인을 진단하고 복구하기.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;describe해보면 응답 안하는거만 알지 왜 안하는지는 모른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 노드에 직접 들어가 봐야 알 수 있음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1786950459129&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;root@controlplane:~$ ssh node01
Last login: Mon Aug 17 07:02:41 2026 from 10.244.4.143
root@node01:~$ systemctl status kubelet
○ kubelet.service - kubelet: The Kubernetes Node Agent
     Loaded: loaded (/usr/lib/systemd/system/kubelet.service; enabled;&amp;gt;
    Drop-In: /usr/lib/systemd/system/kubelet.service.d
             └─10-kubeadm.conf
     Active: inactive (dead) since Mon 2026-08-17 07:02:54 UTC; 3min 5&amp;gt;
   Duration: 10min 2.277s
       Docs: https://kubernetes.io/docs/
    Process: 1635 ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS &amp;gt;
   Main PID: 1635 (code=exited, status=0/SUCCESS)
        CPU: 5.653s

Aug 17 06:53:03 node01 kubelet[1635]: I0817 06:53:03.886861    1635 sc&amp;gt;
Aug 17 06:53:03 node01 kubelet[1635]: I0817 06:53:03.898634    1635 sc&amp;gt;
Aug 17 06:53:03 node01 kubelet[1635]: I0817 06:53:03.908758    1635 sc&amp;gt;
Aug 17 06:53:13 node01 kubelet[1635]: I0817 06:53:13.777688    1635 sc&amp;gt;
Aug 17 06:53:13 node01 kubelet[1635]: I0817 06:53:13.779216    1635 ku&amp;gt;
Aug 17 06:53:31 node01 kubelet[1635]: I0817 06:53:31.742916    1635 pr&amp;gt;
Aug 17 07:02:54 node01 systemd[1]: Stopping kubelet.service - kubelet:&amp;gt;
Aug 17 07:02:54 node01 systemd[1]: kubelet.service: Deactivated succes&amp;gt;
Aug 17 07:02:54 node01 systemd[1]: Stopped kubelet.service - kubelet: &amp;gt;
Aug 17 07:02:54 node01 systemd[1]: kubelet.service: Consumed 5.653s CP&amp;gt;
root@node01:~$&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Active가 inactive(dead) 상태임. failed랑 다르게 그냥 멈췄다는것&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Loaded에서 자동 시작이 설정되어있음. 이부분 중요함&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그를 보면 정상적으로 멈췄음을 알 수 있음 그냥 시작해주면 된다. systemctl start kubelet&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DevOps/Docker &amp;amp;&amp;amp; Kubernetes</category>
      <author>i3months</author>
      <guid isPermaLink="true">https://13months.tistory.com/873</guid>
      <comments>https://13months.tistory.com/873#entry873comment</comments>
      <pubDate>Mon, 17 Aug 2026 16:12:53 +0900</pubDate>
    </item>
    <item>
      <title>[Kubernetes] Certified Kubernetes Administrator 연습 (3)</title>
      <link>https://13months.tistory.com/872</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Q1. GPU 작업용 워크로드를 minikube-m03 노드에 배포하려는데 Pod이 안뜬다. m03노드는 GPU 전용임. 일반 워크로드가 못 들어오도록 설정해뒀음. m03 기본설정은 유지하되 Pod 2개가 m03에서 Running 되도록 조치하기.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 노드에 Pod를 배치하지 않도록 설정하는건 taint. toleration은 그 거부 표시를 견딜 수 있음을 명시하는 표식으로 Pod에 붙인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;0/3&amp;nbsp;nodes&amp;nbsp;are&amp;nbsp;available:&lt;br /&gt;&amp;nbsp;&amp;nbsp;1&amp;nbsp;node(s)&amp;nbsp;had&amp;nbsp;untolerated&amp;nbsp;taint(s)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;larr;&amp;nbsp;m03:&amp;nbsp;taint&amp;nbsp;있는데&amp;nbsp;Pod에&amp;nbsp;통행증&amp;nbsp;없음&lt;br /&gt;&amp;nbsp;&amp;nbsp;2&amp;nbsp;node(s)&amp;nbsp;didn't&amp;nbsp;match&amp;nbsp;Pod's&amp;nbsp;node&amp;nbsp;affinity/selector&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;larr;&amp;nbsp;minikube,&amp;nbsp;m02:&amp;nbsp;nodeSelector가&amp;nbsp;m03을&amp;nbsp;지정했으니&amp;nbsp;당연히&amp;nbsp;안&amp;nbsp;맞음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나머지 2개는 원래 배제 대상이고 한개는 확인해 봐야 함. untolerated taint는 Pod이 taint를 견딜 toleration이 없음을 의미함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1785824707712&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;13months@13monthsBook k8s % k describe node minikube-m03 | grep -i taint
Taints:             dedicated=gpu:NoSchedule
13months@13monthsBook k8s % k edit deployment gpu-job -n prod
deployment.apps/gpu-job edited
13months@13monthsBook k8s % k get pods -n prod -o wide       
NAME                       READY   STATUS    RESTARTS   AGE   IP            NODE           NOMINATED NODE   READINESS GATES
gpu-job-6c765f4fff-9rb66   1/1     Running   0          5s    10.244.2.39   minikube-m03   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
gpu-job-6c765f4fff-mq7h5   1/1     Running   0          3s    10.244.2.40   minikube-m03   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
13months@13monthsBook k8s %&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pod에 toleration을 추가하면 된다. 위치는 spec.template.spec 아래, containers 옆에다가 배치하면 됨.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;taint를 확인하고 그대로 YAML에 적으면 된다. operator: Equal은 고정으로 붙임. 그냥 k8s docs에서 복붙하면 되긴해.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Q2. 모니터링 담당자가 monitor-sa 계정으로 prod namespace의 Pod을 조회하려는데 권한이 없다고 함. 고쳐라.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1785824876576&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;13months@13monthsBook k8s % k auth can-i get pods --as=system:serviceaccount:prod:monitor-sa -n prod
no
13months@13monthsBook k8s % k auth can-i list pods --as=system:serviceaccount:prod:monitor-sa -n prod
no
13months@13monthsBook k8s %&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;can-i 로 확인해보면 진짜 안되는걸 확인할 수 있음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1785825163420&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;13months@13monthsBook k8s % k describe role pod-reader -n prod
Name:         pod-reader
Labels:       &amp;lt;none&amp;gt;
Annotations:  &amp;lt;none&amp;gt;
PolicyRule:
  Resources  Non-Resource URLs  Resource Names  Verbs
  ---------  -----------------  --------------  -----
  services   []                 []              [get list]
13months@13monthsBook k8s % k describe rolebinding monitor-binding -n prod
Name:         monitor-binding
Labels:       &amp;lt;none&amp;gt;
Annotations:  &amp;lt;none&amp;gt;
Role:
  Kind:  Role
  Name:  pod-reader
Subjects:
  Kind            Name        Namespace
  ----            ----        ---------
  ServiceAccount  monitor-sa  prod
13months@13monthsBook k8s %&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Role의 이름은 pod-reader인데 권한은 services 관련 권한으로 설정되어있음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 rolebinding은 정상이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pod-reader를 수정하면 됨. k edit으로 수정하면 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 리소스 이름이니까 k get role -n prod 로 이름을 찾아준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. can-i 명령어로 무슨 리소스에 대한 무슨 동작을 누구의 권한에서 수행할 수 있는지 확인할 수 있음&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. describe role 도 마찬가지임 그냥 쓰던대로 해&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Q3. DB 서비스 배포했는데 Pod이 안뜬다. 고치고 /var/lib/data 에 볼륨 마운트되도록 수정하기&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pod이 안 뜨면 STATUS 부터 봐야함. YAML에는 볼륨이 있으니 PVC도 함께 확인해야 함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;볼륨을 쓴다면 Pod와 PVC를 한 세트로 봐야 한다. (k get pods, k get pvc)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PVC가 Pending이면 당연히 Pod도 Pending이다. PVC 부터 고쳐야함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;k describe pvc data-claim -n prod로 확인해보니 fast-ssd 를 못찾는다고 함. 이게 머임? 이건 storageClass임. k get storageClass로 확인해보면 standard 하나만 뜬다. PVC는 fast-ssd를 요구하니까 이 부분을 고쳐야 함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;k edit pvc 로 고치려는데 안된다. pvc는 immutable이니까.. 한 번 만들면 수정이 안 됨. 삭제 후 재작성 해야 한다. 먼저 Pod가 쓰고 있으니 Deployment를 먼저 삭제하고 PVC를 삭제해야 한다. vim 으로 storage-issue.yaml을 수정하고 재생성한다. standard가 기본이니 그 줄을 그냥 지워버리는게 합리적이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바꾸고 나니까 아직도 Pending 인데 Events를 확인하자. provisioner를 확인하라고 함. k get pods -n kube-system으로 확인해보면 프로비저너가 없는걸 확인할 수 있음. 즉, 클러스터 문제라는거임. 그러니 minikube addons enable storage-provisioner로 활성화 해 주면 해결됨.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Q4. prod namespace에 로깅 에이전트를 배포해야 함. 노드 하나에 정확하게 하나씩 실행되어야 함. log-agent / busybox:1.36 / sh -c &quot;while true; do echo collecting; sleep 30; done&quot; 마스터 노드에도 배치되어야 함.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Deployemnt로 replicas: 3을 지정해도 스케쥴러가 노드 한개에 2개를 몰아줄 수 있음. 그러니 노드마다 한개를 강제하려면 DaemonSet을 사용해야 한다. Deployment yaml 템플릿에서 kind 부분만 바꿔주면 됨.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;minikube는 마스터 노드도 Pod를 배치할 수 있어서 그냥 그대로 쓰면 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;k create deployment log-agent --image=busybox:1.36 -n prod --dry-run=client -o yaml &amp;gt; agent.yaml&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;템플릿 뽑고 거기다가 kind 바꾸고 replicas 삭제하고 strategy 삭제하면 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혹시나 노드 중에서 taint 붙어있는거 있을 수 있으니 최종 점검하고 확인하면 됨. DaemonSet도 taint를 무시할 수는 없다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 yaml 작성할 때 commands 위치도 좀 알아두면 좋을듯.. &quot;sh&quot; &quot;-c&quot; &quot;나머지&quot; 이런 순서로 배치해야 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Q5. 프론트 배포했는데 서비스가 불안정함. frontend Pod 정상으로 만들고 SITE_NAME 환경변수 체크하고 frontend-svc로 접속되도록 수정하기.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서비스가 불안정하다는건 아예 안뜨는게 아니라 떴다 죽었다를 반복하는 것. get pods 에서 RESTARTS 되는걸 확인한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;describe로 확인해보면 Pod는 잘 뜸. 에러도 없음. 그런데 SIGQUIT를 받고 죽었다는건? 누군가 외부에서 죽인거다. 쿠버가 죽인듯.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Events를 보면 Liveness Probe에서 실패해서 재시작중이라고 함. 실패하면 컨테이너를 재시작하는거니까..&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨테이너가 듣는 포트는 80인데 실제로 헬스체크하는 포트는 8080이다. k edit deployment로 수정해줬음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;echo로 환경변수 찍을 때는 &quot; &quot; 말고 ' ' 로 감싸줘야 정상작동함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Q6. 리포트 서비스를 배포했는데 Pod이 만들어지지 않음. 아예 안보임. 고쳐보기.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;k get pods 했더니 없음. 그러면 describe deployment로 확인한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;must specify limits.cpu limits.memory 라고 함. 이러면 requests를 설정해 줘야 하는걸 알 수 있음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;resources는 컨테이너의 속성이니 containers의 아래, image name과 같은 라벨로 위치시켜야 함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨테이너의 속성은 containers 안에다가 배치하고 pod의 속성은 template.spec 아래에 배치한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;헷갈리면 Managing Resources for Containers 를 k8s docs에 검색하면 됨.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Q7. 매 분 마다 실행되는 백업 작업을 배포했는데 작업이 완료되지 않고 있음. CronJob은 만들어졌고 Job도 생성됨. 고쳐보기.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1785895749312&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CronJob  ──(시간 되면)──&amp;gt;  Job  ──(만듦)──&amp;gt;  Pod
  틀                      실행 단위          실제 작업&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CronJob은 작업을 반복해서 실행하라는 규칙이고, Job은 그 실제로 만들어진 작업을 의미한다. Pod는 Job이 실행하는 컨테이너임.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Deployment -&amp;gt; ReplicaSet -&amp;gt; Pod 계층과 유사하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;k get cronjob -n prod&amp;nbsp;&lt;br /&gt;k get jobs -n prod&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;br /&gt;k get pods -n prod&amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Job은 생기는데 Pod가 안생김. 그러니 describe job 으로 확인해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;확인하면 또 request와 limit를 설정해 줘야 한다고 함. 그러면 CronJob을 수정해서 해당 부분을 명시해 주면 됨.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위치는 컨테이너와 같은 위치.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 안된다. 이번에는 describe pod을 본다. 확인해보니 ConfigMap 이름 문제임.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CronJob을 수정해서 이름 맞춰주면 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 Deployment와 다르게 CronJob을 고쳐도 이미 만들어진 Job은 수정되지 않음. 그러니 k delete job --all -n prod 로 모두 삭제한 후 확인하면 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Q8. API 게이트웨이를 배포했는데 서비스로 접속이 안된다. Pod는 살아있는 상태. gateway-svc로 정상 접속되도록 고치기.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;k get pods로 확인했을 때 Running 이지만 READY 컬럼이 0/1 상태임. 뭔가 문제가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;k describe svc 와 pod로 봤을 때 Endpoints가 비어있음. 그런데 Selector는 정상이네?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pod를 보니 /healthz 로 요청을 보내고 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;/healthz 경로가 nginx에 없으니 404를 뱉고, READY 0/1이 되는 것. 그러니 Service가 Endpoints에서 제거되는거고..&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;READY가 0/1 이면 Selector가 아니라 다른걸 봐야한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;k describe로 볼 때 | less 를 사용하면 vim 처럼 확인할 수 있음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Q9. 장바구니 API가 배포가 안되고 서비스도 동작하지 않음. MODE 환경변수 확인하고 8080으로 접속되도록 확인하기&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Deployment의 selector는 immutable이다. 그러니 바꾸려면 삭제 후 재생성 해야 함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Service의 selector는 수정할 수 있으니 라벨 불일치 문제는 Service쪽을 수정하는게 합리적임.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DevOps/Docker &amp;amp;&amp;amp; Kubernetes</category>
      <author>i3months</author>
      <guid isPermaLink="true">https://13months.tistory.com/872</guid>
      <comments>https://13months.tistory.com/872#entry872comment</comments>
      <pubDate>Thu, 6 Aug 2026 10:49:07 +0900</pubDate>
    </item>
    <item>
      <title>[Kubernetes] kubectl 연습 - RoleBinding</title>
      <link>https://13months.tistory.com/859</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 회사 클러스터에서는 누가 뭘 할 수 있는지를 제어해야 한다. Role-Based Access Control이 필요함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;secret을 다룰 때도 사실 그냥 인코딩일 뿐이니 진짜 secret처럼 다루려면 RBAC로 아무나 get secret을 수행하지 못하게 해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;주체&lt;/b&gt; : 쿠버 밖의 사람, ServiceAccount&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Role:&lt;/b&gt; 권한의 목록으로 뭘 할 수 있느닞를 정의한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;RoleBinding&lt;/b&gt; : 주체와 Role을 묶는다. 특정 사람에게 이 Role을 준다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;912&quot; data-origin-height=&quot;819&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cMyxJo/dJMcacYeP9w/TFe4vPThPfK472qHLDFrM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cMyxJo/dJMcacYeP9w/TFe4vPThPfK472qHLDFrM1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cMyxJo/dJMcacYeP9w/TFe4vPThPfK472qHLDFrM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcMyxJo%2FdJMcacYeP9w%2FTFe4vPThPfK472qHLDFrM1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;566&quot; height=&quot;508&quot; data-origin-width=&quot;912&quot; data-origin-height=&quot;819&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Role과 RoleBinding은 특정 namespace 안에서만 유효하고, ClusterRole과 ClusterRoleBinding은 클러스터 전체에서 유효하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1784793171137&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;13months@13monthsBook k8s % k create serviceaccount pod-viewer
serviceaccount/pod-viewer created
13months@13monthsBook k8s % k create role pod-reader --verb=get --verb=list --resource=pods
role.rbac.authorization.k8s.io/pod-reader created
13months@13monthsBook k8s % k create rolebinding pod-viewer-binding --role=pod-reader --serviceaccount=default:pod-viewer
rolebinding.rbac.authorization.k8s.io/pod-viewer-binding created
13months@13monthsBook k8s % k get serviceaccount
NAME         AGE
default      5h38m
pod-viewer   17s
13months@13monthsBook k8s % k get role
NAME         CREATED AT
pod-reader   2026-07-23T07:47:21Z
13months@13monthsBook k8s % k get rolebinding
NAME                 ROLE              AGE
pod-viewer-binding   Role/pod-reader   11s
13months@13monthsBook k8s %&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;User는 인증서 설정이 복잡하니 ServiceAccount를 사용해보자.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pod에게 제한된 권한을 주고 실제로 그 권한만 줄 수 있는지 확인하면 됨.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pod-viewer라는 앱 계정과 Pod를 대상으로 get과 list를 수행할 수 있는 role을 만들어주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 RoleBinding으로 ServiceAccount와 role을 연결해준다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1784993578740&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;13months@13monthsBook k8s % kubectl auth can-i get pods
yes
13months@13monthsBook k8s % kubectl auth can-i get pods --as=system:serviceaccount:default:pod-viewer
yes
13months@13monthsBook k8s % kubectl auth can-i list pods --as=system:serviceaccount:default:pod-viewer
yes
13months@13monthsBook k8s % kubectl auth can-i delete pods --as=system:serviceaccount:default:pod-viewer
no
13months@13monthsBook k8s % kubectl auth can-i get secrets --as=system:serviceaccount:default:pod-viewer
no
13months@13monthsBook k8s %&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역할이 제대로 연결됐는지 확인해보자.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;can-i 명령어를 사용하면 특정 계정으로 특정 작업을 수행할 수 있는지 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관리자 계정으로 물어보면 무조건 yes라고 뜸.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의도된대로 나타남을 확인할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;kubectl auth can-i &amp;lt;동작&amp;gt; &amp;lt;리소스&amp;gt; --as=&amp;lt;주체&amp;gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이거를 기억해두면 권한 에러를 뱉을 때 뭐가 막혔는지를 확인할 수 있다. 그러니 Role이나 RoleBinding을 고쳐주면 됨.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 Role은 자기 namespace 안에서만 유효하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Q. 웹 애플리케이션을 쿠버네티스에 배포해줘. 설정값은 외부에서 주입하고, 데이터는 영구 저장되어야 하고, 외부에서 접속 가능해야 해. 전용 namespace에 격리해서.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1785041904546&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1. namespace
k create namespace guestbook

2. ConfigMap
k create configmap app-config \
  --from-literal=APP_TITLE=MyGuestbook \
  --from-literal=APP_ENV=production \
  -n guestbook
  
3. PVC (k8s docs에서 붙여넣기)
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: guestbook-data
  namespace: guestbook
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 500Mi
k apply -f guestbook-pvc.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실수로 pvc 말고 pv 만들었으면 삭제하고 진행해야 함. 수정은 불가능하다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;k8s docs에서 복붙하거나 dry-run으로 yaml 작성하자.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Q. guestbook namespace에 guestbook-app이라는 Deployment를 만드세요. 요구사항은 네 가지입니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;이미지: nginx&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;replicas: 3개&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;앞에서 만든 ConfigMap app-config의 값들을 환경변수로 주입 (envFrom 방식 &amp;mdash; 전체 주입)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;앞에서 만든 PVC guestbook-data를 컨테이너의 /data 경로에 마운트&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;yaml 구조를 외우려고 하지 말고 왜 거기 있는지 이해하자.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;replicas: 3은 Deployment의 속성이니 spec 바로 아래에 위치함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;image: nginx는 Container의 속성이니 containers 항목 안에 위치함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;envFrom은 Container의 속성이니 containers 항목 안에 위치함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;volumeMounts는 Container의 속성이니 containers 항목 안에 위치함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;volumes는 Pod의 속성이니 template.spec 아래 위치함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;volumeMounts는 컨테이너가 볼륨을 어디에 붙일지, volumes는 Pod가 어떤 볼륨을 가질지를 결정한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1785044239945&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: guestbook-app
  name: guestbook-app
  namespace: guestbook
spec:
  replicas: 3
  selector:
    matchLabels:
      app: guestbook-app
  strategy: {}
  template:
    metadata:
      labels:
        app: guestbook-app
    spec:
      containers:
      - image: nginx
        name: nginx
        resources: {}
        envFrom:
        - configMapRef:
            name: app-config
        volumeMounts:
        - name: data-vol
          mountPath: /data
      volumes:
      - name: data-vol
        persistentVolumeClaim:
          claimName: guestbook-data
status: {}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;dry-run 으로 템플릿 만들고 수정하되, 어디에 어떤 속성이 붙는지만 제대로 정리해두자.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;yaml에서 - 는 List로 여러 요소를 나열할 때 사용한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이름표:값은 Map이다. 맨날 쓰는 그거임&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨테이너는 여러 개일 수 있으니 리스트이고, 각 컨테이너는 여러 속성을 가지니 맵이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1785044603598&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 단순 값 리스트
colors:
- red
- blue

# 맵 리스트 (각 항목이 속성 여러 개)
people:
- name: 철수
  age: 20
- name: 영희
  age: 25

# 맵 안에 리스트, 그 안에 또 맵
containers:
- name: nginx           &amp;larr; 컨테이너 항목
  env:                  &amp;larr; 이 컨테이너의 env (리스트)
  - name: MODE          &amp;larr; env의 첫 항목
    value: prod         &amp;larr; 그 항목의 속성 (name보다 안 깊고 같은 레벨)
    
containers:          &amp;larr; &quot;containers라는 키. 값은 아래를 봐야 앎&quot;
- name: nginx        &amp;larr; &quot;-가 있네! containers는 리스트. 첫 항목 시작. name=nginx&quot;
  image: nginx       &amp;larr; &quot;-가 없고 name과 들여쓰기 같음. 첫 항목에 계속 속함. image=nginx&quot;
  ports:             &amp;larr; &quot;여전히 첫 항목의 속성. ports라는 키. 값은 아래 봐야 앎&quot;
  - containerPort: 80 &amp;larr; &quot;-가 있네! ports는 리스트. 그 항목은 containerPort=80&quot;
- name: sidecar      &amp;larr; &quot;-가 또 나옴! containers 리스트의 두 번째 항목 시작&quot;
  image: busybox     &amp;larr; &quot;두 번째 항목에 속함&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;containers: 에서 아래에 - 가 있으니까 containers가 리스트가 되는거임. - 가 없으면 그냥 맵이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리스트 아래에 같은 들여쓰기로 들어온다면 같은 항목이다. 새 리스트가 나오기 전까지 같은 항목으로 묶임.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;envFrom은 명령어 주입도 된다. 다만 PVC는 명령어로 안되니 YAML을 직접 조작해야 함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kubectl set env deployment/guestbook-app --from=configmap/app-config&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Q. guestbook namespace에 guestbook-svc라는 NodePort Service를 만들어서 guestbook-app을 포트 80으로 노출하세요.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1785046193314&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;13months@13monthsBook k8s % kubectl expose deployment guestbook-app \
&amp;gt; --name=guestbook-svc \
&amp;gt; --type=NodePort \
&amp;gt; --port=80 \
&amp;gt; --target-port=80 \
&amp;gt; -n guestbook
service/guestbook-svc exposed
13months@13monthsBook k8s % kubectl get svc -n guestbook
NAME            TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
guestbook-svc   NodePort   10.109.94.53   &amp;lt;none&amp;gt;        80:30548/TCP   20s
13months@13monthsBook k8s % kubectl describe svc guestbook-svc -n guestbook
Name:                     guestbook-svc
Namespace:                guestbook
Labels:                   app=guestbook-app
Annotations:              &amp;lt;none&amp;gt;
Selector:                 app=guestbook-app
Type:                     NodePort
IP Family Policy:         SingleStack
IP Families:              IPv4
IP:                       10.109.94.53
IPs:                      10.109.94.53
Port:                     &amp;lt;unset&amp;gt;  80/TCP
TargetPort:               80/TCP
NodePort:                 &amp;lt;unset&amp;gt;  30548/TCP
Endpoints:                10.244.1.8:80,10.244.2.6:80,10.244.0.8:80
Session Affinity:         None
External Traffic Policy:  Cluster
Internal Traffic Policy:  Cluster
Events:                   &amp;lt;none&amp;gt;
13months@13monthsBook k8s %&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 명령어로 되는지, YAML로 풀 수 있는지 판단하자. 대부분은 명령어로 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;YAML이 필요해도 빈 파일에서 시작하지 말고 병령어로 뼈대를 잡는게 좋다. --dry-run 을 사용하거나 k8s docs에서 긁어오자.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;dry-run을 사용한 후에 필요한 부분은 또 k8s docs에서 가져오는게 좋음. envFrom을 어느 위치에 넣는지? 같은것..&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 다 만들었다면 검증해야 함. k get / k describe / k exec 등&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DevOps/Docker &amp;amp;&amp;amp; Kubernetes</category>
      <author>i3months</author>
      <guid isPermaLink="true">https://13months.tistory.com/859</guid>
      <comments>https://13months.tistory.com/859#entry859comment</comments>
      <pubDate>Sun, 26 Jul 2026 15:16:32 +0900</pubDate>
    </item>
    <item>
      <title>[AWS] SAA-C03 오답노트 (1)</title>
      <link>https://13months.tistory.com/858</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;S3에 쿼리하는건 AWS Athena. JSON 쿼리 가능. SQL을 사용해서 S3에 있는 데이터를 간편하게 분석할 수 있는 서비스이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복제가 효과적으로 작동하려면 각 읽기 전용 복제본에 원본 DB 인스턴스에 동일한 양의 컴퓨팅 및 스토리지 리소스가 있어야 함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS EBS는 가상 하드디스크를 의미함. SSD랑 똑같다. 단일 EC2 인스턴스에 마운트됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EFS는 여러 EC2가 마운트되고 사용할 수 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DataSync는 데이터 전송 및 마이그레이션에 사용된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SnowBall Edge는 대용량 데이터를 네트워크를 안타고 하드웨어 디바이스로 AWS로 이관함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다중 MSA 환경에서는 메세지 수신을 위해 SNS가 필요함. 메세지 폭증에도 안전하게 처리하려면 SQS 필요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 환경을 AWS 클라우드로 현대화하려면 결합도를 낮추고 확장할 수 있어야 함. 기본 서버 대신 SQS를 사용한다. EC2 Auto Scaling이 인스턴스 수를 조작해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;S3는 SMB를 그대로 지원한다. 버킷에 수명 주기 정책 적용하면 S3 Glacier Deep Archive로 자동 전환해 저장 비용 극대화해서 절감 가능.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주문이 접수된 대로 처리하려면 SQL FIFO 대기열을 사용한다. 이후 Lambda 함수 호출로 처리. 그냥 SNS는 순서 보장 없는 구독 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스 자격 증명 관리와 운영 최적화를 위해 Secret Manager를 사용함. Secret Manager는 기본 빌트인 자동 회전 기능을 제공한다. 그러니 자주 교체해야 하면 Secret Manager를 사용.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;글로벌 사용자 대기시간 줄이기 + 정적 동적 데이터 성능 개선을 위해 CloudFront 배포를 생성한다. CloudFront는 여러 오리진을 지원하니 배포 하나에서 정적은 S3로 동적은 ALB로 라우팅 가능. ALB에서 EC2와 S3로 직접 분기하는건 불가능하다. ALB의 타겟 그룹은 EC2, IP주소, Lambda 뿐임. Cloudfront는 CDN이다. CDN은 캐싱 가능함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Global Accelerator는 캐싱 없이 비 HTTP 트래픽 (TCP/UDP) 을 고정 IP로 가속한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Aurora는 MySQL과 호환되는 맞춤형 DB 엔진으로 RDS MySQL보다 성능도 좋음. Aurora Auto Scaling 정책을 설정하면 Aurora 읽기 전용 복제본을 동적으로 조작해준다. 다중 AZ로 고가용성 확보. 다중 AZ 가 성능을 올려주지는 않는다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VPC(Virtual Private Cloud)로 들어오고 나가는 트래픽에 대한 검사를 위해 Network Firewall을 사용한다. 온프레미스에서의 검사 서버 역할을 그대로 쓸 수 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VPC는 클라우드 안에 만드는 나만의 격리된 가상 네트워크를 의미한다. 10.0.0.0/16 같이 IP 주소를 정하고 그 안에서 네트워크를 구성한다. VPC를 더 작게 쪼갠 구역은 서브넷으로, 퍼블릭 서브넷은 인터넷과 직접 연결되는 구역이고 프라이빗 서브넷은 외부에 노출되면 안 되는 자원을 배치한다. IGW는 VPC를 인터넷과 연결해 주는 출입문으로 퍼블릭 서브넷의 자원이 인터넷과 통신하려면 이게 필요함. 실제 서버 라우터 케이블 등 물리적인 작업은 AWS가 알아서 해주고, 프라이빗 서브넷에 어떤걸 둘지, 방화벽 규칙을 어떻게 설정할지는 내가 직접 설계해야 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;QuickSight는 RDS S3에 직접 연결해 데이터를 통합하고 시각화 할 수 있음. 대시보드 공유 및 엑세스 제어는 IAM이 아니라 QuickSight 내부의 사용자 및 그룹을 기반으로 관리된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EC2 인스턴스가 S3 버킷에 접근할 수 있으려면 IAM 생성 후 EC2 인스턴스에 연결해야 한다. IAM 정책은 JSON 문서일 뿐이니 EC2 인스턴스에 직접 연결할 수 없다. 그러니 정책을 IAM 역할에 첨부하고 그 역할을 EC2에 연결해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트 알림 + SQS + Lambda 를 사용한다. S3는 Event Notification이 있다. 그러니 SQS 대기열로 메세지를 전달하는게 가능함. 트래픽 폭증해도 SQS가 처리함. Lambda가 SQS를 구독하면 자동 실행된다. Lambda는 Stateless.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타사 방화벽을 AWS에 적용한다. 이럴 때는 Gateway LoadBalancer를 사용하는게 좋음. Gateway LoadBalancer는 타사 그룹을 쉽게 사용할 수 있도록 만들어진 전용 로드밸런서. 웹서버 도달 전 모든 트래픽을 검사해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터의 완전 독립 복사, 고성능 I/O 필요 + 준비시간 최소화 &amp;rarr; EBS 스냅샷 + 스냅샷 복원 활성화. 인스턴스 스토어 볼륨은 휘발성이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;피크 시간에 초저지연 처리 + 운영 오버헤드 최소화 &amp;rarr; 서버리스 아키텍처 사용. 자동 확장 가능하고 오버헤드가 낮다. S3 정적 호스팅과 CloudFront 캐싱으로 저지연 구현 가능.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AZ 복원 + 저장 및 검색 비용 최소화 &amp;rarr; S3 Intelligent Tiering. 자주 접근하는 객체와 그렇지 않은 객체를 자동으로 이동시킨다. 여러 AZ에 데이터 저장해 AZ 손실 강함. 예측할 수 없는 패턴이면 S3 Intelligent-Tiering. 1개월 후 접근하지 않는게 명확하다면 Intelligent-Tiering 보다 Glacier Archive가 더 저렴하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인스턴스 유형별 수직 확장 원인 분석 + n개월간 비용 비교 그래프 &amp;rarr; Cost Explorer를 사용한다. 기본 제공 시각화 도구로 세분화해서 비용 추세 그래프를 만들 수 있음. 관리형 도구라 쉬움.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS Config는 리소스 구성을 측정하거나 평가하는 서비스. S3 버킷 에 대한 무단 구성 변경 식별. 지정된 태그가 없는 리소스를 자동으로 찾아 규정 위반으로 표시해 줄 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제품 관리자가 AWS 계정이 없다면 CloudWatch 콘솔에서 대시보드를 공유하고 제품 관리자의 이메일 주소로 공유 링크 전달.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS Organizations로 SSO를 설정하면 AD를 계속 사용할 수 있다. AWS랑 Microsoft 같이 써야 하니까 Two-way Forest Trust를 사용해야 함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UDP 기반 VoIP + 지연시간 최소 + 리전간 Failover &amp;rarr; TCP/UDP를 처리하는 NLB를 사용한다. ALB는 HTTP 기반임. Global Accelerator 도 사용.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인스턴스 중지되면 최대 7일까지만 중지 유지되고 자동시작됨. 인스턴스를 삭제하면 스토리지까지 같이 사라진다. 남는거는 DB 스냅샷인데 스냅샷 저장은 저렴하다. 그리고 그대로 복원하면 됨. 스냅샷은 S3 에 저장되니 인스턴스 사라져도 유지됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정적 컨텐츠로만 구성된다면 S3를 사용할 수 있다. S3도 정적 웹사이트 호스팅을 제공함. 서버가 필요 없으니 저렴하다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수백만 건의 데이터를 확장 가능하게 처리 + 여러 애플리케이션과 실시간으로 공유해야 하는 경우는 Kinesis Data Streams를 사용한다. 저장 전 민감 데이터를 제거할 때는 Lambda를 사용한다. DynamoDB는 대규모 데이터에서도 저지연을 구현하는 NoSQL 이니 지연 시간이 짧은 검색이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS 리소스의 구성 변경 추적은 AWS Config가 처리하고, AWS CloudTrail은 누가 언제 어떤 API를 호출했는지를 기록한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대규모 DDoS 공격을 감지하고 DNS는 타사 서비스를 사용하는 경우 AWS Shield Advanced를 활성화하고 ELB를 할당한다. Shield Standard는 일반적인 공격 방어해주고 Shield Advanced는 대규모 정교한 DDoS 공격을 방어해준다. 타사 서비스를 사용해야 하니 보호 대상으로 지정할 수 있는건 ELB이다. Inspector는 취약점 스캔 서비스이고 GuardDuty는 계정 보호 서비스이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IGW는 VPC와 인터넷을 연결해주는 출입문이고 트래픽 분산은 ELB가 처리한다. 즉 IGW -&amp;gt; ELB -&amp;gt; EC2 이런 절차를 거치게 됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 리전에서 동일한 키로 암복호화 하면서 키가 각 리전에 저장하려면 KMS를 사용한다. 일반적인 KMS 키는 리전에 종속되니 서로 다른 리전의 두 버킷을 KMS 다중 리전 키를 사용해야 한다. SSE-S3는 AWS가 관리하는 키라서 고객 관리형이 아니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;System Manager Session Manager는 인스턴스에 IAM 역할만 연결해주면 브라우저에서 안전한 셸 세션을 열 수 있다. SSH 포트를 열 필요도 없으니 관리할 필요도 없어서 오버헤드가 가장 낮다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CloudFront는 CDN이다. S3 버킷을 오리진으로 삼고 CloudFront를 앞에 두면 정적 컨텐츠가 캐싱되니 전 세계 사용자의 지연 감소.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매일 수백만 건의 업데이트가 발생 + INSERT 작업이 10초 이상 걸림 + 스토리지 문제라고 판단한 경우 스토리지 유형을 변경한다. Provisioned IOPS SSD는 원하는 IOPS 수치를 명시할 수 있어 높은 I/O 성능을 보장한 스토리지이다. 다중 AZ를 설계한다면 읽기 부하를 분산할 수 있지만 여기서는 INSERT가 병목이다. 다중 AZ 배포의 목적은 고가용성과 장애조치이지 성능이나 읽기 확장이 아니다. 하나가 죽었을 때 다른 AZ에 있는거를 승격시켜서 서비스를 이어간다. Read Replica는 읽기 성능 확장을 목표로 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Kinesis Data Firehose는 대량의 스트리밍 데이터를 자동으로 적재한다. 서버를 띄우거나 관리할 필요가 없고 관리형이라 AWS가 Availability를 보장해준다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 EC2가 SaaS소스에서 데이터 수신, S3업로드, 알림까지 처리하면 성능이 저하된다. EC2가 하던 일을 관리형 서비스로 대체해서 부담을 제거해야 함. AppFlow는 SaaS 소스와 AWS 사이 데이터를 코드 없이 안전하게 전송해준다. 알림도 SNS를 사용하면 완전 관리형이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EC2와 S3가 NAT 게이트웨이를 거친다면 네트워크를 타기에 비용이 크다. S3 게이트웨이 VPC 엔드포인트를 사용한다면 VPC 안의 자원이 인터넷을 거치지 않고 AWS 서비스에 사설로 접근한다. S3와 DynamoDB는 무료다. AWS 에서 ingress는 무료지만 egress는 돈이 나간다. 그러니 무료 엔드포인트를 사용함. 인터페이스 엔드포인트는 물리적 자원을 띄운다. 그러니 과금하고 게이트웨이 엔드포인트는 물리적 자원을 띄우지 않는다. 그냥 트래픽 경로만 AWS 내부망으로 틀어준다. S3랑 DynamoDB만 게이트웨이 방식을 지원하는 이유는 이 두 개가 초창기에 나왔기 때문임.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Direct Connect는 온프레미스 데이터센터와 AWS를 이어주는 물리 네트워크 연결이다. 이걸 깔아두고 트래픽을 이 회선으로 보내주면 백업이 회사의 공용 인터넷 회선을 사용하지 않는다. Snowball은 일회성 대량 마이그레이션에 적합하다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우발적인 삭제로부터 데이터를 보호하려면 S3 버전 관리를 키거나 MFA 삭제를 켜야한다. MFA 삭제를 켜면 삭제할 때 인증 코드가 있어야 함. 버킷 정책은 데이터 자체를 복구하지는 않음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SNS에서 바로 Lambda를 연결한다면 네트워크 문제로 Lambda 처리가 실패할 때 SNS 는 몇 번 재시도 후 이벤트를 버린다. SQS 대기열을 끼워두면 메세지를 안전하게 처리할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Amazon Macie는 머신러닝을 사용해서 S3에 저장된 데이터에서 PII같은 민감 정보를 자동으로 분류해준다. 관리형 서비스니까 PII 탐지 로직을 직접 개발할 필요가 없읜 편함. Lambda는 최대 실행 시간이 15분이라서 초대용량 파일을 다루기에 부적합하다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;On-Demand Capacity Reservation은 특정 AZ에서 원하는 인스턴스 만큼의 EC2 용량을 확보한다. 그러니 단기 용량 보장에 딱 맞음. Reserved Instance는 n년 약정으로 인스턴스를 사용하는 대신 요금을 할인받는 개념이다. 가용 영역도 함께 지정해야 함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EFS는 관리형 공유 파일 시스템으로 여러 AZ에 걸쳐 중복 저장하고 여러 EC2 인스턴스가 접근할 수 있으니 좋음. 인스턴스 스토어 파일을 EFS로 옮기면 데이터도 보존되고 여러 서버가 같은 카탈로그를 공유할 수 있다. 카탈로그는 그냥 말 그대로 상품 목록을 말한다. 다만 데이터베이스 레코드가 아니라 파일로 저장되어 있음. EFS는 파일 시스템이고 EC2에 마운트하면 평소처럼 파일 경로로 읽고 쓴다. S3는 객체 스토리지라서 API를 호출하도록 애플리케이션을 다시 작성해야 함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Glacier Deep Archive는 복원에 12시간 걸리니 오래된 파일 조회가 힘들다. 언제 조회될지 모르는 무작위 패턴이면 Intelligent-Tiering 를 사용하는게 합리적. Glacier Flexible Retrieval은 Deep Archive 보다는 비싸지만 복원 시간이 짧다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Systems Manager Run Command를 사용하면 모든 EC2 인스턴스에 패치를 적용할 수 있다. 패치 대상이 타사 소프트웨어고 빠르게 적용해야 하니 Systems Manager Patch Manager는 안된다. 이거는 AWS 서비스에만 적용할 수 있음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EventBridge 예약 이벤트로 매일 Lambda를 호출해 REST API를 쿼리하고 SES로 이메일 보고서를 발송한다. AWS Glue는 대규모 데이터에 대한 ETL을 수행하니 단순한 REST API에서는 경량 커스텀 로직을 위한 Lambda가 적합하다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Windows 워크로드를 사용하고 Windows 파일 공유를 사용한다면 Windows 방식을 유지해야 한다. Windows는 SMB 프로토콜을 사용하니 Amazon FSx for Windows File Server가 적합하다. Window Server 기반의 완전관리형 파일 시스템으로 SMB 지원함. EFS는 Linux용 파일 시스템이니 Windows 클라이언트에서는 적합하지 않다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프라이빗 서브넷에서 실행되는 EC2만 RDS 데이터베이스에 엑세스 가능해야 한다. 보안 그룹은 기본적으로 모든 인바운드 트래픽을 거부한다. 애초에 거부 규칙이 없다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ACM 인증서는 리전에 종속되니 어떤 서비스에 붙이는지에 따라 리전이 달라진다. 리전 API Gateway 엔드포인트에 인증서를 붙일 때는 API Gateway가 배포된 것과 동일한 리전의 ACM 인증서를 사용한다. AWS Certificate Manager는 SSL/TLS 인증서를 발급하고 관리해주는 AWS 서비스이다. ACM 에서 받아서 AWS 에 쓰는 공인 인증서는 무료고 자동으로 갱신해줌. 다만 CloudFront와 엣지 최적화 API Gateway는 글로벌 엣지 기반이라 us-east-1 인증서를 참조한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS Rekognition은 이미지와 비디오를 분석하는 완전관리형 AI 서비스이다. 객체 얼굴 인식 텍스트 추출을 지원함. 신뢰도 점수도 같이 반환해주니 애매한 경우에만 사람이 검토하도록 하면 좋음. Comprehend는 텍스트를 읽고 이해한다. 어떤 언어로 쓰였는지 판별할 때 사용함. SageMaker는 데이터 준비하고 모델 학습시키고 튜닝해서 배포하고 전 과정을 지원한다. Transcribe는 STT이다. Polly는 TTS이다. Textract는 보고서에서 텍스트를 추출한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Fargate는 서버리스 컨테이너 실행 환경으로 컨테이너에 필요한 CPU와 메모리만 지정하면 알아서 준비한다. Fargate에서 ECS를 사용하면 됨.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클릭스트림은 사용자가 웹사이트에서 클릭하고 이동하는 행동을 말한다. 수집 단계는 Kinesis Data Streams. 전송 및 적재는 Kinesis Data Firehose. Firehose는 스트림 데이터를 S3같은 목적지에 자동 적재해준다. 분석 단계는 Redshift. 대규모 데이터를 SQL로 분석하는 데이터 웨어하우스이다. EMR은 Elastic MapReduce로 대규모 데이터를 분산 처리하는 빅데이터 플랫폼이다. Hadoop Spark를 AWS에서 클러스터 형태로 쉽게 쓸 수 있음. 편하긴 한데 완전 서버리스는 아니다. AWS Data Pipeline은 정해진 일정에 데이터를 옮기는 배치 도구이다. (클릭스트림과는 맞지 않음)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ALB가 HTTP와 HTTPS를 각각 처리하도록 구성되어 있다면 HTTP요청을 HTTPS로 리다이렉트 하면 된다. ELB는 AWS의 로드밸런싱 서비스 전체를 가리키는 상위 개념이고 ELB 아래에 ALB NLB GWLB 가 있다. HTTP 기반은 ELB, TCP/UDP 기반은 NLB, 타사 방화벽 및 보안 어플라이언스는 GWLB.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS Secrets Manager는 자격 증명을 Secret Manager에 안전하게 저장하고 애플리케이션을 실행 시점에 API로 가져올 때 사용한다. RDS와 통합되어 있으니 교체 주기만 설정해두면 비밀번호 생성과 RDS 반영을 자동으로 처리한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ACM이 직접 발급하는 인증서는 자동 갱신이 되지만 외부에서 발급받은 인증서를 가져오는 경우 자동 갱신이 안되니 알림 받고 수동으로 교체하는게 최선이다. EventBridge로 이벤트를 발생시킬 수 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;S3는 파일 저장에 최적화되어있음. 용량도 사실상 무제한이고 저장 단가도 굉장히 저렴하다. 그냥 PUT 과 Lambda로 구축하기 정말 좋음. EC2 인스턴스를 상시 운영하면 비용이 많이 발생한다. EFS를 쓰면 EC2를 상시 운영할 수 밖에 없는구조이다. 단가도 S3가 가장 저렴하다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Windows 워크로드를 AWS로 이전하고 있다. Windows를 버리는게 아니라 기존 파일 엑세스 패턴을 변경할 필요가 없다는거니 SMB 파일 공유 방식을 그대로 유지해야 하니 FSx for Windows File Server가 필수이다. 일부는 AWS에 있고 일부는 온프레미스에 남아있으니 최소 지연으로 파일에 접근해야 한다. AWS쪽은 FSx for Windows File Server가 담당하고 온프레미스 쪽은 Amazon FSx File Gateway가 담당한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;API Gateway는 클라이언트 요청을 받아서 백엔드로 전달해주는 관리형 서비스를 의미함. ALB와 API Gateway는 하나만 쓰는 경우가 많음. 람다 쓰는 서버리스라면 API Gateway가 진입점. 백엔드가 EC2나 컨테이너면 ALB가 진입점.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉각적인 엑세스가 필요한 경우 S3 Glacier 사용은 적합하지 않다. 이 경우 S3 Standard-Infrequent Access가 필요하다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SQS에는 중복 메세지가 없는데 RDS에는 중복 레코드가 생긴다는 건 같은 메세지가 두 번 이상 처리된다는 것. EC2 인스턴스가 메세지를 받아가면 SQS는 메세지를 삭제하지 않고 일정 시간동안 다른 소비자에게 보이지 않게 숨겨둔다. 이 숨기는 시간이 가시성 초과 시간. 소비자가 처리 도중 죽어버릴 수 있으니 이렇게 하는 것. 처리 시간이 가시성 시간 초과보다 길 때 문제가 발생함. SQS FIFO 대기열은 한 번 처리를 보장하지만 기존 표준 대기열 구조를 유지하기에 가시성 시간 초과 조정이 답이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VPN은 공용 인터넷 위에 암호화된 터널을 얹는 방식이기에 지연과 대역폭이 인터넷 상황에 따라 변한다. Direct Connect는 AWS와 온프레미스를 이어주니 지연이 일관된다. 기본 연결은 Direct Connect로 하되 장애 시 VPN으로 전환해야 한다. 문제에서 비용을 최소화 해야 한다고 했으니.. 여기에 집중해야 함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RPO - Recoveru Point Objective로 데이터를 얼마나 잃어도 되는지를 의미한다. 15분이라면 장애 발생부터 최대 15분 전 까지의 데이터는 복구할 수 있어야 됨을 의미.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RTO - Recovery Time Object로 복구에 얼마나 걸려도 되는지를 의미한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DynamoDB의 지정 시간 복구는 테이블의 변경사항을 지속적으로 백업하는 기능이다. 활성화하면 35일 중 어떤 시점으로든 복구할 수 있음. EBS 스냅샷은 EC2에 연결된 블록 스토리지를 위한 기능이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배스천 호스트(Bastion Host)는 외부 네트워크에서 내부 네트워크로 안전하게 접속할 수 있도록 설계된 중계 서버를 의미함. 사내 네트워크는 192.168.0.0/16이나 10.0.0.0/8을 사용하는데, 이 사설 IP는 사내에서만 유효하다. 사내 PC가 인터넷을 통해 외부로 나갈 때는 NAT를 수행하기에 공인 IP로 바뀐다. 배스천 호스트 입장에서는 공인 IP를 보기에 공인 IP 범위를 허용해야 한다. 애플리케이션 인스턴스는 프라이빗 서브넷에 있고 배스천 호스트를 거쳐서 접근할 수 있으니 외부 네트워크를 타지 않아도 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인바운드는 나한테 들어오는 트래픽이고 아웃바운드는 내 리소스에서 외부로 나가는 트래픽을 의미한다. 보안 그룹은 인바운드로 허용된 요청의 응답을 자동으로 내보내준다. 웹서버에 접속하는걸 허용하면 돌려주는 응답은 아웃바운드를 따로 걸지 않아도 된다. 그러니 보안 그룹에서는 인바운드만 신경쓰면 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;0.0.0.0/0 은 모든 IP를 의미한다. 보안 그룹에서 소스를 저렇게 지정하면 전 세계 어디서든 접속이 허용됨을 의미함. 공개 웹사이트면 저거로 여는게 맞는데, SSH RDP DB 같은거를 개방해두면 전 세계 공격자가 다 공격시킬 수 있으니 주의해야 함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;규칙을 설정하는 대상은 데이터베이스 계층 보안 그룹이고, 그 규칙의 내용은 웹 계층 보안 그룹으로부터 오는 포트 1433을 허용하는 것. 인바운드의 소스가 웹 계층 보안 그룹이다. 웹 계층 보안 그룹이라는건 두 개임. 하나는 규칙을 설정하는 위치로서의 보안 그룹, 다른 하나는 규칙 안에서 소스로 참조되는 보안 그룹.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오버로드 발생 시 트랜잭션이 삭제된다면 서버를 키워도 용량을 초과하는 순간 유실된다. 유실을 막으려면 처리하지 못한 요청을 담아두는 곳이 필요한데, 이게 SQS. SQS로 계층 간 통신을 연결하면 아무리 바빠도 요청이 큐에 안전하게 쌓인다. 오버로드가 와도 트랜잭션이 삭제되지 않고 큐에서 대기하게 된다. Lambda를 함께 사용하고 API Gateway를 앞에 두면 무한 확장 서버리스 구조가 됨. 용량을 키우는건 임시방편일 뿐이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Kinesis Data Stream이 실시간 데이터를 받고 Firehose가 S3로 자동 적재한다. 변환은 Lambda가 수행함. 데이터 수집의 진입점으로 EC2 인스턴스는 좋지 않음. OS 패치 확장 등등 이런걸 직접 관리해야 하니 API Gateway 관리형 서비스로 서버리스하면 더 좋음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS Backup은 DynamoDB EBS RDS EFS 등의 백업을 중앙에서 관리하는 관리형 서비스. 백업 일정을 설정해 백업하고 보존 정책을 설정해 보존 기간을 설정한다. DynamoDB는 지정 시간 복구를 사용해 35일 까지만 복원할 수 있다. 실수로 삭제했을 때 복원하는 용도로 사용한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용량 예측이 안 되니 프로비저닝은 의미가 없다. 프로비저닝은 초당 읽기/쓰기를 몇 번 처리할지 정해주는 방식인데 Auto Scaling을 붙이면 트래픽에 따라 지정값을 늘리고 줄일 수 있다. 온디맨드가 가장 적합한 선택이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AMI는 EC2 인스턴스를 시작할 때 사용하는 템플릿으로 서버를 찍어내는 틀을 의미한다. 세팅 다 해두고 AMI 로 만들어내면 인스턴스 찍어낼 수 있음. Auto Scaling 그룹이 인스턴스를 늘린다면 AMI로 만들어지는 것. AMI가 암호화된 EBS 스냅샷 기반이면 KMS 키 공유도 필요함. MSP는 AWS 인증을 받은 파트너 회사로 AWS 환경 설계해주는 업체임. AMI 공유는 launchPermission 속성을 수정한다. 어떤 계정이 이 AMI로 인스턴스를 시작할 수 있는지를 지정하는 속성이다. KMS 키 정책을 수정하면 MSP 파트너 계정이 그 키를 사용할 수 있다. AMI만 공유해도 EBS 스냅샷이 KMS 키로 암호화 되어 있으면 파트너가 인스턴스를 시작할 수 없다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ACM에는 만료 알림 규칙을 설정하는 기능이 없다. AWS Config에는 인증서 만료를 확인하는 관리형 규칙이 있어서 보안팀에 알림을 보낼 수 있음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CloudFront는 정적 컨텐츠만 캐싱하지 않는다. 동적 컨텐츠 가속도 처리함. 요청을 오리진까지 전달하되 AWS의 최적화된 네트워크를 사용한다. 그러니 동적 웹사이트에도 CloudFront를 사용할 수 있음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EC2 구매 옵션은 여러개. 온드맨드는 필요할 때 켜서 쓴 만큼 낸다. 단가가 가장 비싸니 언제 켜고 끌지 예측하기 어렵거나 짧게 쓰는 경우 적합함. 예약 인스턴스는 1년 3년을 미리 약정하는 대신 크게 할인받는다. 장기간 꾸준히 켜져있는게 확실하다면 사용하자. 스팟 인스턴스는 AWS의 남는 여유 용량을 저렴하게 사용하지만 AWS가 언제든 회수할 수 있다. 중단되면 큰일남. 스팟 블록은 스팟의 변형으로 지정한 시간동안은 보장해준다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수정하거나 삭제할 수 없어야 하면 S3 Object Lock을 사용함. S3의 ACL은 이 버킷에 어떤 계정이나 그룹이 읽고 쓸 수 있는지를 지정하는 제어를 의미한다. 그런데 이건 구식 방식이니 IAM 으로 하는게 훨씬 낫다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS에서는 데이터가 egress에 따라서 전송 요금이 발생한다. 그러니 데이터 공유할 때 요청자 지불 기능을 활성화하면 데이터를 요청해서 가져가는 쪽이 돈을 내게 됨. 교차 계정 엑세스를 설정하더라도 데이터를 가져갈 때 발생하는 비용은 버킷 소유자가 부담한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Aurora는 항상 3개의 AZ에 6개의 복제본을 가진다. Aurora 복제는 전체를 물리적으로 복사하지 않고 copy-on-write 방식으로 즉시 복제본을 만들 수 있다. 원본을 그대로 읽는 작업이 아니라서 복제가 빠르다. mysqldump는 오래걸리니까 별로임.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IAM은 기본적으로 모든 것을 거부한다. 명시적으로 Allow가 있을 때만 허용함. 어떤 작업이 Allow여도 하나라도 Deny에 걸린다면 작업은 거부된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SQS FIFO 대기열은 순서 보장과 정확히 한 번만 처리하도록 하지만 대기열에 중복 메세지가 들어오는게 원인이 아니라 가시성 시간 초과 만료로 같은 메세지가 다시 처리되는 경우는 해결할 수 없다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Lustre는 고성능 파일 시스템을 위한 서비스로 HPC나 머신러닝이나 고성능 워크로드에 사용함. 매우 빠르게 처리한다. FSx라고 무조건 윈도우는 아니다. Lustre 파일 시스템이 필요한거고 여기서 필요한건 FSx for Lustre이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;KMS는 암호화 키를 안전하게 관리하고 암복호화를 수행한다. 매우 안전하고 실시간 암복호화 가능함. EBS는 단일 AZ에 종속되니 고가용성이 아니다. S3는 여러 AZ에 걸쳐 데이터를 저장하니 고가용성임.&lt;/p&gt;</description>
      <category>DevOps/Cloud Service</category>
      <author>i3months</author>
      <guid isPermaLink="true">https://13months.tistory.com/858</guid>
      <comments>https://13months.tistory.com/858#entry858comment</comments>
      <pubDate>Sat, 25 Jul 2026 15:11:41 +0900</pubDate>
    </item>
    <item>
      <title>NET 챌린지 13 : 멀티드론 기반 3D 상황인식 시스템 - 착수보고회</title>
      <link>https://13months.tistory.com/856</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2472&quot; data-origin-height=&quot;1410&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cT1l2G/dJMcaglZCnQ/rNaq0hkmfvGd8IQPPfxeDk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cT1l2G/dJMcaglZCnQ/rNaq0hkmfvGd8IQPPfxeDk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cT1l2G/dJMcaglZCnQ/rNaq0hkmfvGd8IQPPfxeDk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcT1l2G%2FdJMcaglZCnQ%2FrNaq0hkmfvGd8IQPPfxeDk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2472&quot; height=&quot;1410&quot; data-origin-width=&quot;2472&quot; data-origin-height=&quot;1410&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마당을 나온 드론 팀 발표 시작하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희가 넷챌린지 캠프에서 개발할 과제는 멀티드론 기반 재난 현장 3D 상황인식 시스템, SkyLens입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;드론으로 현장을 촬영하고, 그 영상을 3D 상황판으로 보여주는 시스템을 목표로 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2484&quot; data-origin-height=&quot;1418&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UjQdc/dJMcaaMTE7u/qoqgVVf6ukbPeErWOQXG9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UjQdc/dJMcaaMTE7u/qoqgVVf6ukbPeErWOQXG9K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UjQdc/dJMcaaMTE7u/qoqgVVf6ukbPeErWOQXG9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUjQdc%2FdJMcaaMTE7u%2FqoqgVVf6ukbPeErWOQXG9K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2484&quot; height=&quot;1418&quot; data-origin-width=&quot;2484&quot; data-origin-height=&quot;1418&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 저희가 만드려고 하는게 어떤 건지, 개요와 개발 필요성을 담은 기획안을 먼저 말씀드리고&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이어서 이 아이디어를 실제로 어떻게 구현할 것인지에 대한 계획과 KOREN 활용 방안 및 일정을 말씀드리겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로는 연구 개발비 사용 계획으로 마무리하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2478&quot; data-origin-height=&quot;1442&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cFa8fI/dJMcafgoIka/giNVeNxzSqhYwNB7JQVb2k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cFa8fI/dJMcafgoIka/giNVeNxzSqhYwNB7JQVb2k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cFa8fI/dJMcafgoIka/giNVeNxzSqhYwNB7JQVb2k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcFa8fI%2FdJMcafgoIka%2FgiNVeNxzSqhYwNB7JQVb2k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2478&quot; height=&quot;1442&quot; data-origin-width=&quot;2478&quot; data-origin-height=&quot;1442&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 개요입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 대의 드론이 RGB 카메라와 열화상 카메라로 현장을 촬영하면, 그 영상이 KOREN 고속망을 타고 코어 서버로 실시간으로 전송됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버에서는 이 영상을 3D로 복원하고 AI가 현장의 위험구역과 구조대상자를 감지합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복원된 3D 상황판은 현장 인근의 Edge 서버를 통해 구조자에게 전달되고, 구조자가 진입 동선을 판단하는 데 사용됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 방식과는 다르게 단일 드론이 아니라 여러 드론이 구역을 나눠 동시에 촬영하고, 30초 주기로 3D와 감지 결과를 갱신합니다. 또한 KOREN 기반으로 코어 서버와 엣지 서버에 역할을 분산합니다. 이 세 가지가 저희 과제의 차별점이라고 생각합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2490&quot; data-origin-height=&quot;1430&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cNZAPq/dJMcadQiEMF/E29w3hR4wwbb8ewbRSATYk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cNZAPq/dJMcadQiEMF/E29w3hR4wwbb8ewbRSATYk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cNZAPq/dJMcadQiEMF/E29w3hR4wwbb8ewbRSATYk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcNZAPq%2FdJMcadQiEMF%2FE29w3hR4wwbb8ewbRSATYk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2490&quot; height=&quot;1430&quot; data-origin-width=&quot;2490&quot; data-origin-height=&quot;1430&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 시스템을 만들지 말씀드렸으니, 이 시스템이 왜 필요한지 말씀드리겠습니다. 세 가지 배경이 맞물려 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫째, 재난 구조 현장의 어려움입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2024년 문경 화재에서는 내부 고립자의 위치를 모른 채 진입한 소방대원이 순직하는 사건이 있었고, 2025년 광명 신안산선 터널 붕괴에도 소방드론이 투입됐습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 실제 구조 작업에 들어가기 전에 내부 위험을 파악하는게 매우 중요함을 의미합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘째, 드론이 이미 현장에 자리 잡고 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;재난드론 출동 횟수는 5년만에 6배정도 증가했고, 소방청과 지자체는 이미 AI 분석을 통해 본격적으로 AI 전환을 시작하고 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;셋째, 관련 기술의 발전입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 각도에서 촬영한 영상을 3D로 복원하고 구조대상자를 감지하려면 Gaussian Splatting, TransUNet같은 복원 및 감지 기술이 필요합니다. 이 기술들은 이미 실용 단계에 들어섰고, 최근에는 드론 오디오 데이터를 사용해 소리 기반으로 구조대상자를 탐색하는 기술이 등장하고 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 세 가지가 만나 멀티드론 영상을 3D로 복원하고 AI로 위험을 감지해 구조자의 판단을 돕는 일이 실현 가능하다는 점이 저희 과제의 출발점입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2502&quot; data-origin-height=&quot;1430&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dvqnzS/dJMcafOgXhL/b8jU1FDb742VVCqSz1HEvk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dvqnzS/dJMcafOgXhL/b8jU1FDb742VVCqSz1HEvk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dvqnzS/dJMcafOgXhL/b8jU1FDb742VVCqSz1HEvk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdvqnzS%2FdJMcafOgXhL%2Fb8jU1FDb742VVCqSz1HEvk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2502&quot; height=&quot;1430&quot; data-origin-width=&quot;2502&quot; data-origin-height=&quot;1430&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 시스템을 어떻게 구축할지 구체적으로 말씀드리겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이프라인은 총 4단계로 구성되고 이걸 코어 서버와 엣지 서버가 나눠서 처리합니다. 무거운 연산을 처리해야 하는 세 단계는 코어 서버가 처리하고 저지연 서빙은 엣지 서버가 담당합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;멀티드론 3D 복원 단계에서는 드론이 촬영한 영상에 3D Gaussian Splatting을 적용해 장면을 복원한 뒤 30초 주기로 갱신합니다. 이후 RGB 3채널과 열화상 1채널을 합쳐서 위험구역과 사람을 동시에 잡아냅니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 2D를 3D로 투영하고 상황판에 보여주는 단계입니다. 감지 결과를 실제 세계좌표의 3D 마커로 변환하고, 복원 결과를 엣지 서버가 받아 웹으로 구조자에게 빠르게 보여줍니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2484&quot; data-origin-height=&quot;1432&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PXlAW/dJMcaaznTKI/Yi8Rc7VsG7c16HzoqSn4ZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PXlAW/dJMcaaznTKI/Yi8Rc7VsG7c16HzoqSn4ZK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PXlAW/dJMcaaznTKI/Yi8Rc7VsG7c16HzoqSn4ZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPXlAW%2FdJMcaaznTKI%2FYi8Rc7VsG7c16HzoqSn4ZK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2484&quot; height=&quot;1432&quot; data-origin-width=&quot;2484&quot; data-origin-height=&quot;1432&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 말씀드린 내용을 도식화했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;드론들이 촬영한 영상은 KOREN 고속망을 거쳐 코어 서버로 전달되고 이 코어 서버에서 3D 복원 / 구조대상자 감지 / 기하 투영이 처리됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 점선으로 표현한 부분은 확장 기능으로 두 가지를 생각하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;드론이 촬영한 영상에 포함된 오디오를 YAMNet에 전달하고 생존자 의심 구역 감지 신뢰도를 높이는 기능입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;별도의 depth 센서 없이 이미 복원해 둔 3D Gaussian Splatting 장면을 드론 시점에서 렌더링하면 Depth Map을 얻을 수 있습니다. 이걸 역참조하면 2D 감지 결과를 3D 좌표로 올릴 수 있으니 정확도를 높이는 용도로 사용하려 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2500&quot; data-origin-height=&quot;1434&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ceZHtq/dJMcacxaGoC/ozWxPNoB0R4i7l7iwZzJM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ceZHtq/dJMcacxaGoC/ozWxPNoB0R4i7l7iwZzJM1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ceZHtq/dJMcacxaGoC/ozWxPNoB0R4i7l7iwZzJM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FceZHtq%2FdJMcacxaGoC%2FozWxPNoB0R4i7l7iwZzJM1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2500&quot; height=&quot;1434&quot; data-origin-width=&quot;2500&quot; data-origin-height=&quot;1434&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희가 목표로 하는 화면입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;화면을 두 영역으로 나눠 좌측은 드론 제어 시뮬레이션, 우측은 결과가 만들어지는 3D 상황판을 배치합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;드론이 현장을 훑으면 우측에 3D 화면이 렌더링되고, 그 위에 위험구역과 구조대상자가 마커로 표시됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추후 예정된 최종 시연에서는 이 화면을 좀 더 고도화한 상태로 보여드리고자 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2482&quot; data-origin-height=&quot;1420&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lhFJW/dJMcaae4ZwG/kS9ReACrJpZofkYkxopO20/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lhFJW/dJMcaae4ZwG/kS9ReACrJpZofkYkxopO20/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lhFJW/dJMcaae4ZwG/kS9ReACrJpZofkYkxopO20/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlhFJW%2FdJMcaae4ZwG%2FkS9ReACrJpZofkYkxopO20%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2482&quot; height=&quot;1420&quot; data-origin-width=&quot;2482&quot; data-origin-height=&quot;1420&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 방식과 저희 과제인 SkyLens를 비교한 표입니다. 핵심만 짚고 넘어가겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;획득 관점에서는 단일 드론과 일반 인터넷망 대신 멀티드론과 KOREN 고속 인터넷을 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인지 관점에서는 2D 영상 중계에 그치지 않고 현장을 3D로 복원하며 RGB에 열화상을 추가해 야간과 극한 상황에도 대응합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처리 관점에서는 오래 걸리는 사후 처리를 30초 주기 준실시간으로 바꾸고 연산을 코어와 엣지로 분산합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의사결정 관점에서는 2D 영상을 기반으로 판단하는 대신 3D 상황판을 기반으로 위치와 동선을 판단하도록 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정리하자면, 수 시간이 걸리던 상황인식을 30초 이내로 줄이고 이를 통해 재난 대응 골든타임을 확보하고자 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2498&quot; data-origin-height=&quot;1442&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVa37p/dJMcahSHaob/faoED3wo5ukPrfycDE5Q00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVa37p/dJMcahSHaob/faoED3wo5ukPrfycDE5Q00/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVa37p/dJMcahSHaob/faoED3wo5ukPrfycDE5Q00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVa37p%2FdJMcahSHaob%2FfaoED3wo5ukPrfycDE5Q00%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2498&quot; height=&quot;1442&quot; data-origin-width=&quot;2498&quot; data-origin-height=&quot;1442&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시스템 구축에 필요한 하드웨어와 소프트웨어를 말씀드리겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3대 이상의 드론이 RGB 및 열화상 카메라로 현장을 촬영하고, KOREN 고속망을 통해 코어 서버의 GPU 서버로 전달됩니다. 여기서 복원과 추론이 끝나면 현장 인근의 엣지 서버로 전송됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하드웨어 흐름 전체는 KOREN 고속망이 하나로 묶어줍니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영상 전송은 GStreamer와 FFmpeg으로 스트리밍 시간을 동기화하고, 3D 복원은 Gaussian Splatting을 바탕으로 점진적으로 갱신합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI 감지 쪽에서는 Pytorch와 TensorRT로 추론을 최적화하고 엣지 서버의 상황판은 Three.js와 Websocket으로 화면을 렌더링합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소프트웨어는 모두 검증된 오픈소스 기술을 사용합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2488&quot; data-origin-height=&quot;1450&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RAwU5/dJMcaa0oMC7/wBL3rC1Fk0RZaWWBlfOxLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RAwU5/dJMcaa0oMC7/wBL3rC1Fk0RZaWWBlfOxLk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RAwU5/dJMcaa0oMC7/wBL3rC1Fk0RZaWWBlfOxLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRAwU5%2FdJMcaa0oMC7%2FwBL3rC1Fk0RZaWWBlfOxLk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2488&quot; height=&quot;1450&quot; data-origin-width=&quot;2488&quot; data-origin-height=&quot;1450&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하드웨어 흐름은 KOREN 고속망을 중심으로 하나로 묶입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;드론 한 대당 50~100Mbps 를 전송하니 3대는 수백 Mbps를 동시에 보내야 합니다. 일반 인터넷망으로는 힘들고, KOREN 고속 인터넷을 사용해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코어 서버에서 엣지 서버로 데이터를 전달할 때도 마찬가지입니다. 3DGS 모델을 지연을 최소화하면서 보내야 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Gaussian Splatting과 AI 추론에는 GPU가 필요합니다. KOREN의 GPU 인프라를 코어로, 현장 인근 노드를 엣지로 사용합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희 과제가 다루는 내용이 재난 환경이다 보니, 네트워크 품질이 매우 중요합니다. 저희가 원하는 수준의 저지연과 네트워크 품질은 KOREN 전용망에서만 가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2478&quot; data-origin-height=&quot;1418&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sZAit/dJMb991xGgN/gOBEJaYDzjnW4RpDuIxHSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sZAit/dJMb991xGgN/gOBEJaYDzjnW4RpDuIxHSK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sZAit/dJMb991xGgN/gOBEJaYDzjnW4RpDuIxHSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsZAit%2FdJMb991xGgN%2FgOBEJaYDzjnW4RpDuIxHSK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2478&quot; height=&quot;1418&quot; data-origin-width=&quot;2478&quot; data-origin-height=&quot;1418&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;재난 환경 도메인에서는 신뢰성과 실시간성이 가장 중요하다고 생각합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;검증을 위해 측정이 필요합니다. 영상 전송은 대역폭과 지연을 바탕으로, 3D 복원은 갱신 주기와 화질을 바탕으로, AI 감지는 F1-Score를 바탕으로, 투영은 실제 좌표 대비 오차로 측정합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이프라인 통합 검증에서는 드론 촬영부터 엣지 서빙까지 걸리는 시간이 30초 이내가 되도록 목표하고 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로는 실제 상황을 가정해 모의 재난 현장에서 실제 드론을 배치하고 저희 과제가 제대로 동작하는지 테스트하려 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2506&quot; data-origin-height=&quot;1426&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vnfV4/dJMcaijQJZI/jJbsoHz5V05Ly3hKYYKmv1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vnfV4/dJMcaijQJZI/jJbsoHz5V05Ly3hKYYKmv1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vnfV4/dJMcaijQJZI/jJbsoHz5V05Ly3hKYYKmv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvnfV4%2FdJMcaijQJZI%2FjJbsoHz5V05Ly3hKYYKmv1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2506&quot; height=&quot;1426&quot; data-origin-width=&quot;2506&quot; data-origin-height=&quot;1426&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역할 분담과 일정입니다. 과제 개발 기간은 7월부터 11월까지로 잡았고, 8월까지 영상 전송과 3D 복원을, 9월까지는 AI 감지와 투영과 통합 시스템을 구축하고 11월에 최종 시스템을 완성하는걸 목표로 하고 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2470&quot; data-origin-height=&quot;1424&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGPvqX/dJMcadW8zRN/R6jkMqO0YZZBSDpFPKUrz1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGPvqX/dJMcadW8zRN/R6jkMqO0YZZBSDpFPKUrz1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGPvqX/dJMcadW8zRN/R6jkMqO0YZZBSDpFPKUrz1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGPvqX%2FdJMcadW8zRN%2FR6jkMqO0YZZBSDpFPKUrz1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2470&quot; height=&quot;1424&quot; data-origin-width=&quot;2470&quot; data-origin-height=&quot;1424&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기술이 구현됐을 때의 현장 변화를 정리했습니다. 크게 세 가지로 요약됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;촬영에서 상황판 반영까지 30초 이내로 처리해 구조자의 의사결정 시간을 단축합니다. 이를 통해 재난 대응 골든타임을 확보합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;야간과 연기 속에서도 RGB와 열화상을 융합해 구조대상자를 효과적으로 탐색합니다. 이를 통해 인명 구조 효율을 향상시킵니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 3D 상황판을 바탕으로 구조자가 안전한 진입 경로를 판단하도록 도와줍니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2500&quot; data-origin-height=&quot;1430&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LqX6N/dJMcafOgYVd/pEHuqhDF17mzSgWww71kok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LqX6N/dJMcafOgYVd/pEHuqhDF17mzSgWww71kok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LqX6N/dJMcafOgYVd/pEHuqhDF17mzSgWww71kok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLqX6N%2FdJMcafOgYVd%2FpEHuqhDF17mzSgWww71kok%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2500&quot; height=&quot;1430&quot; data-origin-width=&quot;2500&quot; data-origin-height=&quot;1430&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 예산입니다. 드론 대여비를 포함한 장비 및 재료비, 회의비, 국내여비로 구성됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이상 마당을 나온 드론 팀의 SkyLens 였습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;드론으로 현장을 촬영하고, 그 영상을 3D 상황판으로 보여주는 시스템을 목표로 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;감사합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  기록</category>
      <author>i3months</author>
      <guid isPermaLink="true">https://13months.tistory.com/856</guid>
      <comments>https://13months.tistory.com/856#entry856comment</comments>
      <pubDate>Thu, 23 Jul 2026 09:41:59 +0900</pubDate>
    </item>
    <item>
      <title>[Kubernetes] kubectl 연습 - Deployment ReplicaSet</title>
      <link>https://13months.tistory.com/854</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 쿠버네티스 클러스터를 다룰 때는 kubectl을 사용한다. (kube-control)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;666&quot; data-origin-height=&quot;96&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/by46sB/dJMcaic8dUZ/RpdTDfNP96CPjdkBMs3zMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/by46sB/dJMcaic8dUZ/RpdTDfNP96CPjdkBMs3zMk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/by46sB/dJMcaic8dUZ/RpdTDfNP96CPjdkBMs3zMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fby46sB%2FdJMcaic8dUZ%2FRpdTDfNP96CPjdkBMs3zMk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;631&quot; height=&quot;91&quot; data-origin-width=&quot;666&quot; data-origin-height=&quot;96&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그냥 명령어임. 도커 데스크탑 말고 CLI로 쓸 때 열심히 치던 명령어와 비슷하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1784615140430&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;13months@13monthsBook ~ % kubectl create deployment my-web --image=nginx
deployment.apps/my-web created
13months@13monthsBook ~ %&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Deployment로 간단한 웹서버를 하나 띄워보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pod을 직접 만들지 않고 Deployment를 사용해서 띄운다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1784615359599&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;13months@13monthsBook ~ % kubectl get deployments
NAME     READY   UP-TO-DATE   AVAILABLE   AGE
my-web   1/1     1            1           2m4s
13months@13monthsBook ~ % kubectl get pods
NAME                      READY   STATUS    RESTARTS   AGE
my-web-684f49ddf4-bm4gh   1/1     Running   0          3m36s
13months@13monthsBook ~ %&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;READY: 1/1 은 원하는 개수 중 준비된 개수를 의미하고 AVAILABLE은 지금 서비스 가능한게 1개 있다는 것.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만든건 deployment 인데 ReplicaSet이랑 Pod도 한개 같이 생겼다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;684f머시기는 ReplicaSet가 붙인 식별자이고, bm4gh는 Pod의 식별자를 의미한다. (라벨아님 라벨은 my-web)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pod는 언제든 죽고 새로 띄워지기에 매번 새로운 이름을 할당받는다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pod 안에는 nginx 웹서버가 한개 떠서 동작하는 중.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1784615578933&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;13months@13monthsBook ~ % kubectl delete pod my-web-684f49ddf4-bm4gh
pod &quot;my-web-684f49ddf4-bm4gh&quot; deleted from default namespace
13months@13monthsBook ~ % kubectl get pods
NAME                      READY   STATUS    RESTARTS   AGE
my-web-684f49ddf4-gj4bf   1/1     Running   0          4s
13months@13monthsBook ~ %&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pod을 지우니까 새로 생긴 Pod이 생성된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ReplicaSet 아이디까지는 같지만 Pod 아이디는 달라짐.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1784615699850&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;13months@13monthsBook ~ % kubectl get pods -o wide
NAME                      READY   STATUS    RESTARTS   AGE    IP           NODE       NOMINATED NODE   READINESS GATES
my-web-684f49ddf4-gj4bf   1/1     Running   0          104s   10.244.0.4   minikube   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
13months@13monthsBook ~ % kubectl delete pod my-web-684f49ddf4-gj4bf
pod &quot;my-web-684f49ddf4-gj4bf&quot; deleted from default namespace
13months@13monthsBook ~ % kubectl get pods -o wide
NAME                      READY   STATUS    RESTARTS   AGE   IP           NODE       NOMINATED NODE   READINESS GATES
my-web-684f49ddf4-ztrt6   1/1     Running   0          3s    10.244.0.5   minikube   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
13months@13monthsBook ~ %&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kubectl get pods -o wide 명령어로 아이피도 같이 확인해보면 죽고 새로 뜰 때 마다 아이피가 변하는걸 확인할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 지금은 Pods를 직접 삭제했는데 어차피 앞으로는 Pod를 직접 다루지 않고 Deployment를 다룬다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1784615828318&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 1. kubectl 자동완성 기능을 켜기 위한 설정을 셸 설정 파일에 추가
echo 'source &amp;lt;(kubectl completion zsh)' &amp;gt;&amp;gt; ~/.zshrc

# 2. k를 kubectl의 별칭으로 등록
echo 'alias k=kubectl' &amp;gt;&amp;gt; ~/.zshrc

# 3. k로도 자동완성이 되게 연결
echo 'complete -F __start_kubectl k' &amp;gt;&amp;gt; ~/.zshrc

# 4. 설정을 지금 터미널에 바로 반영
source ~/.zshrc&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;탭치면 자동완성 되긴 하고 kubectl 치는것도 귀찮으면 k로 쳐도 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1784615982537&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;13months@13monthsBook ~ % k get po
NAME                      READY   STATUS    RESTARTS   AGE
my-web-684f49ddf4-ztrt6   1/1     Running   0          3m55s
13months@13monthsBook ~ % kubectl expose deployment my-web --port=80
service/my-web exposed
13months@13monthsBook ~ % kubectl get service
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1       &amp;lt;none&amp;gt;        443/TCP   53m
my-web       ClusterIP   10.101.193.95   &amp;lt;none&amp;gt;        80/TCP    11s
13months@13monthsBook ~ % k delete pod my-web-684f49ddf4-ztrt6
pod &quot;my-web-684f49ddf4-ztrt6&quot; deleted from default namespace
13months@13monthsBook ~ % k get pods -o wide
NAME                      READY   STATUS    RESTARTS   AGE   IP           NODE       NOMINATED NODE   READINESS GATES
my-web-684f49ddf4-x9tlm   1/1     Running   0          7s    10.244.0.6   minikube   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
13months@13monthsBook ~ % k get service
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1       &amp;lt;none&amp;gt;        443/TCP   57m
my-web       ClusterIP   10.101.193.95   &amp;lt;none&amp;gt;        80/TCP    3m31s
13months@13monthsBook ~ %&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kubectl expose 명령어로 서비스를 만들자. deployment 앞에 서비스를 배치할거임.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서비스를 만들면 그 서비스의 IP가 고정되니 Pod가 죽어도 서비스의 IP는 그대로 유지된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지는 kubectl 명령어를 직접 쳤는데 이건 쿠버의 철학인 declarative와 거리가 좀 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;yaml을 정의해보자.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1784616509839&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-web
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-web
  template:
    metadata:
      labels:
        app: my-web
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링부트에서 항상 쓰던건데 이걸 처음부터 타이핑하지는 않음. AI로 yaml만들면 되긴 하는데 cka에서는 그게 안된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;--dry-run=client -o yaml 옵션을 붙이자. 실제로 만들지는 않고, 그 결과를 yaml 형식으로 보여달라는 명령어임.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1784616720309&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;13months@13monthsBook k8s % k apply -f my-web2.yaml
deployment.apps/my-web2 created
13months@13monthsBook k8s % k get pods
NAME                       READY   STATUS    RESTARTS   AGE
my-web-684f49ddf4-x9tlm    1/1     Running   0          19m
my-web2-6777b885f8-q6pnz   1/1     Running   0          95s
my-web2-6777b885f8-qd66d   1/1     Running   0          95s
my-web2-6777b885f8-rnjtk   1/1     Running   0          95s
13months@13monthsBook k8s % k get deploy
NAME      READY   UP-TO-DATE   AVAILABLE   AGE
my-web    1/1     1            1           37m
my-web2   3/3     3            3           3m2s
13months@13monthsBook k8s % vim my-web2.yaml 
13months@13monthsBook k8s % k apply -f my-web2.yaml 
deployment.apps/my-web2 configured
13months@13monthsBook k8s % k get pods
NAME                       READY   STATUS    RESTARTS   AGE
my-web-684f49ddf4-x9tlm    1/1     Running   0          21m
my-web2-6777b885f8-4h9gk   1/1     Running   0          6s
my-web2-6777b885f8-cr9z8   1/1     Running   0          6s
my-web2-6777b885f8-q6pnz   1/1     Running   0          3m44s
my-web2-6777b885f8-qd66d   1/1     Running   0          3m44s
my-web2-6777b885f8-rnjtk   1/1     Running   0          3m44s
13months@13monthsBook k8s %&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;replicas 개수를 1개 -&amp;gt; 3개 -&amp;gt; 5개로 바꿨음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3개에서 5개로 변할 때는 기존 3개는 그대로 두고 새로 2개만 추가해준다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;yaml만 수정하면 알아서 deployment가 Pod를 만들어주니 내가 직접 Pod를 만들 필요가 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1784617588094&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;13months@13monthsBook k8s % k delete deployment my-web my-web2
deployment.apps &quot;my-web&quot; deleted from default namespace
deployment.apps &quot;my-web2&quot; deleted from default namespace
13months@13monthsBook k8s % k delete service my-web
service &quot;my-web&quot; deleted from default namespace
13months@13monthsBook k8s % k get all
NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.96.0.1    &amp;lt;none&amp;gt;        443/TCP   80m
13months@13monthsBook k8s %&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;deployment를 삭제하면 그 아래 ReplicaSet과 Pods도 함께 정리된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음 apply 했을 때는 created로 나타나지만, 설정 파일 수정 후 다시 apply 하면 configured로 차이만 반영한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아예 파일이 없으면 만들고, 있는데 수정됐다면 차이만 반영하고, 변화가 없다면 아무것도 안함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1784618412322&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;13months@13monthsBook k8s % k create deployment broken --image=nginx:존재하지않는버전999
deployment.apps/broken created
13months@13monthsBook k8s % k get pods
NAME                    READY   STATUS             RESTARTS   AGE
broken-cbb5595d-5pwg5   0/1     InvalidImageName   0          6s
13months@13monthsBook k8s % k describe pod broken-cbb5595d-5pwg5 
Name:             broken-cbb5595d-5pwg5
Namespace:        default
Priority:         0
Service Account:  default
Node:             minikube/192.168.49.2
Start Time:       Tue, 21 Jul 2026 16:19:16 +0900
Labels:           app=broken
                  pod-template-hash=cbb5595d
Annotations:      &amp;lt;none&amp;gt;
Status:           Pending
IP:               10.244.0.12
IPs:
  IP:           10.244.0.12
Controlled By:  ReplicaSet/broken-cbb5595d
Containers:
  nginx:
    Container ID:   
    Image:          nginx:존재하지않는버전999
    Image ID:       
    Port:           &amp;lt;none&amp;gt;
    Host Port:      &amp;lt;none&amp;gt;
    State:          Waiting
      Reason:       InvalidImageName
    Ready:          False
    Restart Count:  0
    Environment:    &amp;lt;none&amp;gt;
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-mkq62 (ro)
Conditions:
  Type                        Status
  PodReadyToStartContainers   True 
  Initialized                 True 
  Ready                       False 
  ContainersReady             False 
  PodScheduled                True 
Volumes:
  kube-api-access-mkq62:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  3607
    ConfigMapName:           kube-root-ca.crt
    Optional:                false
    DownwardAPI:             true
QoS Class:                   BestEffort
Node-Selectors:              &amp;lt;none&amp;gt;
Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                             node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type     Reason         Age               From               Message
  ----     ------         ----              ----               -------
  Normal   Scheduled      16s               default-scheduler  Successfully assigned default/broken-cbb5595d-5pwg5 to minikube
  Warning  InspectFailed  1s (x3 over 15s)  kubelet            spec.containers{nginx}: Failed to apply default image tag &quot;nginx:존재하지않는버전999&quot;: couldn't parse image name &quot;nginx:존재하지않는버전999&quot;: invalid reference format
  Warning  Failed         1s (x3 over 15s)  kubelet            spec.containers{nginx}: Error: InvalidImageName
13months@13monthsBook k8s %&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;deployment를 만들 때 nginx 버전을 이상하게 치면 고장난다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kubectl get pods 명령어와 kubectl describe pod이름 명령어로 에러 로그를 확인해보자.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;STATUS를 보면 InvalidImageName으로 이미지 자체가 규칙에 안맞음을 확인할 수 있음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지 태그에 한글이 들어가니 깨졌다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Events부분을 확인해보면 에러 원인을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;couldn't parse image name invalid reference format 이라니까 저걸 보고 고쳐주면 됨.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1784618849872&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;13months@13monthsBook k8s % k set image deployment/broken nginx=nginx:latest
deployment.apps/broken image updated
13months@13monthsBook k8s % k get pods
NAME                      READY   STATUS    RESTARTS   AGE
broken-74897b87bc-cb7vv   1/1     Running   0          7s&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kubectl set images는 실행 중인 Deployment 컨테이너 이미지를 수정하는 명령어.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지가 깨졌으니까 이미지를 바꿔야 고칠 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;set image를 하면 내부적으로는 무중단 업데이트가 진행된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 확인해보자.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1784619056723&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;13months@13monthsBook k8s % kubectl scale deployment broken --replicas=3
deployment.apps/broken scaled
13months@13monthsBook k8s % k get pods
NAME                      READY   STATUS    RESTARTS   AGE
broken-74897b87bc-49kxs   1/1     Running   0          3s
broken-74897b87bc-79rd2   1/1     Running   0          3s
broken-74897b87bc-cb7vv   1/1     Running   0          4m5s
13months@13monthsBook k8s % k set image deployments/broken nginx=nginx:1.27
deployment.apps/broken image updated
13months@13monthsBook k8s % k get pods
NAME                      READY   STATUS              RESTARTS   AGE
broken-58cc58dd76-qmssq   0/1     ContainerCreating   0          3s
broken-74897b87bc-49kxs   1/1     Running             0          18s
broken-74897b87bc-79rd2   1/1     Running             0          18s
broken-74897b87bc-cb7vv   1/1     Running             0          4m20s
13months@13monthsBook k8s %&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무중단 업데이트의 방법 중 하나인 롤링 업데이트가 실행되는 순간이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예전의 Pod을 먼저 다 죽이지 않고 점진적으로 Pod를 띄운다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kubectl rollout status deployment/broken 명령어를 사용하면 deployment의 교체가 다 끝났는지 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;진행 중이라면 그 상황을 실시간으로 확인할 수 있음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1784619243525&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;13months@13monthsBook k8s % k get pods
NAME                      READY   STATUS    RESTARTS   AGE
broken-58cc58dd76-2qxf7   1/1     Running   0          2m52s
broken-58cc58dd76-dd7f6   1/1     Running   0          2m53s
broken-58cc58dd76-qmssq   1/1     Running   0          3m3s
13months@13monthsBook k8s % k rollout history deployment/broken 
deployment.apps/broken 
REVISION  CHANGE-CAUSE
1         &amp;lt;none&amp;gt;
2         &amp;lt;none&amp;gt;
3         &amp;lt;none&amp;gt;

13months@13monthsBook k8s %&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;rollout history의 REVISION을 통해 Deployment가 몇 번 바뀌었는지를 확인할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지를 두 번 바꿨으니 REVISION 3까지 생겼다. 다만 왜 바꿨는지 이유를 적어놓지 않아서 나머지는 none으로 뜸.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 rollout history에 리비전이 남아있다는건 바로 롤백도 가능하다는 것.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1784619418857&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;13months@13monthsBook k8s % k rollout history deployment/broken 
deployment.apps/broken 
REVISION  CHANGE-CAUSE
1         &amp;lt;none&amp;gt;
2         &amp;lt;none&amp;gt;
3         &amp;lt;none&amp;gt;

13months@13monthsBook k8s % k rollout undo deployment/broken
deployment.apps/broken rolled back
13months@13monthsBook k8s % k get pods
NAME                      READY   STATUS    RESTARTS   AGE
broken-74897b87bc-9p9gq   1/1     Running   0          9s
broken-74897b87bc-mt2cr   1/1     Running   0          8s
broken-74897b87bc-nv5rn   1/1     Running   0          9s
13months@13monthsBook k8s % k rollout history deployment/broken 
deployment.apps/broken 
REVISION  CHANGE-CAUSE
1         &amp;lt;none&amp;gt;
3         &amp;lt;none&amp;gt;
4         &amp;lt;none&amp;gt;

13months@13monthsBook k8s % k describe deployment broken | grep Image
    Image:         nginx:latest
13months@13monthsBook k8s %&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ReplicaSet 해시가 다시 돌아왔고 nginx 버전도 돌아왔다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;rollout history를 보면 REVISION이 1 3 4 로 변했는데..&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 내용의 리비전은 번호가 중복될 수 없고 항상 최신 번호를 받는다. 그러니 2번이 4번으로 식별자를 바꿨음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;describe로 잡을 수 있는 문제는 쿠버네티스 수준에서 해결할 수 있는 문제.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pod이 안 뜨거나, 이미지를 못 받거나, 자원이 부족하거나.. 이럴 때는 describe의 Events를 확인한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨테이너가 시작되긴 했지만 그 안에서 실행되는게 고장난 경우 앱이 출력하는 로그를 본다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;logs 명령어로 확인할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1784619758941&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;13months@13monthsBook k8s % k run crasher --image=busybox --command -- sh -c &quot;echo '앱 시작...'; echo '에러: 설정 파일을 찾을 수 없음' &amp;gt;&amp;amp;2; exit 1&quot;
pod/crasher created
13months@13monthsBook k8s % k get pods
NAME                      READY   STATUS             RESTARTS      AGE
broken-74897b87bc-9p9gq   1/1     Running            0             6m13s
broken-74897b87bc-mt2cr   1/1     Running            0             6m12s
broken-74897b87bc-nv5rn   1/1     Running            0             6m13s
crasher                   0/1     CrashLoopBackOff   1 (16s ago)   23s
13months@13monthsBook k8s % k logs crasher
앱 시작...
에러: 설정 파일을 찾을 수 없음
13months@13monthsBook k8s %&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kubectl run 명령어로 pod를 바로 띄울 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;arg로 exit 1; 호출하고 죽어버리니 컨테이너는 잘 뜨지만 앱이 오류를 뱉고 죽는다. 이 때 logs로 디버깅하면 됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건 못고친다 그냥 logs로 읽을 수 있다만 확인하고 넘어가자.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계속 죽는 애플리케이션은 현재 로그가 비어있을 수 있으니 kube ctl logs --previous로 죽기 직전까지의 로그를 봐야 함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DevOps/Docker &amp;amp;&amp;amp; Kubernetes</category>
      <author>i3months</author>
      <guid isPermaLink="true">https://13months.tistory.com/854</guid>
      <comments>https://13months.tistory.com/854#entry854comment</comments>
      <pubDate>Tue, 21 Jul 2026 16:51:28 +0900</pubDate>
    </item>
    <item>
      <title>[Kubernetes] Kubernetes Concept</title>
      <link>https://13months.tistory.com/853</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿠버네티스는 컨테이너를 관리하는 도구이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 컨테이너는 애플리케이션을 격리해서 실행하는 기술으로, 도커는 컨테이너 기술을 쉽게 쓰는 구현체 중 하나임.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿠버네티스가 직접 컨테이너를 실행하지는 않음. 도커에 종속된 기술은 아니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨테이너를 실행하는 런타임은 꼭 도커가 아니여도 상관없음. (2022부터 쿠버는 containerd 런타임을 사용한다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;docker run으로 컨테이너 띄우고 컨테이너에 웹 띄우고 자러갔는데 컨테이너가 메모리 부족으로 죽어버렸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿠버네티스를 사용하지 않으면 다시 docker run을 입력해야 함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;갑자기 사용자가 10배로 늘어버리면 컨테이너 하나로는 감당할 수 없으니 컨테이너를 여러 개 만들어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버컴 하나에 컨테이너 10개를 두는건 힘드니 서버컴 n개에 컨테이너 m개를 배치해야 함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 어떤 서버가컴이 여유로운지, 어떤 서버컴에 올려야 최적인지 판단해야 하는데, 매번 사람이 계산하는게 너무 힘들다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨테이너가 m개 떠있는데 이러면 서로 다른 IP를 가진다. 사용자는 이 m개 중 하나로 연결해야 함 (수평적 확장 기준)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;k번 컨테이너가 죽고 새로 띄우면 IP가 또 바뀐다. 이렇게 매번 바뀌는 IP도 관리해 줘야 하고, 로드밸런싱도 해 줘야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로운 버전을 배포한다고 하자. m개의 컨테이너를 한 번에 갈아끼우면 서비스가 멈춰버린다. 그러니 한 개씩 교체해야 함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새 버전을 하나 띄우고, 잘 뜨는지 확인하고, 문제 없으면 옛날꺼 내리고.. 이런식으로 반복해야 하는데 이걸 어떻게 사람이 하나씩 함?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 나온 문제를 해결하기 위해 쿠버네티스가 도입됐다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원하는 상태를 선언해두면 시스템이 알아서 맞추는 declarative 관리가 쿠버네티스 철학의 핵심임. (컨테이너 m개 떠있는 상태 유지 ㄱ)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수평 확장을 제1원칙으로 설정하는데, 수평 확장이 가능하려면 컨테이너들이 서로 대체 가능해야 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;API서버처럼 Stateless 하면 상관없지만 데이터베이스처럼 Stateful하면 수평 확장이 힘들다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 쿠버는 Stateless는 Deployment로, Stateful은 StatefulSet으로 두 가지를 구분해서 다룬다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿠버도 수직 확장이 가능하긴 함. Vertical Pod Autoscaler로 컨테이너 하나에 주는 CPU/메모리 크기를 자동으로 조정할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 컨테이너 크기를 바꾸려면 보통 그 컨테이너를 죽였다가 다시 올려야 하니 잠깐 멈출 수 밖에 없으니 수평 확장을 1원칙으로 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;726&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mndx3/dJMcaiqyzNV/yFEztPPGzCXfQOc5jYYlY0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mndx3/dJMcaiqyzNV/yFEztPPGzCXfQOc5jYYlY0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mndx3/dJMcaiqyzNV/yFEztPPGzCXfQOc5jYYlY0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fmndx3%2FdJMcaiqyzNV%2FyFEztPPGzCXfQOc5jYYlY0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;673&quot; height=&quot;382&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;726&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿠버네티스 전체는 클러스터라고 부른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클러스터를 구성하는 서버 하나하나를 노드라고 부르고, 노드는 또 두 가지로 구분된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Control Plane&lt;/b&gt;은 지시하는 쪽으로 실제 컨테이너를 직접 실행하지 않는다. (얘도 노드임)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨테이너 m개 떠있는 상태 유지하라고 declarative 선언이 들어오면 이걸 어떤 워커 노드에 배치할지를 결정하고 지시를 내린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Worker Node&lt;/b&gt;는 실제로 컨테이너를 실해앟는 부분이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Control Plane에서 내린 명령을 Worker Node가 받아서 containerd를 사용해 실제로 컨테이너를 실행한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트래픽이 늘어나면 Worker Node만 더 추가하면 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버 n대에 컨테이너m개를 배치 할 때 Worker Node가 서버 n대의 역할을 수행한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Worker Node 자체는 컨테이너가 아니고, 컨테이너를 담는 그릇임.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클러스터는 노드들의 묶음이고, 각 노드는 서버컴퓨터에 대응하며 컨테이너는 노드에 들어가는 구성요소이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;노드에 그냥 컨테이너를 바로바로 배치하면 좋은데, 컨테이너를 어떤 단위로 다룰건지를 생각해야 함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 서버를 컨테이너로 묶어서 운영하려고 하는데 여기서 만들어지는 로그를 수집해서 외부로 보내야 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러면 웹 서버 컨테이너 안에 로그 수집기를 같이 넣는게 맞을까 로그 수집기를 별도 컨테이너로 분리하는게 맞을까?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨테이너의 관심사는 하나면 좋으니 별도로 분리하자.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 로그 수집기와 웹 서버는 서로 통신이 가능해야 한다. 같은 파일 시스템을 보면 좋으니 로컬호스트에서 통신하면 더 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿠버가 얘내 둘을 따로 배치해서 웹서버는 Worker Node 1에 배치하고 로그 수집기는 Worker Node 2에 배치하면? 귀찮아진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 &lt;b&gt;Pod&lt;/b&gt;가 등장한다. 하나로 묶여서 다루면 좋은 것들은 Pod에 넣고, 배치할 때는 컨테이너 단위 대신 Pod 단위로 배치한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;738&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2nKiA/dJMcaiYkCuc/ODYrEOeQmFYahWJC1MlHSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2nKiA/dJMcaiYkCuc/ODYrEOeQmFYahWJC1MlHSK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2nKiA/dJMcaiYkCuc/ODYrEOeQmFYahWJC1MlHSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2nKiA%2FdJMcaiYkCuc%2FODYrEOeQmFYahWJC1MlHSK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;475&quot; height=&quot;274&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;738&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pod 안에 담긴 컨테이너들은 로컬호스트로 통신할 수 있고 저장 공간도 공유할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당연히 같은 Worker Node에 배치되는게 보장됨.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니까 정확히 말하면 쿠버네티스는 컨테이너를 관리하는게 아니고 Pod를 관리하는거임.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞에서 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;컨테이너 m개 떠있는 상태 유지하라는 명령은 Pod m개가 떠있는 상태를 유지하라는 말이다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;당연히 컨테이너 하나만 Pod에 넣는 경우도 많지만, 그래도 Pod로 포장해서 배치한다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;일관성 있게 처리해야 하니까.. 어디는 Pod로 배치하고 어디는 컨테이너로 배치하면 귀찮아진다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IP도 Pod에 붙고, 죽고 다시 올릴 때 마다 붙어있는 IP가 매번 바뀐다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pod 내부의 컨테이너들은 포트번호로 나눠서 구분한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 Worker Node가 죽어버리면 Control Plane이 감지하고 다른 Worker Node에 새 Pod을 필요한 만큼 띄운다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, Pod은 특정 노드에 묶여있지 않음. 어떤 노드에서든 새로 띄워질 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pod에는 무엇을 실행할지가 정의되어있다. 다만 몇 개를 유지할지와 죽으면 어떻게 할 지는 정의되어 있지 않음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pod를 관리하는 주체는 두 가지가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1075&quot; data-origin-height=&quot;730&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JVyFp/dJMcah6l1ZI/KSuv3LCEYB3ifpzo92LNS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JVyFp/dJMcah6l1ZI/KSuv3LCEYB3ifpzo92LNS0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JVyFp/dJMcah6l1ZI/KSuv3LCEYB3ifpzo92LNS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJVyFp%2FdJMcah6l1ZI%2FKSuv3LCEYB3ifpzo92LNS0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;538&quot; height=&quot;365&quot; data-origin-width=&quot;1075&quot; data-origin-height=&quot;730&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. ReplicaSet&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pod를 항상 정해진 개수만큼 유지하는 역할을 수행한다. 이름처럼 Pod의 복제본을 몇 개 유지할지를 관리함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3개로 만들어두라고 선언해두면 4개가 되면 하나 죽여서 3개로 만들고 2개가 되면 하나 띄워서 3개로 만들어준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. Deployment&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Deployment는 Replica 위에 있는 관리자로 ReplicaSet를 직접 다룬다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무중단 업데이트를 위해 버전을 갈아끼울 때 v2 Pod을 새로 띄우고, 확인하고, v1 Pod를 하나 죽이는 작업을 수행할 때 사용함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ReplicaSet을 두 개 사용하는 방식으로 무중단 업데이트를 구현한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;v2용 ReplicaSet을 만들고 v2용 ReplicaSet의 Pod 개수를 하나 늘리고 v1용 ReplicaSet의 Pod 개수를 하나 줄이는 작업을 반복한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러면 예전 ReplicaSet을 지우지 않으니 롤백도 쉽다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아까는 쿠버네티스가 Pod를 관리한다고 했는데 지금 보면 쿠버네티스가 Deployment를 관리하는 것 처럼 보임.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 둘 다 맞다. 내가 직접 다루는건 Deployment이고 쿠버네티스가 실제로 다루는 최소 단위는 Pod이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Deployment는 Pod를 관리하는 여러 방법 중 하나일 뿐.. Stateful 애플리케이션은 StatefulSet으로 관리한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 외에도 DaemonSet, Job 등 상황별로 여러 관리자가 있음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Deployment가 Pod 3개를 관리하고, Pod는 자신만의 IP를 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3개니까 IP도 3개인데, 사용자에게 3개중 아무데나 가라고 할 수는 없으니 로드밸런싱이 필요함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그냥 라운드로빈 돌면 될 것 같지만 Pod가 죽으면 새로 띄워지고 새로 띄워질 때 마다 IP가 바뀐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 그냥 IP를 하드코딩해두면 라우팅이 안된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여타 다른 클라우드 플랫폼이 그렇듯 고정된 이름을 하나 두는 식으로 해결하는데, 쿠버에서는 그 고정 IP를 가지는 객체를 서비스라고 부른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;744&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhIMJj/dJMcaixnW0l/MCXtlHSwumjdqJfXZHHHu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhIMJj/dJMcaixnW0l/MCXtlHSwumjdqJfXZHHHu1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhIMJj/dJMcaixnW0l/MCXtlHSwumjdqJfXZHHHu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhIMJj%2FdJMcaixnW0l%2FMCXtlHSwumjdqJfXZHHHu1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;552&quot; height=&quot;297&quot; data-origin-width=&quot;744&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서비스는 고정된 주소(아이피 + 도메인)를 하나 가지고 이 주소는 서비스 뒤에 있는 여러 Pod이 죽든 말든 바뀌지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 로드밸런싱을 수행하는 주체는 서비스임.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;752&quot; data-origin-height=&quot;529&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tWzuH/dJMcahkZb2v/s7ip2GIVS0KqdlrjVDca1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tWzuH/dJMcahkZb2v/s7ip2GIVS0KqdlrjVDca1k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tWzuH/dJMcahkZb2v/s7ip2GIVS0KqdlrjVDca1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtWzuH%2FdJMcahkZb2v%2Fs7ip2GIVS0KqdlrjVDca1k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;533&quot; height=&quot;375&quot; data-origin-width=&quot;752&quot; data-origin-height=&quot;529&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서비스가 알아서 죽은 Pod의 아이피를 정리하고 살아있는 Pod으로 연결해준다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pod에는 라벨이 붙어있다. 그리고 서비스는 라벨을 통해 Pod을 찾아냄.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pod가 죽고 다시 띄워질 때 IP는 계속 바뀌더라도 라벨은 바뀌지 않으니 매번 바뀌는 IP를 관리할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DevOps/Docker &amp;amp;&amp;amp; Kubernetes</category>
      <author>i3months</author>
      <guid isPermaLink="true">https://13months.tistory.com/853</guid>
      <comments>https://13months.tistory.com/853#entry853comment</comments>
      <pubDate>Tue, 21 Jul 2026 14:32:26 +0900</pubDate>
    </item>
    <item>
      <title>[Embedded Challenge] 자율주행 프로젝트 회고</title>
      <link>https://13months.tistory.com/848</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;568&quot; data-origin-height=&quot;744&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5YJlc/dJMcaiqmnvM/0Ehdgcm43bGdITlHuIQgwK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5YJlc/dJMcaiqmnvM/0Ehdgcm43bGdITlHuIQgwK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5YJlc/dJMcaiqmnvM/0Ehdgcm43bGdITlHuIQgwK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5YJlc%2FdJMcaiqmnvM%2F0Ehdgcm43bGdITlHuIQgwK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;396&quot; height=&quot;519&quot; data-origin-width=&quot;568&quot; data-origin-height=&quot;744&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 풀어야 할 문제를 명확하게 정의해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;미로는 약 5 m &amp;times; 10 m 직사각형 공간이며, 출발선에서 출발하여 북쪽에 위치한탈출구에 충돌 없이 가장 빠르게 도달하는 것이 목표다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;장애물은 uBrain 포장 박스로 구성된 고정형 장애물과 이동형&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;uBrain 1 대로 구분된다. 여기서 핵심은 탈출구가 반드시&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;북쪽에 위치하며 &amp;lsquo;ㅁ&amp;rsquo;형 맵이 아니라는 특징 그리고, 탈출구에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도달하기 위해 필요한 방향 전환 횟수가 정해져 있다는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부분이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 강한 가정을 통해서, 완전성이 보장되므로 이 문제를 디바이스에 방향에 대한 정보를 제공하여 북쪽(디바이스가 처음 놓인 방향) 탈출구로 안정적으로 수렴시키는 그리디 문제로 재정의했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초기에는 Occupancy Grid 기반 mapping, 벽 추출, A*/D* 전역 경로계획을 통합하는 풀스택 자율주행 파이프라인을 구현 및 실측했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 실측 과정에서 우리 팀이 받은 로봇의 좌&amp;middot;우 모터 출력 비대칭이 상대적으로 타 팀의 로봇보다 크고, 디바이스 내에 IMU 센서 부재로 인한 다소 부정확한 상태 추정을 수행할 수 밖에 없다는 근본적 한계를 확인했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 부정확한 환경 내에서 자세 추정의 누적 오차로 인해 Occupancy Grid 매핑 시 오히려 주행 안정성이 떨어지는 문제가 발생하였다. 따라서, 당일 오전에 맵이 공개된다는, 즉 우리가 미로의 구조를 알 수 있다는 점에 착안하여 2D 기반의 맵을 하드코딩하고, 추정하기 어려운 동적 장애물의 구간을 y 좌표의 임계점을 개략적으로 정의하여 확률 모델링을 통해 디바이스에게 동적 장애물에 대한 정보를 전달하여 추정한다는 원칙으로 설계를 축약했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이론적 최적성보다는 하드웨어 제약하에 견고성에 대한 핵심 원칙을 투영할 수 있는 알고리즘이 임베디드 시스템에서 더 중요하다고 생각했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;〈최종&amp;nbsp;아키텍처〉&amp;nbsp;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하드코딩한&amp;nbsp;미로(고정&amp;nbsp;벽)&amp;nbsp;+&amp;nbsp;EKF&amp;nbsp;센서&amp;nbsp;퓨전&amp;nbsp;+&amp;nbsp;Greedy&amp;nbsp;Cardinal&amp;nbsp;내비게이션&amp;nbsp;+&amp;nbsp;결승&amp;nbsp;직전&amp;nbsp;동적&amp;nbsp;장애물&amp;nbsp;확률&amp;nbsp;모델링&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;미로에는 곡선 구조가 전혀 없다. 모든 구성이 직교 구조로 구성된다. 이 구조를 고려해보면 로봇의 주행을 상하좌우 + 90 도 코너 회전으로 단순화 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순한 구조를 바탕으로 로봇의 주행을 복잡한 경로 추종 로직 대신 Finite State Machine 으로 환원한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1668&quot; data-origin-height=&quot;292&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xRYwE/dJMcadWTCK2/sdzYTvMKkUgmfhZCINFfLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xRYwE/dJMcadWTCK2/sdzYTvMKkUgmfhZCINFfLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xRYwE/dJMcadWTCK2/sdzYTvMKkUgmfhZCINFfLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxRYwE%2FdJMcadWTCK2%2FsdzYTvMKkUgmfhZCINFfLK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;701&quot; height=&quot;123&quot; data-origin-width=&quot;1668&quot; data-origin-height=&quot;292&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, 이 Finite State Machine 이 제대로 작동하기 위해서는 직진에 강하게 수렴하는 주행과 90 도 회전의 정밀도가 매우 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회전이 조금 어긋나거나 직진이 조금 어긋나는 경우 그 오차가 누적되고 경로가 무너지기에 회전&amp;middot;직진 보정을 집중적으로 검토했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 주행 알고리즘 - Greedy 북향 내비게이션 (Cardinal FSM)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Non-wall-following 과 함께, 측벽 거리의 변화량 &amp;Delta; 를 기준으로 코너 및 교차로를 이산 감지하여 회전하며 통로를 통과하되, 항상 북쪽(도착지)을 선호하도록 설정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구체적으로, 진행방향에 우선순위를 부여한다(북:0, 서&amp;middot;동:1, 남:2). 전면 충돌이 임박한 EMERGENCY 를 포함한 90 도 회전 상황에서는 이 우선순위에 따라 회피 방향을 결정하며(priority-prefer rotation), 동일 우선순위가 충돌할 경우 좌&amp;middot;우 센서 값을 비교해 더 넓은 쪽으로 진행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러면 충돌 직전 상황에서도 전체 진행 방향이 목표로 수렴한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 교차로 판별 시 북향 진행이 가능하면 북쪽을 강제 선택한다. 이러한 규칙을 통해, 북향 단조 구조를 갖는 미로라는 가정 하에서 사전 전역 경로 없이도 출구로의 도달이 보장된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;절대 좌표가 아니라 측벽 거리 및 cardinal heading(상대 방향)에 기반해 분기를 판단하므로, 위치 추정 누적 오차 드리프트에 강하고 부정확한 측위 위에서도 강하게 동작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 주행 알고리즘 -&amp;nbsp; 동적 장애물 확률 모델링&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이동형 uBrain 1 대는 위치가 변하니 하드코딩 맵으로 다룰 수 없고, IMU&amp;middot;정밀 센서가 없는 본 보드에서 이동체를 정밀 추적하는 것은 오히려 불안정하다. 따라서 정밀 추적 대신 관측-후-결단 휴리스틱을 채택했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 결승점 직전 마지막 구간(실습 채점기준 4 구간)에 진입하면 동적 회피 모드를 활성화한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 센서 빔 종점에 점유 확률을 시간 가중으로 누적 및 감쇠시켜 정적 벽과 이동 물체를 분리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 그 상태에서 로봇은 N 회 북향 사이클을 수행하며 가능한 만큼 안전하게 전진하고 이동 장애물의 통과 리듬 및 간격을 기록한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 전면이 임계 거리 이상으로 열린 통과 창이 확인되면, 순항 속도를 일시적으로 높여(V_cruise &amp;rarr; V_dash) 장애물이 되돌아오기 전에 빠르게 통과한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;if ( front_clear &amp;ge; D_pass AND cycle_count &amp;ge; N ) &amp;rArr; v &amp;larr; V_dash&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이동체의 정확한 위치&amp;middot;속도를 추정하려면 고품질 센서&amp;middot;필터가 필요하지만, 통과 가능한 시점만 포착하는 문제로 환원하면 저품질 센서로도 충분하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;확률 감쇠 덕분에 한 번의 순간적 감지가 통로를 차단하지 않으며, N 회 관측은 우연한 오감지에 의한 무모한 돌진을 막는 안전장치로 작동한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 주행 알고리즘 - 교차로 판정 + 정지시간 보정 함수&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;측벽 개구는 측면 초음파 센서로 판정하는데, 저성능 센서임을 고려하여, 아래와 같이 노이즈에 버틸 수 있도록, 누적 + 감쇠를 구현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 단발 스파이크가 아닌 일정시간 지속적으로 열려있는지를 확인하도록 증거를 누적하고 시간이 지나면 leak 하는 구조로 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1690&quot; data-origin-height=&quot;442&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdQxko/dJMcai4Ueof/gwOWqrz3fwdHz1KAzIkK50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdQxko/dJMcai4Ueof/gwOWqrz3fwdHz1KAzIkK50/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdQxko/dJMcai4Ueof/gwOWqrz3fwdHz1KAzIkK50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdQxko%2FdJMcai4Ueof%2FgwOWqrz3fwdHz1KAzIkK50%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;661&quot; height=&quot;173&quot; data-origin-width=&quot;1690&quot; data-origin-height=&quot;442&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이로 인해 연속적으로 여러 Tick 이 열려야 임계를 넘으므로, 오판이 억제된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;더 나아가서 한 번 정지 또는 판단한 교차로를 즉시 재 트리거 하지 않는 debounce 효과 또한 부수적으로 얻을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;판정 즉시 회전하면 교차로 중앙이 아닌 진입부에서 돌아 벽에 충돌한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 개구 판정 후 기존 방향으로 일정 시간 더 진행해 중앙에 정렬한 뒤 회전해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 진행 시간을 단일 상수로 하드코딩하면 주행 속도에 따라 실제 진행 거리가 달라져 회전 위치가 흔들린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 직전 정지 직후에는 로봇이 가속 구간에 있어 속도가 낮고, 시간이 지나면 순항 속도에 수렴한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 보상하기 위해, 직전 motor_stop() 이후 경과 시간 &amp;Delta;t 를 현재 속도의 대리 변수로 삼아 진행 시간 t_advance 를 다음과 같이 정의했다(값은 실측 캘리브레이션 결과를 썼음).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1634&quot; data-origin-height=&quot;164&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l4xoa/dJMcage1x8g/QJ9IKfNnuJukmgePKh1eM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l4xoa/dJMcage1x8g/QJ9IKfNnuJukmgePKh1eM0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l4xoa/dJMcage1x8g/QJ9IKfNnuJukmgePKh1eM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl4xoa%2FdJMcage1x8g%2FQJ9IKfNnuJukmgePKh1eM0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1634&quot; height=&quot;164&quot; data-origin-width=&quot;1634&quot; data-origin-height=&quot;164&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 두 수식을 통해서 교차로 판단의 안정성과 반응성을 동시에 확보한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. 오류 보정 - Calibration&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시간을 가장 많이 투자한 영역이다. 이상적 알고리즘이 현실 하드웨어에서 그대로 동작하지 않는 물리 오차를 추적하고 보정하는 부분이 매우 중요했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1) 배터리 의존성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동일한 코드인데도 배터리 충전 상태에 따라 모터 거동이 달라졌다. 충전이 낮으면 회전수가 떨어지고 그 전하량도 좌측 모터와 우측 모터가 달라, 동일한 듀티비에도 한쪽 바퀴가 덜 돌아 직진이 휘고 90 도 회전이 어긋났다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 TICKS_PER_CM, pivot substep 같은 캘리브레이션 상수가 배터리 상태에 따라 달라진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 항상 100% 충전된 상태를 가정한 후 Calibration 했고, 실전에서는 100% 충전 상태를 유지했으며 회전을 인코더 폐루프로 구현해&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자가보정이 어느정도 가능하도록 설정했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2) 바퀴에 엉킨 머리카락&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;492&quot; data-origin-height=&quot;648&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2todh/dJMcajbFjEx/79m0fcl3wWvOMSk5YiH7K1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2todh/dJMcajbFjEx/79m0fcl3wWvOMSk5YiH7K1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2todh/dJMcajbFjEx/79m0fcl3wWvOMSk5YiH7K1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2todh%2FdJMcajbFjEx%2F79m0fcl3wWvOMSk5YiH7K1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;255&quot; height=&quot;336&quot; data-origin-width=&quot;492&quot; data-origin-height=&quot;648&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;90 도 회전 및 직진 Calibration 도중 좌측 우측 인코더 값이 비정상적으로 크게 달랐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드 수준에서 몇 번을 돌려봐도 나아지지 않았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하드웨어를 직접 점검한 결과 우측 바퀴 축에 상대적으로 더 많은 머리카락이 엉켜 회전을 물리적으로 방해하고 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 제거한 뒤 다시 Calibration 하자 좌우 대칭성이 크게 완화되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좌측&amp;nbsp; 사진은 바퀴에 붙어있던 머리카락의 일부로, 좌측보다 우측에 훨씬 더 많은 양의 머리카락이 붙어있음을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3) 전용 Calibration 모드&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CALIB_PIVOT, CALIB_IR, CALIB_ODOM 을 빌드 스위치로 분리해 90 도 회전, IR 센서 탐색 수준, 직진 정도를 반복해서 측정했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 알고리즘 적인 측면에서 보정 전략은 아래와 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Wheel Odometry - RK2(midpoint) 적분으로 EXTI 인코더 ISR 이 quadrature edge 마다 좌&amp;middot;우 휠 카운터를 증감하여 uint16 wrap 을 signed delta 캐스팅으로 보정하여 한 tick 에 |&amp;Delta;| &amp;lt; 2&amp;sup1;⁵ 범위까지 안전하다. 좌&amp;middot;우 휠 변위로부터 본체 변위 &amp;Delta;s 와 회전 &amp;Delta;&amp;theta; 를 계산한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EKF 센서 퓨전 (Predict + Update) 으로 상태벡터는 x = [x, y, &amp;theta;]&lt;span&gt;ᵀ&lt;/span&gt;, 공분산 P &amp;isin; ℝ&amp;sup3;&lt;span&gt;ˣ&lt;/span&gt;&amp;sup3;. X&amp;middot;Y 는 모터 인코더 적분, &amp;theta; 는 센서값 기반으로 보정되는 구조로, 인코더의 누적 드리프트를 초음파 센서가 잡아준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최종 주행 알고리즘 흐름도는 아래 참고&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1338&quot; data-origin-height=&quot;1390&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvOTtM/dJMcabShykU/lBzcAr4vwKMmfmL7I0rKek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvOTtM/dJMcabShykU/lBzcAr4vwKMmfmL7I0rKek/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvOTtM/dJMcabShykU/lBzcAr4vwKMmfmL7I0rKek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvOTtM%2FdJMcabShykU%2FlBzcAr4vwKMmfmL7I0rKek%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;669&quot; height=&quot;695&quot; data-origin-width=&quot;1338&quot; data-origin-height=&quot;1390&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;태스크 구성 및 설계는 FreeRTOS API를 사용함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CS를 전공하고 관련된 프로젝트를 진행하면서 항상 소프트웨어만 다뤄왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대부분의 버그는 코드 내에서 해결할 수 있고 거의 모든 경우에 동일한 입력에는 동일한 출력을 확인할 수 있었음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 하드웨어를 다룰 때는 디버깅 포인트가 늘어난다. 코드를 제대로 작성했더라도 현실세계에서 발생하는 다른 물리적인 변수에서 유발되는 여러 문제점이 있음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 하면서 바퀴에 엉킨 머리카락, 모터성능, 배터리 풀충 등 현실세계에서는 고려할 부분이 더 많다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 디버깅을 코드 수준에서만 하지 말고 하드웨어 수준도 고려해야 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가설을 세우고 검증하는게 중요해보임. 데이터과학이랑 비슷한 느낌..&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Calibration이 진짜 정말 중요했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보고서 원문 참고&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignCenter&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/bPduil/dJMcaay87Ir/XHmxoUHANixTr8YMXg0lU0/%E1%84%8B%E1%85%B5%E1%86%B7%E1%84%87%E1%85%A6%E1%84%83%E1%85%B5%E1%84%83%E1%85%B3%E1%84%8E%E1%85%A2%E1%86%AF%E1%84%85%E1%85%B5%E1%86%AB%E1%84%8C%E1%85%B5_%E1%84%8E%E1%85%AC%E1%84%8C%E1%85%A9%E1%86%BC%E1%84%85%E1%85%B5%E1%84%91%E1%85%A9%E1%84%90%E1%85%B3.pdf?attach=1&amp;amp;knm=tfile.pdf&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;임베디드챌린지_최종리포트.pdf&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;1.92MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  기록</category>
      <author>i3months</author>
      <guid isPermaLink="true">https://13months.tistory.com/848</guid>
      <comments>https://13months.tistory.com/848#entry848comment</comments>
      <pubDate>Wed, 1 Jul 2026 11:53:08 +0900</pubDate>
    </item>
    <item>
      <title>[Data Science] Data Mining</title>
      <link>https://13months.tistory.com/847</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Association Rule Mining&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A를 구매한 사람은 B도 같이 구매하더라~ 같은 패턴을 찾는게 목표&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;itemset : 물건들의 집합&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;support : 아이템셋이 전체 거래 중 몇 비율에서 등장하는지&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQiJ6z/dJMcajbqq0P/6mYXbNPudLKsKTrtOLirMK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQiJ6z/dJMcajbqq0P/6mYXbNPudLKsKTrtOLirMK/img.png&quot; data-origin-width=&quot;570&quot; data-origin-height=&quot;104&quot; data-is-animation=&quot;false&quot; style=&quot;width: 52.8492%; margin-right: 10px;&quot; data-widthpercent=&quot;53.47&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQiJ6z/dJMcajbqq0P/6mYXbNPudLKsKTrtOLirMK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQiJ6z%2FdJMcajbqq0P%2F6mYXbNPudLKsKTrtOLirMK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;570&quot; height=&quot;104&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/05dS3/dJMcajbqq0U/0dOvfWih55aN4aWtbqBwQk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/05dS3/dJMcajbqq0U/0dOvfWih55aN4aWtbqBwQk/img.png&quot; data-origin-width=&quot;620&quot; data-origin-height=&quot;130&quot; data-is-animation=&quot;false&quot; style=&quot;width: 45.988%;&quot; data-widthpercent=&quot;46.53&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/05dS3/dJMcajbqq0U/0dOvfWih55aN4aWtbqBwQk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F05dS3%2FdJMcajbqq0U%2F0dOvfWih55aN4aWtbqBwQk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;620&quot; height=&quot;130&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나이브하게 생각하면 모든 가능한 연관 규칙을 찾고 support값과 confidence값을 계산해도 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 이렇게 하면 규칙 수가 너무 많아져서 느림 -&amp;gt; Apriori 알고리즘 사용&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최소 지지도인 minsup과 최소 신뢰도인 minconf를 지정하고 비교함 (각각 직접 설정하는 파라미터)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;support &amp;gt;= minsup , confidence &amp;gt;= minconf (흔한 패턴만 보겠다 + 믿을 만한 규칙만 보겠다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 itemset이 &lt;b&gt;frequent 하다면 (support &amp;gt;= minsup 이면)&lt;/b&gt; 그 모든 부분집합도 frequent 하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 어떤 itemset이 frequent하지 않으면 그걸 포함하는 큰 itemset도 frequent하지 않다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러면 특정 item이 탈락하는 순간 그 item을 포함하는 itemset을 계산하지 않고 한 번에 쳐낼 수 있다. (prunning)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Apriori&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;크기가 k인 frequent itemset을 Fk라고 부른다. 작은 것 부터 한 층씩 올라감.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Fk가 공집합이면 종료하고, 공집합이 아니면 k+1 후 반복한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;F1을 계산할 때는 물건이 n개면 후보가 n개 뿐이니 각각 support를 세고 frequent한 것만 남긴다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;k가 1보다 클 때는 두 단계로 나눠서 계산함&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 후보 집합 Ck를 만든다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. Ck의 각 원소 support를 세서 frequent 한 것만 Fk에 남긴다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1번 계산 시 모든 k 조합을 후보로 넣으면 계산량이 너무 많으니 이미 구한 Fk-1을 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;{a1, a2 ... ak} 가 frequent 한 k-아이템셋이라면, {a1, a2 ... ak-1} 과 {a1, a2, ... ak-2, ak} 는 Fk-1에 있어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저 두 아이템셋의 prefix는 {a1, a2, ... ak-2} 로 똑같다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 모든 아이템에 순서를 정하고 Fk-1을 prefix로 정렬한 후 prefix가 같은 것 끼리 그룹화한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 그룹 안에서 위의 두 아이템셋의 pair 마다 합친 결과를 Ck에 추가하는 방식을 사용함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 앞부분 똑같고 마지막 항목만 다른 것들을 추가하는 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들면 C3를 만들 때는 3-2=1로 맨 앞 1글자가 같은걸 대상으로 그룹으로 묶는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 그 그룹 안에서 서로 다른 2개를 짝지어서 합치는 것. 후보가 3개면 3C2로 3개가 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;F&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;{{&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span&gt;}} 에서 C3는 abc abd acd 가 나옴&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;그리고 abc abd acd 에서 ab ac bc ad bd cd 가 모두 F2에 있는지 확인하는데, bd는 F2에 없으니 prunning 된다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;prefix가 다르면 어차피 합쳐봐야 의미 없으니 계산하지 않는다. 이러면 후보 수가 확 줄어듦.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 k&amp;gt;=2 인 빈발 아이템셋 I를 하나 고르고 겹치지 않는 두 조각 I1 I2로 나눈다. (I1 U I2 = I)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러면 I1 -&amp;gt; I2 가 후보 규칙으로 정해짐.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;454&quot; data-origin-height=&quot;118&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/C0bdO/dJMcaci7aop/kSGFrH9KZiLDgiKtNCaUUk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/C0bdO/dJMcaci7aop/kSGFrH9KZiLDgiKtNCaUUk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/C0bdO/dJMcaci7aop/kSGFrH9KZiLDgiKtNCaUUk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FC0bdO%2FdJMcaci7aop%2FkSGFrH9KZiLDgiKtNCaUUk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;312&quot; height=&quot;81&quot; data-origin-width=&quot;454&quot; data-origin-height=&quot;118&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 후보 규칙의 confidence를 계산해서 minconf 이상인 것만 보고한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미 분자와 분모는 1단계에서 모두 구해뒀으니 규칙 생성 단계에서는 계산만 하면 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;I가 frequent 하니까 support는 신경쓰지 않아도 되고 confidence만 검사함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 쪽이 통째로 비는 두 경우를 제외하면 I 하나당 2^k - 2개의 후보 규칙이 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;열심히 계산해서 confidence 값이 mincof 이하인걸 잘라내면 됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;666&quot; data-origin-height=&quot;90&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rBb4i/dJMcaci7aKi/RdcPvK6W839XmrxUE5vD9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rBb4i/dJMcaci7aKi/RdcPvK6W839XmrxUE5vD9k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rBb4i/dJMcaci7aKi/RdcPvK6W839XmrxUE5vD9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrBb4i%2FdJMcaci7aKi%2FRdcPvK6W839XmrxUE5vD9k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;533&quot; height=&quot;72&quot; data-origin-width=&quot;666&quot; data-origin-height=&quot;90&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왼쪽이 클수록 confidence가 높다 - 어차피 분자는 같고 더 작은 집합이 더 흔하니까..&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 left-contains 한다고 부름.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 규칙을 Lattice로 두고 왼쪽이 큰 규칙부터 top-down으로 검사한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 규칙이 minconf 에 도달하지 못하면 left-contains하는 모든 아래쪽 규칙도 자동으로 미달이니 confidence를 계산하지 않고 쳐낼 수 있음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;PCA meets SVD&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터가 d개의 특징을 가질 때, 그 특징들이 서로 상관되어 있는 경우 진짜 중요한 방향은 몇 개 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PCA는 데이터가 가장 크게 퍼지는 직교 방향을 찾고 새 좌표축으로 삼는다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러면 상위 n개 축만 남기고 나머지를 버리니 d차원을 k차원으로 줄이면서 정보를 최대한 보존할 수 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래 PCA는 공분산 행렬을 만들고 고유값 분해를 하는 방법이지만 실무에서는 PCA 대신 SVD를 사용한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공분산 + 고유값분해 대신 SVD로 PCA를 수행함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;행렬의 대각합과 고유값의 합은 동일함. 분산은 사라지지 않고 PC로 재분배되기 때문&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1306&quot; data-origin-height=&quot;598&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uxag2/dJMcajoXuIs/C534gCPApCdORsUnizxCk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uxag2/dJMcajoXuIs/C534gCPApCdORsUnizxCk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uxag2/dJMcajoXuIs/C534gCPApCdORsUnizxCk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fuxag2%2FdJMcajoXuIs%2FC534gCPApCdORsUnizxCk1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;598&quot; height=&quot;274&quot; data-origin-width=&quot;1306&quot; data-origin-height=&quot;598&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SVD는 데이터 X를 회전(V^T) -&amp;gt; 축 별로 늘리기(S) -&amp;gt; 회전(U) 세 동작으로 분해해서 다룬다. (행렬 하나를 셋으로 쪼개서 다룸)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;V는 방향, S는 그 방향으로 데이터가 퍼진 정도를 의미함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;n개의 데이터(행), d개의 특징(열), d &amp;lt; n 가정&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;S는 대각행렬&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;U * U^T = I&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;V * V^T = I&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PC 값은 그 자체가 분산이니 제곱하지 않아도 됨. 특이값을 줬을 때만 제곱해서 쓴다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복원이 정확하려면 버리는 방향의 분산이 0이여야 함. k=n으로 줄일때 버려지는게 0이 아니면 부정확하다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;808&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjOffX/dJMcag6UUWJ/6lWuFS1Txm3rvJvdpFMFuk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjOffX/dJMcag6UUWJ/6lWuFS1Txm3rvJvdpFMFuk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjOffX/dJMcag6UUWJ/6lWuFS1Txm3rvJvdpFMFuk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjOffX%2FdJMcag6UUWJ%2F6lWuFS1Txm3rvJvdpFMFuk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;505&quot; height=&quot;250&quot; data-origin-width=&quot;808&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 특징이 있는 데이터를 점으로 찍으면 한쪽으로 길쭉하게 펴진다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 많이 퍼진 한 방향이 PC1이고, 수직이면서 그 다음으로 퍼진 방향은 PC2이다. PCA는 데이터에 맞춰 좌표축을 다시 그어준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터는 PC1 방향으로 길고 PC2 방향으로는 거의 펴지지 않았다. 그러니 각 점을 PC1 위에서 어디쯤인지로 표현해도 됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 d차원을 k차원으로 줄이는 테크닉이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, V의 열은 PC 방향 그 자체이고 S의 특이값은 각 화살표 방향으로 데이터가 퍼진 크기를 의미한다 - PC1은 크고 PC2는 작다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특이값이 큰 것 부터 정렬되어 있으니 앞에서 k개만 챙기면 좋은거만 가져가는 셈.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 점이 PC1 위에서 어디쯤 있는지 알기 위해서는 방향선에 수직으로 점의 그림자를 떨어뜨리면 된다. (투영)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내적으로 계산하면 됨.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PCA는 데이터가 가장 퍼진 방향을 찾고 각 점을 그 방향에 투영해서 새 좌표를 얻고 그 방향 퍼짐의 크기를 계산하는 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PCA 공식 : Z = XV 데이터를 PC 방향에 투영해서 줄인 결과&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Z = XV = (USV^T)V = US(V^TV) = US&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PC의 분산과 방향은 따로 구해야함&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;V의 열은 X^TX의 고유벡터이고 U의 열은 XX^T의 고유벡터이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Clustering&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정답 라벨 없이 비슷한 점끼리 묶는 테크닉으로 같은 그룹은 가깝게 다른 그룹은 멀게 매핑한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클러스터 개수 k를 미리 정해두면 n개의 점을 k개의 클러스터로 나누되 이 값을 최소화함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;374&quot; data-origin-height=&quot;134&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oWQc4/dJMcaiRcvd5/6RKXV30i4SSjGco5zClDl1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oWQc4/dJMcaiRcvd5/6RKXV30i4SSjGco5zClDl1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oWQc4/dJMcaiRcvd5/6RKXV30i4SSjGco5zClDl1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoWQc4%2FdJMcaiRcvd5%2F6RKXV30i4SSjGco5zClDl1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;279&quot; height=&quot;100&quot; data-origin-width=&quot;374&quot; data-origin-height=&quot;134&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최적해는 가능한 모든 경우를 다 따져봐야하는데 이러면 시간이 너무 오래 걸리니 휴리스틱인 &lt;b&gt;K-Means&lt;/b&gt;를 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. k를 정하고 중심 k개를 아무렇게나 찍는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 각 점을 가장 가까운 중심의 색으로 칠하고, 각 색의 중심을 점들의 평균 위치로 옮긴다. (centroid)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 어떤 점도 색이 바뀌지않으면 끝&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;global optimum이 아니라 local optimum에 수렴함. 처음 중심을 어디에 찍는지에 따라 결과가 달라진다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니까, 처음부터 모든 점이 특정 클러스터에 속하는거고 클러스터의 중심을 바꿔가면서 조작하는 것&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Hierarchical Agglomerative&lt;/b&gt;는 기존 K-Means와 정반대로 아래에서 위로 쌓는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 모든 점이 각자 클러스터고, 그 중 가장 가까운 두 클러스터를 합치는걸 가장 큰 클러스터가 남을 때 까지 반복한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Single Linkage : 두 클러스터에서 가장 가까운 점 한 쌍의 거리&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Complete Linkage : 두 클러스터에서 가장 먼 점 한 쌍의 거리&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Average Linkage : 모든 점 쌍 거리의 평균&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연결 기준을 정해야 두 클러스터 사이의 거리를 측정할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘의 결과는 하나의 큰 클러스터가 아니라 합쳐진 전체 과정이다. (덴드로그램)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 덴드로그램 안에는 모든 단계의 클러스터링이 들어있으니 나무를 끝까지 키운 뒤 원하는 높이에서 자르면 클러스터의 답이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1068&quot; data-origin-height=&quot;432&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ctBloa/dJMcab5COUm/TS8TfsNVFzxRHuIHOFX7gK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ctBloa/dJMcab5COUm/TS8TfsNVFzxRHuIHOFX7gK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ctBloa/dJMcab5COUm/TS8TfsNVFzxRHuIHOFX7gK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FctBloa%2FdJMcab5COUm%2FTS8TfsNVFzxRHuIHOFX7gK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;546&quot; height=&quot;221&quot; data-origin-width=&quot;1068&quot; data-origin-height=&quot;432&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클러스터링을 돌렸는데 이게 잘 된건지를 측정하려면 Silhouette Score를 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;점 X 하나에 대해서 두 거리를 측정함. (내 무리랑은 가깝고 남의 무리랑은 멀어야 함)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A. X에서 자기 클러스터 안의 다른 점들까지의 평균 거리 -&amp;gt; 작을수록 좋다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;B. X에서 가장 가까운 다른 클러스터의 점들까지의 평균 거리 -&amp;gt; 클수록 좋다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;288&quot; data-origin-height=&quot;130&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ExHi2/dJMcaiwU4a3/txTdG1itztdh48W3TihYKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ExHi2/dJMcaiwU4a3/txTdG1itztdh48W3TihYKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ExHi2/dJMcaiwU4a3/txTdG1itztdh48W3TihYKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FExHi2%2FdJMcaiwU4a3%2FtxTdG1itztdh48W3TihYKK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;224&quot; height=&quot;101&quot; data-origin-width=&quot;288&quot; data-origin-height=&quot;130&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A가 작고 B는 크면 S가 1에 가깝다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A랑 B가 유사하면 S가 0에 가깝고 경계에 애매하게 걸친 점이 됨&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A가 더 크면 S가 음수가 되고 잘못 묶였다고 볼 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 점의 S값을 평균 내면 클러스터링 점수가 된다 - k를 설정할 때 사용함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;평균 실루엣이 가장 높은 k를 선택한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;DBSCAN&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클러스터를 점이 모인 지역으로 보고, 떨어진 부분은 노이즈로 처리한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;잡음점 주변은 sparse하고 같은 클러스터의 두 점은 dense한 지역만 밟아서 오갈 수 있어야 함&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;K-Means처럼 덩어리만 잘 찾는게 아니라 구불구불한 모양도 밀도만 이어지면 하나의 클러스터로 설정할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 k를 미리 정하지 않아도 됨.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;674&quot; data-origin-height=&quot;428&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xoIv2/dJMcah5TfQR/bDlqopvzIliQubUk68Ucdk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xoIv2/dJMcah5TfQR/bDlqopvzIliQubUk68Ucdk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xoIv2/dJMcah5TfQR/bDlqopvzIliQubUk68Ucdk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxoIv2%2FdJMcah5TfQR%2FbDlqopvzIliQubUk68Ucdk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;483&quot; height=&quot;307&quot; data-origin-width=&quot;674&quot; data-origin-height=&quot;428&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엡실론 값은 거리 문턱값이고 MinPts는 정수 상수를 의미함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;점 p를 중심으로 반경이 엡실론인 공은 p의 이웃 영역이 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 구역 안에 점이 MinPts개 이상 들어있는 점은 핵심점으로 DBSCAN의 가장 중요한 부분이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초록색 점 p는 핵심점이고 보라색 점은 핵심이 될 수는 없으니 경계점이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회색 점은 외딴 곳에 있으니 노이즈.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클러스터는 두 가지 단계를 통해 만들어짐&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 핵심점끼리 묶기 - p를 구간 안의 점들과 선으로 연결하고 이어진 덩어리 하나하나를 클러스터로 본다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 경계점 배정 - 비핵심점 p는 모든 핵심점의 클러스터에 추가되니 여러 클러스터에 동시에 속할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음 중심을 어디에 찍는지에 따라서 결과가 달라지는 K-Means와 다르게 결과가 유일하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Single Linkage 덴드로그램이 있을 때 minPts가 1이면 모든 점이 핵심점이니 덴드로그램을 엡실론에서 자른것과 같음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 클러스터 안에 핵심점이 여러개 있을 수 있고, 경계점은 이웃이 부족해 핵심점은 아니지만 어떤 핵심점의 원 안에 들어가는 경우를 의미한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Neural Network&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력 데이터를 받아서 쓸모 있는 출력으로 바꾸는 기계이고, 그 변환 규칙이 학습 가능한 파라미터로 정해진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Encoder&lt;/b&gt; - 큰 입력 데이터를 하나의 대표 벡터로 압축한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Head&lt;/b&gt; - 대표 벡터로 실제로 풀고 싶은 문제를 풀어서 출력을 만들어낸다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2048&quot; data-origin-height=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/w2Sbi/dJMcaf1fdZW/K64Gl5hZhQ6IQv6eXhaBqK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/w2Sbi/dJMcaf1fdZW/K64Gl5hZhQ6IQv6eXhaBqK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/w2Sbi/dJMcaf1fdZW/K64Gl5hZhQ6IQv6eXhaBqK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fw2Sbi%2FdJMcaf1fdZW%2FK64Gl5hZhQ6IQv6eXhaBqK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;642&quot; height=&quot;188&quot; data-origin-width=&quot;2048&quot; data-origin-height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;818&quot; data-origin-height=&quot;468&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blTVxu/dJMcaffVNCk/hnUfAxsaCwrHDtqGwalek1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blTVxu/dJMcaffVNCk/hnUfAxsaCwrHDtqGwalek1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blTVxu/dJMcaffVNCk/hnUfAxsaCwrHDtqGwalek1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblTVxu%2FdJMcaffVNCk%2FhnUfAxsaCwrHDtqGwalek1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;463&quot; height=&quot;265&quot; data-origin-width=&quot;818&quot; data-origin-height=&quot;468&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;290&quot; data-origin-height=&quot;82&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7LHbp/dJMcaijnrWf/niTqk65gRuKDccRrOkkBy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7LHbp/dJMcaijnrWf/niTqk65gRuKDccRrOkkBy0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7LHbp/dJMcaijnrWf/niTqk65gRuKDccRrOkkBy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7LHbp%2FdJMcaijnrWf%2FniTqk65gRuKDccRrOkkBy0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;216&quot; height=&quot;61&quot; data-origin-width=&quot;290&quot; data-origin-height=&quot;82&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 입력 뉴런이 모든 출력 뉴런과 연결되니 fully-connected 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출력 뉴런 하나하나는 W의 한 행과 x의 내적으로 표현되고, 그림의 선 하나가 가중치 하나를 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;활성화 함수로 가중합 결과를 비선형으로 구부려주고 bias로 결과를 살짝 밀어줌.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;활성화 함수가 없으면 그냥 선형 변환일 뿐이니 층을 아무리 여러 개 쌓아도 선형 변환으로 합쳐져 버린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 할성화 함수를 통해 매 층마다 비선형하게 구부려줘야 층을 쌓는 의미가 생기고, Neural Network가 거의 모든 함수를 흉내낼 수 있다. (ex. ReLU)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Convolution Neural Network&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지는 2D 격자라서 한 줄로 펴서 MLP에 넣을 수도 있지만 Overfit 위험이 크고 가중치도 너무 많아서 적합하지 않음. 그리고 주변 픽셀도 못본다. Locality 편향이 있어야 하는데.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 Convolution을 사용한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작은 창 하나를 이미지 위에 두고 그 내부 값들을 Kernel과 원소별로 곱해서 더한다 (내적)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 결과로 출력 뉴런이 하나 나오고, 이걸 Feature Map이라고 부른다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심은 같은 Kernel을 모든 위치에 재사용 - 이러면 파라미터도 줄고 Locality 편향이 생긴다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Kernel을 슬라이딩 윈도우 방식으로 다루니 Feature Map은 입력보다 작아진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;454&quot; data-origin-height=&quot;138&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7VSjL/dJMcaftpsUf/33pRM8fUnsGfeuaNLN4hsK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7VSjL/dJMcaftpsUf/33pRM8fUnsGfeuaNLN4hsK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7VSjL/dJMcaftpsUf/33pRM8fUnsGfeuaNLN4hsK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7VSjL%2FdJMcaftpsUf%2F33pRM8fUnsGfeuaNLN4hsK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;359&quot; height=&quot;109&quot; data-origin-width=&quot;454&quot; data-origin-height=&quot;138&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Stride&lt;/b&gt; - 창이 한 번에 몇 칸씩 건너뛸지를 정한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Padding&lt;/b&gt; - 연산 시 가장자리가 깎여 크기가 줄어드는데, 입력 테두리에 0을 둘러서 크기를 키워놓고 연산하면 입력과 출력이 같은 크기로 유지된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Pooling&lt;/b&gt; - 가중치 없이 창 안에 있는 값을 최댓값 또는 평균값을 사용해서 계산한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Convolution 뉴런은 Fully Connected 대신 Locality Window만 보니 가중치가 적으니 과적합이 방지된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가중치를 공유해 같은 Kernel을 모든 위치에 재사용할 수 있어 공간 상관관계를 포착할 수 있음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;채널은 같은 크기의 2D 격자 한 장으로, Tensor는 이런 격자를 여러 장 쌓아올린걸 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지는 RGB로 채널이 3개 -&amp;gt; Convolution을 지나면 채널은 색이 아니라 Feature Map이 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Filter 하나가 Feature Map 한 장을 만들어낸다. 세로 모서리.. 곡선.. 무늬..&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;채널 수가 늘어나는건 Filter를 많이 써서 Feature Map을 여러 장 뽑는다는 것.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Convolution의 Kernel은 공간만 k * k 이고 항상 입력 채널 전부를 한 번에 본다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1032&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JGdB3/dJMcadI24UB/ekfKRhEJ5IhDbsH76oFk31/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JGdB3/dJMcadI24UB/ekfKRhEJ5IhDbsH76oFk31/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JGdB3/dJMcadI24UB/ekfKRhEJ5IhDbsH76oFk31/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJGdB3%2FdJMcadI24UB%2FekfKRhEJ5IhDbsH76oFk31%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;545&quot; height=&quot;211&quot; data-origin-width=&quot;1032&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 1*1 Kernel를 사용하면 픽셀 하나만 보되 그 칸의 모든 채널 값을 다 섞어버린다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실상 1*1 Kernel은 1*1*in Kernel과 같다고 보면 됨. 출력 채널 수는 사용하는 Kernel 개수와 같다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파라미터 개수는 k*k*in*out + out(bias)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;in은 입력 채널 out은 출력 채널&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3*3 커널 2개를 사용하면 결국 5*5 시야를 가지는데, 5*5 커널 한개를 사용할 때 보다 파라미터 수가 적다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 CNN은 큰 커널 대신 작은 커널을 여러 번 쌓는 방식을 사용함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Text Mining&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴퓨터가 문서를 다루려면 문서를 벡터로 변환해야 한다. (Vector Space Model)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각각의 concept을 차원으로 본다. concept이 k개면 k차원 공간&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 문서는 두 공간의 벡터이고 문서 벡터 사이의 거리는 문서의 관계도를 의미함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VSM은 concept을 어떻게 고르는지를 정해주지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의미가 서로 겹치지 않는 Orthogonal 상태이고 가중치를 알아서 매길 수 있어야 한다. (Bag-of-Words)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Bag-of-Words&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단어 하나하나를 차원으로 써서 문서를 벡터로 바꾸고 벡터 거리로 비교한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 문서에 나온 단어를 모아서 목록을 만든다. 이 단어 하나하나가 차원이 됨.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 문서마다 벡터를 채워준다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;text mining is mining 에서는&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[1,2,0,1] 각각 text mining apple is&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런식으로 단어의 등장 횟수만&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RAG가 하는 일과 정확히 일치함. 질문과 문서를 벡터로 바꿔서 가장 가까운 문서 벡터를 찾아온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 BoW 대신 임베딩을 사용해 의미까지 담은 벡터를 만드는 것.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 원문을 그대로 BoW에 넣으면 지저분하니 벡터로 만들기 전에 다듬는 과정을 거친다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;토큰화 -&amp;gt; 정규화 + 스테밍(mining을 mine으로. Vocabulary Gap을 커버함) -&amp;gt; 불용어 제거 -&amp;gt; BoW 벡터 완성&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단어 빈도는 순위에 반비례한다. 그러니 단어를 빈도순으로 줄세우면 this that of a 같은 불용어가 대부분이라 일단 버림&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 sesquipedalianism 같은 희귀어는 거의 안나오니까 이것도 버림&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 양 끝을 쳐내는걸 Zipf 법칙이라고 부른다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;TF-IDF&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BoW는 단어를 그냥 카운트하는데, 모든 단어가 똑같이 중요하지는 않음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단어가 문서를 잘 대표하려면 이 문서에는 자주 나오고 전체 문서 모음에서는 드물어야한다. TF-IDF는 이걸 정확하게 계산할 수 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Term Frequency&lt;/b&gt;는 단어 t가 문서 d에 몇 번 나오는지를 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;많이 나오면 그 문서에 중요한거고, 근데 그냥 횟수만 쓰면 긴 문서가 무조건 유리하니 완화해서 사용함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sub-linear : wf = 1 + log(count)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최대 TF 스케일링 : 문서 내 최대 단어 횟수로 나눠서 0~1로 표준화&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Inverse Document Frequency&lt;/b&gt;는 단어가 전체에서 얼마나 Rare한지를 판단한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;df(t) 는 그 단어를 포함하는 문서 개수로, 적은 문서에 나올수록 더 변별력이 강해짐.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;df는 단어에 대해서 계산하는 것&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;642&quot; data-origin-height=&quot;128&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cOijzq/dJMcaglyaqg/kgszshSG4R8wJowxbxm4Jk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cOijzq/dJMcaglyaqg/kgszshSG4R8wJowxbxm4Jk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cOijzq/dJMcaglyaqg/kgszshSG4R8wJowxbxm4Jk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcOijzq%2FdJMcaglyaqg%2FkgszshSG4R8wJowxbxm4Jk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;386&quot; height=&quot;77&quot; data-origin-width=&quot;642&quot; data-origin-height=&quot;128&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;428&quot; data-origin-height=&quot;88&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4tXds/dJMcadI3PDc/2j9V3wLIbvK32THBz7MDi0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4tXds/dJMcadI3PDc/2j9V3wLIbvK32THBz7MDi0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4tXds/dJMcadI3PDc/2j9V3wLIbvK32THBz7MDi0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4tXds%2FdJMcadI3PDc%2F2j9V3wLIbvK32THBz7MDi0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;258&quot; height=&quot;53&quot; data-origin-width=&quot;428&quot; data-origin-height=&quot;88&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문서에는 자주 등장하고 전체에서는 드물게 나타나는 요소에 대해 높은 점수를 부여한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;+1을 붙이는 이유는 흔한 단어도 최소 가중치 1은 남도록 하기 위해서임&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Skip-gram&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BoW와 TF-IDF 벡터는 어휘 크기만큼 길고 의미를 담을 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 의미가 비슷한 단어는 벡터도 가깝게 표현할 수 있어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비슷한 문맥에 등장하는 단어는 의미가 비슷하다. 그러니 주변 단어를 잘 골라내도록 벡터를 학습시킨다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1002&quot; data-origin-height=&quot;354&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/whvjP/dJMcajoYd3L/zfPAMkGKaKYxQkaekGIOn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/whvjP/dJMcajoYd3L/zfPAMkGKaKYxQkaekGIOn0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/whvjP/dJMcajoYd3L/zfPAMkGKaKYxQkaekGIOn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwhvjP%2FdJMcajoYd3L%2FzfPAMkGKaKYxQkaekGIOn0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;566&quot; height=&quot;200&quot; data-origin-width=&quot;1002&quot; data-origin-height=&quot;354&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;텍스트 위로 윈도우를 놓고, 가운데가 중심 단어 c이고 양 옆 +- m개가 주변 단어로 간주한다. (총 2m개)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중심 단어 c로 주변 단어 o를 맞출 확률을 벡터 내적 + softmax로 정의함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;478&quot; data-origin-height=&quot;122&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cHq96Z/dJMb99NsWQd/koi8kxqyCIsmM9XuhGkWHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cHq96Z/dJMb99NsWQd/koi8kxqyCIsmM9XuhGkWHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cHq96Z/dJMb99NsWQd/koi8kxqyCIsmM9XuhGkWHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcHq96Z%2FdJMb99NsWQd%2Fkoi8kxqyCIsmM9XuhGkWHk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;310&quot; height=&quot;79&quot; data-origin-width=&quot;478&quot; data-origin-height=&quot;122&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 벡터가 비슷한 방향일수록 이웃일 확률이 높고, 단어마다 벡터를 두 개 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주변 단어들의 확률을 최대화하고 Negative Log-Likelihood를 최소화한다. 이를 통해 SGD로 학습함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;학습이 끝나면 비슷한 문맥에 쓰이는 단어는 벡터가 가까워지고 의미 연산도 가능해진다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 의미 벡터는 NLP와 RAG의 기반이 됨.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비슷한 의미의 단어는 비슷한 문맥에 등장하니까 같은 이웃을 잘 맞히려면 벡터가 서로 비슷해진다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 Skip-gram은 고전 임베딩이라 가볍고 로컬에서도 다룰 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요즘은 거대 트랜스포머 모델이 문맥까지 반영해서 같은 단어도 문장에 따라 벡터가 다르고 의미 보존이 훨씬 잘 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- log P(dog | cat) 을 줄이려면 P(dog | cat)을 키워야 하고, 내적값을 키워야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SGD가 서로 닮은 방향으로 밀어서 내적이 커짐.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Vcat (1,0) Udog (0,1) 이라고 하면&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서로 가까워지도록 살짝씩 밀어주는 역할&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Graph Mining&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래프에서 누가 중요한 노드인지 따지는 Centrality와 웹페이지 중요도인 PageRank와 Random Walk로 구분된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Centrality&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;노드와 간산으로 구성되는 그래프에서 어떤 노드가 가장 중요한지를 점수로 매기기 위해 Centrality를 측정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;836&quot; data-origin-height=&quot;466&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GQ8TP/dJMcaaMp7en/RazfWANbD4xX6udRwwFhfK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GQ8TP/dJMcaaMp7en/RazfWANbD4xX6udRwwFhfK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GQ8TP/dJMcaaMp7en/RazfWANbD4xX6udRwwFhfK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGQ8TP%2FdJMcaaMp7en%2FRazfWANbD4xX6udRwwFhfK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;380&quot; height=&quot;212&quot; data-origin-width=&quot;836&quot; data-origin-height=&quot;466&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네 가지를 확인한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Degree 측면에서는 연결된 간선이 많으면 중심이 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Eccentricity 측면에서는 노드에서 가장 먼 노드까지의 거리를 측정하고 가장 먼 곳이 가까울수록 중심이 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Closeness 측면에서는 다른 모든 노드까지 최단거리 합의 역수를 측정하고 합이 작을수록 중심이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Betweenness 측면에서는 노드를 지나가는 최단경로의 개수를 측정하고 경로가 많을수록 중심이 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;PageRank &amp;amp; Random Walk&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹을 방향 그래프로 본다. 페이지는 노드가 되고 하이퍼링크는 방향 있는 간선이 됨.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나가는 링크가 없는 페이지는 셀프루프를 붙인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 확률 a : 페이지 u의 나가는 링크 중 하나를 무작위로 따라가서 이동함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 확률 1-a : 아무 페이지로 순간이동함&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;순간이동이 없으면 막다른 곳이나 링크 루프에 갇힐 수 있으니 모든 페이지가 도달 가능하도록 하기 위해 필요하다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 페이지의 PageRank는 사용자가 오랜 시간 뒤에도 그 페이지에 있을 확률을 의미한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중요한 페이지들이 많이 링크하는 페이지일수록 자주 방문되고 PageRank가 높아진다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 수학으로 계산하는 방법이 따로 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 확률 벡터로 상태를 표현해야함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;페이지가 n개일 때 지금 각 페이지에 있을 확률을 벡터 P로 기록한다. 이게 곧 확률벡터가 됨. (전부 더하면 1)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이동 규칙을 행렬 M에 담는다. (Stochastic Matrix) - i에 있을 때 j로 갈 확률&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전부 1인 벡터를 M의 왼쪽에 곱하면&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 분포가 P(t) 이면 다음 분포는 P(t+1) = M * P(t) 로 정리됨.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;M을 한번 곱할 때 마다 한 번 더 걸은 분포가 나온다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계속 걷다 보면 분포가 더 이상 변하지 않는 지점에 도달함 (P = MP)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서의 P를 정상분포라고 하고, 이게 PageRank벡터.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, P는 M의 고유값 1에 대응하는 고유벡터가 됨. (PCA에서 다룬 내용과 같다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1122&quot; data-origin-height=&quot;248&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o0Rqt/dJMcahLyjQx/KO3e8EPKBTniKddLTfl211/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o0Rqt/dJMcahLyjQx/KO3e8EPKBTniKddLTfl211/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o0Rqt/dJMcahLyjQx/KO3e8EPKBTniKddLTfl211/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo0Rqt%2FdJMcahLyjQx%2FKO3e8EPKBTniKddLTfl211%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;597&quot; height=&quot;132&quot; data-origin-width=&quot;1122&quot; data-origin-height=&quot;248&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;행렬과 그 행렬의 전치행렬은 고유값이 똑같다. 그러니 P = MP 인 정상분포 P가 항상 존재하는게 보장됨.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 전부 1인 벡터를 왼쪽에 곱해주면 열의 합이 1이라서 그대로 나온다는거임&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Recommender System&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자가 아직 평가하지 않은 아이템에 몇 점을 매길지 예측하고, 높을 것 같은걸 추천한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 &lt;b&gt;Collaborative&lt;/b&gt; &lt;b&gt;Filtering&lt;/b&gt;이라고 부른다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;User-User는 나와 취향이 비슷한 사용자를 찾고 걔내들의 평점으로 내 평점을 예측&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Item-Item은 내가 평가한 아이템 중 목표 아이템과 비슷한 아이템을 찾고 내가 준 평점의 가중편균으로 예측&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;358&quot; data-origin-height=&quot;144&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzeLxE/dJMcaftqiS8/ky1RP72s8JJRLBTJIOgCNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzeLxE/dJMcaftqiS8/ky1RP72s8JJRLBTJIOgCNK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzeLxE/dJMcaftqiS8/ky1RP72s8JJRLBTJIOgCNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzeLxE%2FdJMcaftqiS8%2Fky1RP72s8JJRLBTJIOgCNK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;266&quot; height=&quot;107&quot; data-origin-width=&quot;358&quot; data-origin-height=&quot;144&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웬만하면 Item-Item이 User-User보다 낫다. 아이템은 사람보다 단순하니까..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Collaborative Filtering은 아이템 종류를 가리지 않고 평점만 있어도 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 매칭할 사용자가 충분히 쌓여야 하고, 평점표가 비어있어 같은 아이템을 평가한 사용자가 찾기 어려우면 사용하기 힘들다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무도 평가하지 않은 새 아이템은 추천하기 어렵고, 독특한 취향을 반영하는것도 어려우며 극단화를 유도할 수 있음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Netflix의 SVD는 희소성을 정면 돌파한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;평점 행렬 R을 두 개의 얇은 행렬 곱으로 근사때려버림.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;222&quot; data-origin-height=&quot;92&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CH6ww/dJMcagMHpuY/VWZmI2X8AA6WGrTahffxbk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CH6ww/dJMcagMHpuY/VWZmI2X8AA6WGrTahffxbk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CH6ww/dJMcagMHpuY/VWZmI2X8AA6WGrTahffxbk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCH6ww%2FdJMcagMHpuY%2FVWZmI2X8AA6WGrTahffxbk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;164&quot; height=&quot;68&quot; data-origin-width=&quot;222&quot; data-origin-height=&quot;92&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Q는 아이템 i의 요인 벡터 (그 영화의 액션성, 로맨스성, 예술성 등을 얼마나 가지는지)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;P는 사용자 x의 요인 벡터 (그 사람이 액션을 얼마나 좋아하는지)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자 x의 아이템 i 평점은 두 요인 벡터의 내적으로 구할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;406&quot; data-origin-height=&quot;124&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/phsx3/dJMcagy5OEb/B7C3TBgHkDakiRmmzZ9kdK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/phsx3/dJMcagy5OEb/B7C3TBgHkDakiRmmzZ9kdK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/phsx3/dJMcagy5OEb/B7C3TBgHkDakiRmmzZ9kdK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fphsx3%2FdJMcagy5OEb%2FB7C3TBgHkDakiRmmzZ9kdK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;321&quot; height=&quot;98&quot; data-origin-width=&quot;406&quot; data-origin-height=&quot;124&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빈칸이 많아도 평점만 잘 맞추도록 Q와 P를 학습하면 그 내적값으로 빈칸을 예측할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Lattice는 말 그대로 격자를 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;834&quot; data-origin-height=&quot;642&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bOUtVH/dJMcaayVZDH/0ucwmwdkh8TUu84pEoTpU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bOUtVH/dJMcaayVZDH/0ucwmwdkh8TUu84pEoTpU1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bOUtVH/dJMcaayVZDH/0ucwmwdkh8TUu84pEoTpU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbOUtVH%2FdJMcaayVZDH%2F0ucwmwdkh8TUu84pEoTpU1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;318&quot; height=&quot;245&quot; data-origin-width=&quot;834&quot; data-origin-height=&quot;642&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 아이템셋과 포함관계를 한눈에 그린 그림으로, 어떤 아이템셋이 infrequent하면 그 위쪽도 전부 infrequent함을 보여주기 위해 등장함. 그냥 Apriori 시각화를 위해 사용되는 개념이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;80&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4HSNj/dJMcaiRd6BP/7X8ojHoPQh6nQ7nBGnJamk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4HSNj/dJMcaiRd6BP/7X8ojHoPQh6nQ7nBGnJamk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4HSNj/dJMcaiRd6BP/7X8ojHoPQh6nQ7nBGnJamk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4HSNj%2FdJMcaiRd6BP%2F7X8ojHoPQh6nQ7nBGnJamk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;650&quot; height=&quot;80&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;80&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;rank는 0이 아닌 특이값의 개수로, 데이터의 독립적인 방향이 몇 개인지를 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;점들이 한 직선 위에만 있으면 방향이 1개라서 rank도 1이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Orthogonal은 수직을 의미하고 기하적으로는 두 벡터가 수직이라는 뜻이다. (내적값 0)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PCA에서 PC들이 직교하면 서로 수직이라서 정보가 겹치지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의미가 서로 겹치지 않아서 독립적이라는 뜻. 독립적이면서 겹치지 않는 방향을 의미함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BoW는 전처리 후 어휘 만들고 단어 횟수만 세서 벡터로 만든다. 이게 너무 간단하니 TF-IDF와 임베딩이 나온 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미 frequent한 I 에서 I1 -&amp;gt; I2를 만드는거니까 규칙 단계에서는 support를 신경쓰지 않고 confidence만 검사하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;X = U S V^T&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SVD가 데이터 X를 셋으로 쪼갠다 (이게 시작점)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;V의 열은 PC의 방향이고, S의 특이값은 그 방향으로 퍼지는 정도&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Z = XV (이건 PCA 공식)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Z = XV = U S V^T V = US&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;X = Z V^T&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;minPts가 1이면 모든 점이 핵심점이 된다. 이러면 DBSCAN은 거리 엡실론 이하로 이어지는 점을 모두 묶음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건 그냥 Single Linkage에서 높이 엡실론으로 덴드로그램 자른거랑 같다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문서가 길면 그냥 TF가 높아지니까 Scaling이 필요함&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sub-linear는 1 + log(횟수). 로그로 눌러버린다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최대 TF Scaling은 그 문서에서 가장 많이 나온 단어로 나눠서 0~1로 맞추고 긴 문서 편향을 제거함&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TF만 쓰면 모든 문서에 흔한 단어가 점수를 독식하니 IDF를 사용함 -&amp;gt; TF * IDF 로 최종 계산&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;df는 그 단어가 몇 개의 문서에 등장하는지를 카운트함&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ttf는 그 단어가 전체에서 몇 번 나온지를 카운트함&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 ttf 대신 df 쓴다. 단어가 한 문서에서만 100번 나오면 ttf는 크지만 df는 1이기 때문 -&amp;gt; 특정 문서 전용단어임을 캐치&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;희귀할수록 IDF가 올라감&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Computer Science/Data Science</category>
      <author>i3months</author>
      <guid isPermaLink="true">https://13months.tistory.com/847</guid>
      <comments>https://13months.tistory.com/847#entry847comment</comments>
      <pubDate>Thu, 18 Jun 2026 14:02:28 +0900</pubDate>
    </item>
  </channel>
</rss>