<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>안승규의 블로그 (Stay hungry, stay foolish)</title>
    <link>https://ahnseungkyu.com/</link>
    <description>Seungkyu Ahn's Blog, Kubernetes, Container, CNCF, OpenStack, Linux, Programming and so on</description>
    <language>ko</language>
    <pubDate>Sat, 4 Apr 2026 11:51:07 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>seungkyua@gmail.com</managingEditor>
    <image>
      <title>안승규의 블로그 (Stay hungry, stay foolish)</title>
      <url>https://t1.daumcdn.net/cfile/tistory/277A994B5306DAC527</url>
      <link>https://ahnseungkyu.com</link>
    </image>
    <item>
      <title>Cloud Native Community Day Korea 2024 Recap</title>
      <link>https://ahnseungkyu.com/329</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;2024년 행사 Recap&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;kcd-recap-2024.png&quot; data-origin-width=&quot;3360&quot; data-origin-height=&quot;2240&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mR8ED/btsNdQ3l9Ad/Qk7rcXxuLug0NhRxM32brk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mR8ED/btsNdQ3l9Ad/Qk7rcXxuLug0NhRxM32brk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mR8ED/btsNdQ3l9Ad/Qk7rcXxuLug0NhRxM32brk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmR8ED%2FbtsNdQ3l9Ad%2FQk7rcXxuLug0NhRxM32brk%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;3360&quot; height=&quot;2240&quot; data-filename=&quot;kcd-recap-2024.png&quot; data-origin-width=&quot;3360&quot; data-origin-height=&quot;2240&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Kubernetes</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/329</guid>
      <comments>https://ahnseungkyu.com/329#entry329comment</comments>
      <pubDate>Wed, 9 Apr 2025 09:51:42 +0900</pubDate>
    </item>
    <item>
      <title>Kubernetes Korea Group Discord Channel</title>
      <link>https://ahnseungkyu.com/328</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;쿠버네티스 코리아 디스코드 채널 주소 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://discord.gg/AmqYyGDQ3U&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://discord.gg/AmqYyGDQ3U&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1727305034657&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;kubernetes-korea Discord 서버에 가입하세요!&quot; data-og-description=&quot;Discord에서 kubernetes-korea 커뮤니티를 확인하세요. 395명과 어울리며 무료 음성 및 텍스트 채팅을 즐기세요.&quot; data-og-host=&quot;discord.com&quot; data-og-source-url=&quot;https://discord.gg/AmqYyGDQ3U&quot; data-og-url=&quot;https://discord.com/invite/AmqYyGDQ3U&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://discord.gg/AmqYyGDQ3U&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://discord.gg/AmqYyGDQ3U&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;kubernetes-korea Discord 서버에 가입하세요!&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Discord에서 kubernetes-korea 커뮤니티를 확인하세요. 395명과 어울리며 무료 음성 및 텍스트 채팅을 즐기세요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;discord.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Kubernetes</category>
      <category>Discord</category>
      <category>kuberneteskoreagroup</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/328</guid>
      <comments>https://ahnseungkyu.com/328#entry328comment</comments>
      <pubDate>Thu, 26 Sep 2024 08:02:24 +0900</pubDate>
    </item>
    <item>
      <title>Linux single node 에서 kubeadm 으로 kubernetes 설치 하기</title>
      <link>https://ahnseungkyu.com/327</link>
      <description>&lt;h2 data-en-clipboard=&quot;true&quot; data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size26&quot;&gt;1. sudo 사용자 추가, 보안 s/w 내리기, swap off&lt;/h2&gt;
&lt;pre id=&quot;code_1723099242303&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ sudo adduser ask

$ cat &amp;lt;&amp;lt;EOF | sudo tee /etc/sudoers.d/sudoers-ask
ask     ALL=(ALL:ALL)   NOPASSWD:ALL
EOF

$ sudo systemctl stop ufw
$ sudo systemctl disable ufw
$ sudo systemctl stop apparmor.service
$ sudo systemctl disable apparmor.service
$ sudo swapoff -a&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. module load&lt;/h3&gt;
&lt;pre id=&quot;code_1723099287667&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ cat &amp;lt;&amp;lt;EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF

$ sudo modprobe overlay
$ sudo modprobe br_netfilter&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. network forwarding 설정&lt;/h3&gt;
&lt;pre id=&quot;code_1723099327735&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ cat &amp;lt;&amp;lt;EOF | sudo tee /etc/sysctl.d/99-kubernetes.conf
net.bridge.bridge-nf-call-iptables  = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward                 = 1
EOF


$ sudo sysctl --system
$ sudo iptables -P FORWARD ACCEPT&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. containerd 설치&lt;/h3&gt;
&lt;pre id=&quot;code_1723099404397&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ sudo apt-get update
$ sudo apt-get install -y apt-transport-https ca-certificates curl gpg
$ sudo install -m 0755 -d /etc/apt/keyrings
$ sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
$ sudo chmod a+r /etc/apt/keyrings/docker.asc

$ echo \
  &quot;deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release &amp;amp;&amp;amp; echo &quot;$VERSION_CODENAME&quot;) stable&quot; | \
  sudo tee /etc/apt/sources.list.d/docker.list &amp;gt; /dev/null

$ sudo apt-get update
$ sudo apt-get install -y containerd.io

$ sudo mkdir -p /etc/containerd
$ sudo containerd config default | sudo tee /etc/containerd/config.toml

$ sudo sed -i 's/SystemdCgroup \= false/SystemdCgroup \= true/g' /etc/containerd/config.toml

$ sudo systemctl restart containerd
$ sudo systemctl enable containerd
$ sudo systemctl status containerd&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-en-clipboard=&quot;true&quot; data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size26&quot;&gt;5. crictl 설치&lt;/h2&gt;
&lt;pre id=&quot;code_1723099557896&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#----------------------------------------------------------
# 서버가 arm64 or amd64 인지 확인하여 설치
#----------------------------------------------------------
$ VERSION=&quot;v1.30.0&quot;
$ curl -L https://github.com/kubernetes-sigs/cri-tools/releases/download/$VERSION/crictl-${VERSION}-linux-arm64.tar.gz --output crictl-${VERSION}-linux-arm64.tar.gz

$ sudo tar zxvf crictl-$VERSION-linux-arm64.tar.gz -C /usr/local/bin
$ rm -f crictl-$VERSION-linux-arm64.tar.gz

#----------------------------------------------------------
# crictl 이 어느 container 를 접속할 것인지 세팅
#----------------------------------------------------------
$ cat &amp;lt;&amp;lt;EOF | sudo tee /etc/crictl.yaml
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 2
debug: false
pull-image-on-create: false
EOF

$ sudo bash -c &quot;crictl completion &amp;gt; /etc/bash_completion.d/crictl&quot;
$ source ~/.bashrc


#----------------------------------------------------------
# containerd 설정 확인
#----------------------------------------------------------
$ sudo crictl info&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6. kubectl 설치&lt;/h3&gt;
&lt;pre id=&quot;code_1723099678590&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#----------------------------------------------------------
# 서버가 arm64 or amd64 인지 확인하여 설치
#----------------------------------------------------------
$ curl -LO &quot;https://dl.k8s.io/release/v1.30.0/bin/linux/arm64/kubectl&quot;
$ chmod +x ./kubectl
$ sudo mv ./kubectl /usr/local/bin/kubectl&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.&amp;nbsp; Kubernetes 설치&lt;/h3&gt;
&lt;pre id=&quot;code_1723103623007&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ mkdir -p ~/kubeadm &amp;amp;&amp;amp; cd ~/kubeadm

#-----------------------------------------------
# kubernetes 다운로드 key 와 url 등록
#-----------------------------------------------
$ curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg

$ echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.30/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
$ sudo apt-get update


#========================================================================
# kubelet 설치 (아직 kubelet 이 뜨지는 않음)
#========================================================================
$ sudo apt-get install -y kubelet=&quot;1.30.3-*&quot; kubeadm=&quot;1.30.3-*&quot;
$ sudo systemctl enable --now kubelet
$ sudo systemctl start kubelet

#========================================================================
# 1. kubeadm 설치
#========================================================================
$ sudo kubeadm config images pull

#------------------------------------------------------------
# 자기 노드의 ip: --apiserver-advertise-address
# multi control-plane 일 경우 L4 ip: --control-plane-endpoint
# cgroup driver 세팅 (https://kubernetes.io/docs/tasks/administer-cluster/kubeadm/configure-cgroup-driver/)
#------------------------------------------------------------
$ vi kubeadm-config.yaml

apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration
nodeRegistration:
  criSocket: &quot;/var/run/containerd/containerd.sock&quot;

---
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
apiServer:
  certSANs:
  - 127.0.0.1
  - localhost
  - &amp;lt;Node private IP&amp;gt;
  - &amp;lt;Node public IP&amp;gt;
networking:
  serviceSubnet: 10.233.0.0/18
  podSubnet: 10.233.64.0/18
  dnsDomain: &quot;cluster.local&quot;


#----------------------------------------------------------------
# kubeadm init 을 하고 나면 /var/lib/kubelet/config.yaml 이 생성되어
# kubelet 이 정상적으로 실행됨
#----------------------------------------------------------------
$ sudo kubeadm init --config kubeadm-config.yaml --v=5


#------------------------------------------------------------
# kubeconfig
#------------------------------------------------------------
$ mkdir -p ~/.kube
$ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
$ sudo chown $(id -u):$(id -g) $HOME/.kube/config&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8. Calico 설치&lt;/h3&gt;
&lt;pre id=&quot;code_1723103706139&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ mkdir -p ~/calico &amp;amp;&amp;amp; cd ~/calico

$ curl -LO https://raw.githubusercontent.com/projectcalico/calico/v3.28.0/manifests/tigera-operator.yaml

$ kubectl create -f tigera-operator.yaml

$ curl -LO https://raw.githubusercontent.com/projectcalico/calico/v3.28.0/manifests/custom-resources.yaml

#------------------------------------------------------------
# yaml 을 열어서 pod 네트워크를 확인하고 변경
#------------------------------------------------------------
$ vi custom-resources.yaml
...
    cidr: 10.233.64.0/18
...

$ kubectl create -f custom-resources.yaml

#------------------------------------------------------------
# calico 설치 확인
#------------------------------------------------------------
$ kubectl get pods -n calico-system&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;9. kubectl bash completion&lt;/h3&gt;
&lt;pre id=&quot;code_1723103772016&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ source &amp;lt;(kubectl completion bash)
$ kubectl completion bash &amp;gt; ~/.kube/completion.bash.inc

$ printf &quot;
# kubectl shell completion
source '$HOME/.kube/completion.bash.inc'
&quot; &amp;gt;&amp;gt; $HOME/.bash_aliases

$ source $HOME/.bash_aliases&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;10. taint 제거&lt;/h3&gt;
&lt;pre id=&quot;code_1723103812146&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ kubectl taint nodes --all node-role.kubernetes.io/control-plane-&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;11. 설치 테스트&lt;/h3&gt;
&lt;pre id=&quot;code_1723103912269&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ mkdir -p ~/sample-yaml &amp;amp;&amp;amp; cd ~/sample-yaml

$ cat &amp;lt;&amp;lt;EOF | tee ./nginx-service.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx-deployment
  name: nginx-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.21.0
        ports:
        - containerPort: 80

---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service-nodeport
spec:
  selector:
    app: nginx
  ports:
  - protocol: TCP
    port: 8080
    targetPort: 80
    nodePort: 30180
  type: NodePort
  externalTrafficPolicy: Local
EOF


$ kubectl apply -f nginx-service.yaml

$ kubectl get pods

$ curl &amp;lt;Node ip&amp;gt;:30180&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Kubernetes</category>
      <category>kubeadm</category>
      <category>kubernetes all-in-one</category>
      <category>kubernetes 설치</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/327</guid>
      <comments>https://ahnseungkyu.com/327#entry327comment</comments>
      <pubDate>Thu, 8 Aug 2024 16:59:40 +0900</pubDate>
    </item>
    <item>
      <title>minkube, kind 설치하기</title>
      <link>https://ahnseungkyu.com/326</link>
      <description>&lt;h1&gt;Minikube 설치하기&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;minkube 설치는 아래 사이트를 참고한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://minikube.sigs.k8s.io/docs/start/&quot;&gt;https://minikube.sigs.k8s.io/docs/start/&lt;/a&gt;&lt;/p&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;$ curl -LO &amp;lt;https://storage.googleapis.com/minikube/releases/latest/minikube-darwin-arm64&amp;gt;
$ install minikube-darwin-arm64 /Users/ask/bin/minikube
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;start cluster&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://minikube.sigs.k8s.io/docs/drivers/docker/&quot;&gt;https://minikube.sigs.k8s.io/docs/drivers/docker/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;driver 를 docker 로 사용하기 때문에 docker 를 미리 설치해 놓아야 한다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ docker context use default
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후에 minikube 로 cluster 를 생성한다.&lt;/p&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;$ minikube start --driver=docker --memory=4096
--- output ---
   Darwin 13.5.2 (arm64) 의 minikube v1.33.0
✨  유저 환경 설정 정보에 기반하여 docker 드라이버를 사용하는 중
   Using Docker Desktop driver with root privileges
   Starting &quot;minikube&quot; primary control-plane node in &quot;minikube&quot; cluster
   Pulling base image v0.0.43 ...
   Creating docker container (CPUs=2, Memory=4096MB) ...
❗  This container is having trouble accessing &amp;lt;https://registry.k8s.io&amp;gt;
   To pull new external images, you may need to configure a proxy: &amp;lt;https://minikube.sigs.k8s.io/docs/reference/networking/proxy/&amp;gt;
   쿠버네티스 v1.30.0 을 Docker 26.0.1 런타임으로 설치하는 중
    ▪ 인증서 및 키를 생성하는 중 ...
    ▪ 컨트롤 플레인을 부팅하는 중 ...
    ▪ RBAC 규칙을 구성하는 중 ...
   bridge CNI (Container Networking Interface) 를 구성하는 중 ...
   Kubernetes 구성 요소를 확인...
    ▪ Using image gcr.io/k8s-minikube/storage-provisioner:v5
   애드온 활성화 : storage-provisioner, default-storageclass

❗  /Users/ask/bin/kubectl is version 1.28.2, which may have incompatibilities with Kubernetes 1.30.0.
    ▪ Want kubectl v1.30.0? Try 'minikube kubectl -- get pods -A'
   끝났습니다! kubectl이 &quot;minikube&quot; 클러스터와 &quot;default&quot; 네임스페이스를 기본적으로 사용하도록 구성되었습니다.
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;디폴트 메모리를 config 에 세팅할 수 도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;config 세팅은 기존에 만든 minikube node 에는 적용이 안되고 새롭게 만드는 노드에만 적용된다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ minikube config set memory 4096
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;node 추가&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;minikube 에 worker node 를 추가할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;$ minikube node add
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;node 가 추가된 것을 볼 수 있다.&lt;/p&gt;
&lt;pre class=&quot;lsl&quot;&gt;&lt;code&gt;$ kubectl get nodes
NAME           STATUS   ROLES           AGE     VERSION
minikube       Ready    control-plane   8m22s   v1.30.0
minikube-m02   Ready    &amp;lt;none&amp;gt;          86s     v1.30.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;node 에 Role 을 추가하고 싶으면 다음과 같이 지정한다.&lt;/p&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;$ kubectl label node minikube-m02 node-role.kubernetes.io/node=enabled --overwrite

$ kubectl get nodes
NAME           STATUS   ROLES           AGE     VERSION
minikube       Ready    control-plane   15m     v1.30.0
minikube-m02   Ready    node            8m12s   v1.30.0
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;minikube 명령어&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;현재 설치된 minkube node 를 조회한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;ldif&quot;&gt;&lt;code&gt;$ minkube status
--- output ---
minikube
type: Control Plane
host: Running
kubelet: Running
apiserver: Running
kubeconfig: Configured

minikube-m02
type: Worker
host: Running
kubelet: Running
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;minikube 로 만든 kubernetes cluster 의 모든 namespace 를 잠시 멈춘다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;$ minkube pause -A
--- output --
⏸️  Pausing node minikube ...
⏸️  Pausing node m02 ...
⏯️  Paused 16 containers
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;minkube 로 pause 한 cluster 를 다시 실행한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;$ minikube unpause -A
--- output ---
⏸️  Unpausing node minikube ...
⏸️  Unpausing node m02 ...
⏸️  Unpaused 16 containers
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;minikube 모든 노드를 중지한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;$ minikube stop --all=true
--- output ---
✋  &quot;minikube-m02&quot; 노드를 중지하는 중 ...
   &quot;minikube-m02&quot;를 SSH로 전원을 끕니다 ...
✋  &quot;minikube&quot; 노드를 중지하는 중 ...
   &quot;minikube&quot;를 SSH로 전원을 끕니다 ...
   2개의 노드가 중지되었습니다.
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;aged 란 이름의 다른 쿠버네티스 버전을 추가로 설치한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;$ minikube start -p aged --kubernetes-version=v1.28.2
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 minikube 로 만든 kubernetes cluster 를 삭제한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;livecodeserver&quot;&gt;&lt;code&gt;minikube delete --all
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;minikube addons 목록을 살펴본다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;gherkin&quot;&gt;&lt;code&gt;$ minikube addons list
|-----------------------------|----------|--------------|--------------------------------|
|         ADDON NAME          | PROFILE  |    STATUS    |           MAINTAINER           |
|-----------------------------|----------|--------------|--------------------------------|
| ambassador                  | minikube | disabled     | 3rd party (Ambassador)         |
| auto-pause                  | minikube | disabled     | minikube                       |
| cloud-spanner               | minikube | disabled     | Google                         |
| csi-hostpath-driver         | minikube | disabled     | Kubernetes                     |
| dashboard                   | minikube | disabled     | Kubernetes                     |
| default-storageclass        | minikube | enabled ✅   | Kubernetes                     |
| efk                         | minikube | disabled     | 3rd party (Elastic)            |
| freshpod                    | minikube | disabled     | Google                         |
| gcp-auth                    | minikube | disabled     | Google                         |
| gvisor                      | minikube | disabled     | minikube                       |
| headlamp                    | minikube | disabled     | 3rd party (kinvolk.io)         |
| helm-tiller                 | minikube | disabled     | 3rd party (Helm)               |
| inaccel                     | minikube | disabled     | 3rd party (InAccel             |
|                             |          |              | [info@inaccel.com])            |
| ingress                     | minikube | disabled     | Kubernetes                     |
| ingress-dns                 | minikube | disabled     | minikube                       |
| inspektor-gadget            | minikube | disabled     | 3rd party                      |
|                             |          |              | (inspektor-gadget.io)          |
| istio                       | minikube | disabled     | 3rd party (Istio)              |
| istio-provisioner           | minikube | disabled     | 3rd party (Istio)              |
| kong                        | minikube | disabled     | 3rd party (Kong HQ)            |
| kubeflow                    | minikube | disabled     | 3rd party                      |
| kubevirt                    | minikube | disabled     | 3rd party (KubeVirt)           |
| logviewer                   | minikube | disabled     | 3rd party (unknown)            |
| metallb                     | minikube | disabled     | 3rd party (MetalLB)            |
| metrics-server              | minikube | disabled     | Kubernetes                     |
| nvidia-device-plugin        | minikube | disabled     | 3rd party (NVIDIA)             |
| nvidia-driver-installer     | minikube | disabled     | 3rd party (Nvidia)             |
| nvidia-gpu-device-plugin    | minikube | disabled     | 3rd party (Nvidia)             |
| olm                         | minikube | disabled     | 3rd party (Operator Framework) |
| pod-security-policy         | minikube | disabled     | 3rd party (unknown)            |
| portainer                   | minikube | disabled     | 3rd party (Portainer.io)       |
| registry                    | minikube | disabled     | minikube                       |
| registry-aliases            | minikube | disabled     | 3rd party (unknown)            |
| registry-creds              | minikube | disabled     | 3rd party (UPMC Enterprises)   |
| storage-provisioner         | minikube | enabled ✅   | minikube                       |
| storage-provisioner-gluster | minikube | disabled     | 3rd party (Gluster)            |
| storage-provisioner-rancher | minikube | disabled     | 3rd party (Rancher)            |
| volumesnapshots             | minikube | disabled     | Kubernetes                     |
| yakd                        | minikube | disabled     | 3rd party (marcnuri.com)       |
|-----------------------------|----------|--------------|--------------------------------|
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;dashboard 를 설치한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;livecodeserver&quot;&gt;&lt;code&gt;$ minikube addons enable dashboard
--- output ---
   dashboard is an addon maintained by Kubernetes. For any concerns contact minikube on GitHub.
You can view the list of minikube maintainers at: &amp;lt;https://github.com/kubernetes/minikube/blob/master/OWNERS&amp;gt;
    ▪ Using image docker.io/kubernetesui/dashboard:v2.7.0
    ▪ Using image docker.io/kubernetesui/metrics-scraper:v1.0.8
   Some dashboard features require the metrics-server addon. To enable all features please run:

	minikube addons enable metrics-server

   'dashboard' 애드온이 활성화되었습니다
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;metrics-server 를 설치한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;$ minikube addons enable metrics-server
--- output ---
   metrics-server is an addon maintained by Kubernetes. For any concerns contact minikube on GitHub.
You can view the list of minikube maintainers at: &amp;lt;https://github.com/kubernetes/minikube/blob/master/OWNERS&amp;gt;
    ▪ Using image registry.k8s.io/metrics-server/metrics-server:v0.7.1
   'metrics-server' 애드온이 활성화되었습니다
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;dashboard 에 접속한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;ada&quot;&gt;&lt;code&gt;$ minikube dashboard --url
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;minikube trouble shooting&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;minikube 를 설치하고 pod 가 생성안되는 가장 큰 이유는 proxy 때문이다. 회사에서 proxy 를 사용한다면 proxy 세팅을 추가로 해줘야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 내용은 proxy 이외의 문제일 때 해결 방법이다.&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;docker hub 으로 부터 이미지를 다운 받지 못하는 문제&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;subunit&quot;&gt;&lt;code&gt;Error response from daemon: Get &quot;&amp;lt;https://registry-1.docker.io/v2/&amp;gt;&quot;: tls: failed to verify certificate: x509: certificate signed by unknown authority
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;minikube 의 docker-env 를 확인한 후 세팅한다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ minikube -p minikube docker-env
--- output ---
export DOCKER_TLS_VERIFY=&quot;1&quot;
export DOCKER_HOST=&quot;tcp://127.0.0.1:53131&quot;
export DOCKER_CERT_PATH=&quot;/Users/ask/.minikube/certs&quot;
export MINIKUBE_ACTIVE_DOCKERD=&quot;minikube&quot;

$ docker context create minikube --description &quot;Minikube&quot; --docker &quot;host=tcp://localhost:53131,ca=/Users/ask/.minikube/certs/ca.pem,cert=/Users/ask/.minikube/certs/cert.pem,key=/Users/ask/.minikube/certs/key.pem&quot;
$ docker context use minikube
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 경우에는 minikube 를 띄울 때 --insecure-registry 를 추가한다.&lt;/p&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;$ minikube start --insecure-registry=&quot;registry-1.docker.io&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아니면 minikube 로 노드에 접속해서 docker 에 인증서를 추가한다.&lt;/p&gt;
&lt;pre class=&quot;groovy&quot;&gt;&lt;code&gt;$ minikube ssh
$ sudo su -

$ update-ca-certificates --fresh
$ openssl s_client -showcerts -verify 5 -connect k8s.gcr.io:443 &amp;lt; /dev/null 2&amp;gt;/dev/null | openssl x509 -outform PEM | tee ~/k8s.gcr.io.crt
$ openssl s_client -showcerts -verify 5 -connect registry-1.docker.io:443 &amp;lt; /dev/null 2&amp;gt;/dev/null | openssl x509 -outform PEM | tee ~/registry-1.docker.io.crt
$ openssl s_client -showcerts -verify 5 -connect auth.docker.io:443 &amp;lt; /dev/null 2&amp;gt;/dev/null | openssl x509 -outform PEM | tee ~/auth.docker.io.crt
$ cp ~/k8s.gcr.io.crt /usr/local/share/ca-certificates/
$ cp ~/registry-1.docker.io.crt /usr/local/share/ca-certificates/
$ cp ~/auth.docker.io.crt /usr/local/share/ca-certificates/
$ update-ca-certificates

$ systemctl restart docker
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Kind 설치&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kind 는 아래 설치 사이트를 참조한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://kind.sigs.k8s.io/docs/user/quick-start/&quot;&gt;https://kind.sigs.k8s.io/docs/user/quick-start/&lt;/a&gt;&lt;/p&gt;
&lt;pre class=&quot;elixir&quot;&gt;&lt;code&gt;$ [ $(uname -m) = arm64 ] &amp;amp;&amp;amp; curl -Lo ./kind &amp;lt;https://kind.sigs.k8s.io/dl/v0.22.0/kind-darwin-arm64&amp;gt;
$ chmod +x kind
$ mv kind ~/bin/kind
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;kind config 세팅&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;image 는 아래 사이트에서 확인 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/kubernetes-sigs/kind/releases&quot;&gt;https://github.com/kubernetes-sigs/kind/releases&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kind config 는 여기를 참조한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://kind.sigs.k8s.io/docs/user/quick-start/#configuring-your-kind-cluster&quot;&gt;https://kind.sigs.k8s.io/docs/user/quick-start/#configuring-your-kind-cluster&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ingress 를 사용하기 위해서는 아래 내용 처럼 port mapping 을 해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://kind.sigs.k8s.io/docs/user/ingress&quot;&gt;https://kind.sigs.k8s.io/docs/user/ingress&lt;/a&gt;&lt;/p&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;$ vi kind-config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
# patch the generated kubeadm config with some extra settings
kubeadmConfigPatches:
- |
  apiVersion: kubelet.config.k8s.io/v1beta1
  kind: KubeletConfiguration
  evictionHard:
    nodefs.available: &quot;0%&quot;
# patch it further using a JSON 6902 patch
kubeadmConfigPatchesJSON6902:
- group: kubeadm.k8s.io
  version: v1beta3
  kind: ClusterConfiguration
  patch: |
    - op: add
      path: /apiServer/certSANs/-
      value: my-hostname
nodes:
- role: control-plane
  image: kindest/node:v1.29.2@sha256:51a1434a5397193442f0be2a297b488b6c919ce8a3931be0ce822606ea5ca245
#  extraPortMappings:
#  - containerPort: 80
#    hostPort: 10080
#    listenAddress: &quot;0.0.0.0&quot; # Optional, defaults to &quot;0.0.0.0&quot;
#    protocol: tcp # Optional, defaults to tcp
- role: worker
  image: kindest/node:v1.29.2@sha256:51a1434a5397193442f0be2a297b488b6c919ce8a3931be0ce822606ea5ca245
#featureGates:
#  FeatureGateName: true
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;kind create cluster&lt;/h2&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;$ KIND_EXPERIMENTAL_PROVIDER=docker &amp;amp;&amp;amp; kind create cluster --name kind --config kind-config.yaml
--- output ---
Creating cluster &quot;kind&quot; ...
 ✓ Ensuring node image (kindest/node:v1.29.2)  
 ✓ Preparing nodes    
 ✓ Writing configuration  
 ✓ Starting control-plane  ️
 ✓ Installing CNI  
 ✓ Installing StorageClass  
 ✓ Joining worker nodes  
Set kubectl context to &quot;kind-kind&quot;
You can now use your cluster with:

kubectl cluster-info --context kind-kind

Thanks for using kind!  
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;kind cluster 보기&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ kind get clusters
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;context 로 cluster 조회하기&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;$ kubectl cluster-info --context kind-kind
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;cluster 삭제하기&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;fortran&quot;&gt;&lt;code&gt;$ kind delete cluster --name kind
&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Kubernetes</category>
      <category>kind</category>
      <category>minikube</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/326</guid>
      <comments>https://ahnseungkyu.com/326#entry326comment</comments>
      <pubDate>Thu, 9 May 2024 09:07:13 +0900</pubDate>
    </item>
    <item>
      <title>(OpenLab 스터디) 어플리케이션 배포 전략에 따른 실제 배포 실습</title>
      <link>https://ahnseungkyu.com/325</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;스터디에서 준비해야 할 내용 리스트&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;배포 전략에 대한 개념 설명&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Rolling Update&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Blue/Green&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Canary&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Recreate&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Argo CD 설치, Argo Rollout 설치&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Argo CD 로 github 을 연동하여 gitops 구현해 보기&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Argo Rollout 을 활용하여 Blue/Green 구현해 보기&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Kubernetes 에서 Deployment 로 배포된 서비스가 Rolling Update 되는 로직을 설명&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;(선택) Nginx Ingress Controller 를 활용하여 Canary 배포를 구현해 보기&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Kubernetes</category>
      <category>Argo CD</category>
      <category>argo rollout</category>
      <category>bluegreen</category>
      <category>canary</category>
      <category>recreate</category>
      <category>Rolling Update</category>
      <category>배포전략</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/325</guid>
      <comments>https://ahnseungkyu.com/325#entry325comment</comments>
      <pubDate>Thu, 9 May 2024 08:50:54 +0900</pubDate>
    </item>
    <item>
      <title>쿨린이가 Kubernetes(쿠버네티스)를 처음 공부하려면 무엇부터 공부해야 할까?</title>
      <link>https://ahnseungkyu.com/324</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;Kubernetes 를 세미나를 하거나 모임에서 만나면 쿠버네티스를 알고 싶어 하시는 분들이 제일 문제 물어보는 것이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&quot;쿠버네티스를 잘 모르는데 이제부터 공부하고 싶어요. 어떤거 부터 하면 좋을까요?&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그 동안은 이는 리눅스를 무엇부터 공부해야 할까요? 와 거의 비슷한 이야기인거 같다. 그래서 키워드로 스스로 공부할 수 있도록 키워드로 리스트를 만들었다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;컨테이너&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Docker 노트북에 설치&lt;/li&gt;
&lt;li&gt;리눅스 네임스페이스 &amp;amp; cgroup&lt;/li&gt;
&lt;li&gt;dockerfile 작성 및 docker image 만들기&lt;/li&gt;
&lt;li&gt;docker image 실행/종료/삭제 하기&lt;/li&gt;
&lt;li&gt;docker hub 에 가입하여 개인 계정에 image 올리기&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Kubernetes&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Kubernetes 는 누가 만들었을까? 어떻게 해서 나오게 된 것일까? (Google Borg 로 검색)&lt;/li&gt;
&lt;li&gt;CNCF (Cloud Native Computing Foundation) - 이 재단이 어떤 재단인지 알아보기&lt;/li&gt;
&lt;li&gt;Kubernetes 는 기능이 어떤 것들이 있을까?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기본적으로 Kubernetes 는 컨테이너 이미지를 실행시키는 등 관리하는 역할 수행&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Kubernetes 노트북에 설치 (아래 3개 중에 하나)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;kind&lt;/li&gt;
&lt;li&gt;k3s&lt;/li&gt;
&lt;li&gt;minikube&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Kubernetes client 설치
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;kubectl 설치&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Kubernetes Architecture 확인
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Control plane
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;etcd (key-value store)&lt;/li&gt;
&lt;li&gt;kube-apiserver&lt;/li&gt;
&lt;li&gt;kube-controller&lt;/li&gt;
&lt;li&gt;kube-scheduler&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Node
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;kube-proxy&lt;/li&gt;
&lt;li&gt;kubelet&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Network plugin&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Kubernetes 에서 Pod 란 무엇인가?&lt;/li&gt;
&lt;li&gt;Kubernetes 에 Nginx 이미지를 pod 로 띄우기
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pod yaml 만들기&lt;/li&gt;
&lt;li&gt;kubectl 로 pod yaml 을 Kubernetes 에 배포하기&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Pod 는 어떻게 뜨는 것일까?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사용자가 pod yaml 을 작성&lt;/li&gt;
&lt;li&gt;사용자가 kubectl 로 pod yaml 을 kubernetes 로 보냄&lt;/li&gt;
&lt;li&gt;kubernetes api-server 가 이를 받아서 etcd 에 저장&lt;/li&gt;
&lt;li&gt;kube-scheduler 가 pod 를 원하는 node 로 스케줄링&lt;/li&gt;
&lt;li&gt;스케줄링된 node 에 실행중인 kubelet 이 pod 를 실행&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Kubernetes Resource 알아보기
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Pod&lt;/li&gt;
&lt;li&gt;ReplicaSet&lt;/li&gt;
&lt;li&gt;Deployment&lt;/li&gt;
&lt;li&gt;Label &amp;amp; Selector&lt;/li&gt;
&lt;li&gt;Service
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ClusterIP&lt;/li&gt;
&lt;li&gt;NodePort&lt;/li&gt;
&lt;li&gt;LoadBalancer&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Ingress &amp;amp; Ingress Controller&lt;/li&gt;
&lt;li&gt;StatefulSet&lt;/li&gt;
&lt;li&gt;DaemonSet&lt;/li&gt;
&lt;li&gt;StorageClass&lt;/li&gt;
&lt;li&gt;Persistent Volume&lt;/li&gt;
&lt;li&gt;Persistent Volume Claim&lt;/li&gt;
&lt;li&gt;ConfigMap&lt;/li&gt;
&lt;li&gt;Secret&lt;/li&gt;
&lt;li&gt;ServiceAccount&lt;/li&gt;
&lt;li&gt;ClusterRole&lt;/li&gt;
&lt;li&gt;ClusterRoleBinding&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Custom Controller (Operator 란 무엇인가?)&lt;/li&gt;
&lt;li&gt;CNCF Projects 알아보기
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Graduated Projects&lt;/li&gt;
&lt;li&gt;Incubating Projects&lt;/li&gt;
&lt;li&gt;Sandbox Projects&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Kubernetes</category>
      <category>kubernetes</category>
      <category>kubernetes 초보자</category>
      <category>쿠버네티스</category>
      <category>쿠버네티스 초보자</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/324</guid>
      <comments>https://ahnseungkyu.com/324#entry324comment</comments>
      <pubDate>Tue, 30 Apr 2024 10:04:41 +0900</pubDate>
    </item>
    <item>
      <title>OPA(Open Policy Agent) hello rego 프로그램 실행하기</title>
      <link>https://ahnseungkyu.com/323</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;OPA 실행 파일 설치&lt;/h2&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;$ curl -L -o opa &amp;lt;https://github.com/open-policy-agent/opa/releases/download/v0.62.1/opa_darwin_arm64_static&amp;gt;
$ chmod +x opa
$ mv opa ~/bin/&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 홈 디렉토리 아래의 bin 디렉토리에 실행 패스가 잡혀있기 때문에 해당 디렉토리로 이동시킨 것이다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Intellij 와 Open Policy Agent Plugin 설치&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JetBrain 의 IntelliJ 가 있다면 Open Policy Agent 플러그인을 설치하여 rego 프로그램을 작성할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;hello 프로그램을 작성하여 실행하여 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 번들용 chap1 디렉토리를 만든다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;$ mkdir -p chap1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;chap1 번들 아래에 hello.rego 파일을 만든다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;package hello

default allow_hello = false
default allow_world = false

allow_hello {
    &quot;hello&quot; != &quot;&quot;
}

allow_world {
    &quot;world&quot; != &quot;world&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;패키지 hello 는 디렉토리와 상관없으며 chap1 디렉토리를 만들었기 때문에 bundle 은 chap1 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;allow_hello 와 allow_world 는 rule 을 나타낸다. OPA 1.0 미만은 if 문이 없기 때문에 비교문 만으로 표현한다. OPA 1.0 부터는 if 문을 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;opa 실행은 input json 에 대한 output json 이 결과로 나오는데 input 소스를 보면 input 이 필요없기 때문에 빈 input.json 파일을 만든다.&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;$ touch input.json &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재까지의 디렉토리 구조를 보면 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;rego-example.iml 은 IntelliJ 의 OPA 플러그인에서 사용하는 파일이므로 신경쓸 필요가 없다.&lt;/p&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;$ tree .
.
├── chap1
│   ├── hello.rego
│   └── input.json
└── rego-example.iml&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 cli 로 실행하면 다음과 같다.&lt;/p&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;$ opa eval -f pretty -b chap1 data.hello    

--- output ---
{
  &quot;allow_hello&quot;: true,
  &quot;allow_world&quot;: false
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;opa eval 명령어로 rule 을 평가할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-f pretty 결과를 보기 쉽게 출력하라는 의미이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-b cha1 은 &lt;b&gt;Bundle&lt;/b&gt; 을 입력해야 하는데 chap1 디렉토리 의 아래 rego 파일을 실행하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;data.hello 는 &lt;b&gt;Query&lt;/b&gt; 를 의미하며, 여기에는 package 나 rule 을 넣으면 된다. data 는 명시적으로 붙혀서 data.패키지 로 입력하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;allow_hello rule 을 실행하기 위해서는 query 부분에 rule 까지 넣어주면 된다.&lt;/p&gt;
&lt;pre class=&quot;haskell&quot;&gt;&lt;code&gt;$ opa eval -f pretty -b chap1 data.hello.allow_hello

--- output ---
true&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과 값으로 json 형태가 디퐅트로 출력되는데 -f pretty 를 제거하면 json 으로 결과가 출력된다.&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;$ opa eval -b chap1 data.hello

--- output ---
{
  &quot;result&quot;: [
    {
      &quot;expressions&quot;: [
        {
          &quot;value&quot;: {
            &quot;allow_hello&quot;: true,
            &quot;allow_world&quot;: false
          },
          &quot;text&quot;: &quot;data.hello&quot;,
          &quot;location&quot;: {
            &quot;row&quot;: 1,
            &quot;col&quot;: 1
          }
        }
      ]
    }
  ]
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;input 을 위해서 빈 input.json 파일을 만들었는데 이를 활용하는 명령을 추가할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;input 값을 실제로 사용하지는 않기 때문에 결과 값은 동일하다.&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;$ opa eval -b chap1 -i chap1/input.json data.hello

--- output ---
{
  &quot;result&quot;: [
    {
      &quot;expressions&quot;: [
        {
          &quot;value&quot;: {
            &quot;allow_hello&quot;: true,
            &quot;allow_world&quot;: false
          },
          &quot;text&quot;: &quot;data.hello&quot;,
          &quot;location&quot;: {
            &quot;row&quot;: 1,
            &quot;col&quot;: 1
          }
        }
      ]
    }
  ]
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행을 cli 로 하지 말고 IntelliJ 에서 실행하는 방법은 아래와 같이 입력하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메뉴에서 Run &amp;gt;&amp;gt; Edit Configurations... 을 실행한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1722&quot; data-origin-height=&quot;1142&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dz04sF/btsF2QWeft1/17VukpR6a1CKVoKCSKvyf0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dz04sF/btsF2QWeft1/17VukpR6a1CKVoKCSKvyf0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dz04sF/btsF2QWeft1/17VukpR6a1CKVoKCSKvyf0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdz04sF%2FbtsF2QWeft1%2F17VukpR6a1CKVoKCSKvyf0%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;1722&quot; height=&quot;1142&quot; data-origin-width=&quot;1722&quot; data-origin-height=&quot;1142&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&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;Run 버튼을 클릭하면 다음과 같이 결과가 나온다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1492&quot; data-origin-height=&quot;301&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cNDeoO/btsFZSV6lmk/B5jl5zsNapUAhCig8ovi11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cNDeoO/btsFZSV6lmk/B5jl5zsNapUAhCig8ovi11/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cNDeoO/btsFZSV6lmk/B5jl5zsNapUAhCig8ovi11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcNDeoO%2FbtsFZSV6lmk%2FB5jl5zsNapUAhCig8ovi11%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;1492&quot; height=&quot;301&quot; data-origin-width=&quot;1492&quot; data-origin-height=&quot;301&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소스는 아래 사이트에서 다운받을 수 있다. (계속 업데이트 될 예정)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/seungkyua/rego-example.git&quot;&gt;https://github.com/seungkyua/rego-example.git&lt;/a&gt;&lt;/p&gt;</description>
      <category>프로그래밍/Rego (OPA)</category>
      <category>OPA</category>
      <category>Open Policy Agent</category>
      <category>Rego</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/323</guid>
      <comments>https://ahnseungkyu.com/323#entry323comment</comments>
      <pubDate>Fri, 22 Mar 2024 19:54:14 +0900</pubDate>
    </item>
    <item>
      <title>(golang) Embedding Interface 활용</title>
      <link>https://ahnseungkyu.com/322</link>
      <description>&lt;p&gt;인터페이스가 다른 인터페이서를 가지는 임베딩 방식을 사용하여 인터페이스를 선언할 수 있다. 예를 들어 io.ReadCloser 인터페이스는 io.Reader 와 io.Closer 인터페이스를 가지고 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;type Reader interface {
        Read(p []byte) (n int, err error)
}

type Closer interface {
        Close() error
}

type ReadCloser interface {
        Reader
        Closer
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이 경우 ReadCloser 인터페이스는 아래와 동일 효과를 갖는다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;type ReadCloser interface {
        Read(p []byte) (n int, err error)
        Close() error
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;그런데 인터페이스를 struct 타입 안에 임베딩할 수 도 있다.&lt;/p&gt;
&lt;p&gt;이렇게 struct 타입 안에 인터페이스를 넣는 이유는 보통 Stub 으로 유닛 테스트 코드를 만들기 쉽기 때문이다.&lt;/p&gt;
&lt;p&gt;아래와 같이 &lt;code&gt;Calculator&lt;/code&gt; 라는 스트럭트가 있다고 하자.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;type Calculator struct {
    Resolver MathResolver
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;여기에는 &lt;code&gt;MathResolver&lt;/code&gt; 인터페이스 타입의 필드를 가지고 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;type MathResolver interface {
    Resolve(expression string) (float64, error)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이렇게 인터페이스를 만들어 놓으면 &lt;code&gt;MathResolver&lt;/code&gt; 를 Stub 으로 구현하여 테스트 코드를 만들 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Calculator&lt;/code&gt; 는 계산 표현식을 가지고 실제 계산하여 결과 값을 리턴하는 &lt;code&gt;Process&lt;/code&gt; 라는 메소스도 가진다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;func (c Calculator) Process(r io.Reader) (float64, error) {
    expression, err := readOneLine(r)
    if err != nil {
        return 0, err
    }
    if len(expression) == 0 {
        return 0, errors.New(&amp;quot;no expression to read&amp;quot;)
    }
    answer, err := c.Resolver.Resolve(expression)
    return answer, err
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;readOneLine&lt;/code&gt; 함수는 계산 표현식을 한 줄만 읽어들이는 함수이며, 이렇게 읽어들인 함수를 &lt;code&gt;MathResolver&lt;/code&gt; 타입의 &lt;code&gt;Resolve&lt;/code&gt; 함수에 아규먼트로 넘겨서 결과를 받아오는 구조이다.&lt;/p&gt;
&lt;p&gt;이제 &lt;code&gt;Proecess&lt;/code&gt; 메소드에 대한 테스트 코드를 만들어 보자.&lt;/p&gt;
&lt;p&gt;첫번째로 테스트 코드로 &lt;code&gt;MathResolverStub&lt;/code&gt; 스트럭트와 &lt;code&gt;Resolve&lt;/code&gt; 메소드를 간단히 구현한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;type MathResolverStub struct{}

func (mr MathResolverStub) Resolve(expr string) (float64, error) {
    switch expr {
    case &amp;quot;2 + 4 * 10&amp;quot;:
        return 42, nil
    case &amp;quot;( 2 + 4 ) * 10&amp;quot;:
        return 60, nil
    case &amp;quot;( 2 + 4 * 10&amp;quot;:
        return 0, fmt.Errorf(&amp;quot;invalid expression: %s&amp;quot;, expr)
    }
    return 0, nil
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;다음으로 이 스텁을 사용한 테스트 코드를 작성한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;func TestCalculatorProcess(t *testing.T) {
    c := embed.Calculator{Resolver: MathResolverStub{}}
    in := strings.NewReader(`2 + 4 * 10
( 2 + 4 ) * 10
( 2 + 4 * 10`)

    data := []float64{42, 60, 0}
    expectedErr := errors.New(&amp;quot;invalid expression: ( 2 + 4 * 10&amp;quot;)
    for _, d := range data {
        result, err := c.Process(in)
        if err != nil {
            if err.Error() != expectedErr.Error() {
                t.Errorf(&amp;quot;want (%v) got (%v)&amp;quot;, expectedErr, err)
            }
        }
        if result != d {
            t.Errorf(&amp;quot;Expected result %f, got %f&amp;quot;, d, result)
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;MathResolverStub&lt;/code&gt; 를 가지는 &lt;code&gt;Calculator&lt;/code&gt; 를 생성하여 &lt;code&gt;Calculator 의 Process&lt;/code&gt; 메소드를 테스트할 수 있는 코드를 쉽게 작성할 수 있다.&lt;/p&gt;
&lt;p&gt;테스트 코드의 전체 작성은 다음과 같다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ mkdir -p interface/embed
$ vi interface/embed/calculate.go

package embed

import (
    &amp;quot;errors&amp;quot;
    &amp;quot;io&amp;quot;
)

type Calculator struct {
    Resolver MathResolver
}

type MathResolver interface {
    Resolve(expression string) (float64, error)
}

func (c Calculator) Process(r io.Reader) (float64, error) {
    expression, err := readOneLine(r)
    if err != nil {
        return 0, err
    }
    if len(expression) == 0 {
        return 0, errors.New(&amp;quot;no expression to read&amp;quot;)
    }
    answer, err := c.Resolver.Resolve(expression)
    return answer, err
}

func readOneLine(r io.Reader) (string, error) {
    var out []byte
    b := make([]byte, 1)
    for {
        _, err := r.Read(b)
        if err != nil {
            if err == io.EOF {
                return string(out), nil
            }
        }
        if b[0] == &amp;#39;\n&amp;#39; {
            break
        }
        out = append(out, b[0])
    }
    return string(out), nil
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ vi interface/embed/calculate_test.go

package embed_test

import (
    &amp;quot;errors&amp;quot;
    &amp;quot;fmt&amp;quot;
    &amp;quot;strings&amp;quot;
    &amp;quot;testing&amp;quot;

    &amp;quot;github.com/seungkyua/go-test/interface/embed&amp;quot;
)

type MathResolverStub struct{}

func (mr MathResolverStub) Resolve(expr string) (float64, error) {
    switch expr {
    case &amp;quot;2 + 4 * 10&amp;quot;:
        return 42, nil
    case &amp;quot;( 2 + 4 ) * 10&amp;quot;:
        return 60, nil
    case &amp;quot;( 2 + 4 * 10&amp;quot;:
        return 0, fmt.Errorf(&amp;quot;invalid expression: %s&amp;quot;, expr)
    }
    return 0, nil
}

func TestCalculatorProcess(t *testing.T) {
    c := embed.Calculator{Resolver: MathResolverStub{}}
    in := strings.NewReader(`2 + 4 * 10
( 2 + 4 ) * 10
( 2 + 4 * 10`)

    data := []float64{42, 60, 0}
    expectedErr := errors.New(&amp;quot;invalid expression: ( 2 + 4 * 10&amp;quot;)
    for _, d := range data {
        result, err := c.Process(in)
        if err != nil {
            if err.Error() != expectedErr.Error() {
                t.Errorf(&amp;quot;want (%v) got (%v)&amp;quot;, expectedErr, err)
            }
        }
        if result != d {
            t.Errorf(&amp;quot;Expected result %f, got %f&amp;quot;, d, result)
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;실행을 위한 세팅 명령어는 다음과 같다. &lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ go mod init github.com/seungkyua/go-test
$ go mod tidy
$ go mod vendor

$ go work init
$ go work use .&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;go work 는 비지니스 모듈 패키지를 아직 github 에 커밋하지 않은 상태에서 로컬의 최신 패키지 참조를 위해서 필요하다. &lt;/p&gt;
&lt;p&gt;전체 소스 트리는 다음과 같다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ tree .                   
.
├── README.md
├── go.mod
├── go.work
└── interface
    └── embed
        ├── calculate.go
        └── calculate_test.go&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;다음은 테스트 실행 결과이다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ go test interface/embed/calculate_test.go
ok      command-line-arguments  0.390s&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;소스는 아래의 링크에서 다운 받을 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/seungkyua/go-test.git&quot;&gt;https://github.com/seungkyua/go-test.git&lt;/a&gt;&lt;/p&gt;</description>
      <category>프로그래밍/Go</category>
      <category>embedding interface</category>
      <category>golang</category>
      <category>golang test code</category>
      <category>Interface</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/322</guid>
      <comments>https://ahnseungkyu.com/322#entry322comment</comments>
      <pubDate>Mon, 18 Mar 2024 11:47:01 +0900</pubDate>
    </item>
    <item>
      <title>git commit 을 원복하는 방법</title>
      <link>https://ahnseungkyu.com/321</link>
      <description>&lt;p&gt;Git 을 사용하다 보면 저장소에 작업한 commit 을 원복해야 하는 경우가 종종 발생한다. 로컬에서 혼자서 작업한다면 reset 을 사용해서 이전 commit 으로 쉽게 돌릴 수 있지만 이미 원격 저장소에 push 한 상태라면 revert 를 사용하여 이전 commit 을 취소하는 새로운 commit 을 만들어야 한다.&lt;/p&gt;
&lt;p&gt;명료하게 아래 2가지 경우만 생각하면 된다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;아직 원격 저장소에 push 하지 않은 경우 : reset 사용
원격 저장소에 push 한 경우 : revert 사용&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;예외적으로 원격 저장소에 push 한 경우라도 reset 을 사용해서 commit 을 돌릴 수 있다. 하지만 이 때는 원격의 commit 도 같이 삭제하는 작업이 필요하므로 git push 를 할 때 -f 으로 강제 push 를 해야하는 문제가 있어 여러명이 함께 작업하는 경우라면 다른 사람들에게 문제가 발생할 수 있다. (웬만하면 하지 말아야 한다)&lt;/p&gt;
&lt;h1&gt;git reset : 로컬 환경을 특정 commit 위치로 되돌리기&lt;/h1&gt;
&lt;p&gt;아래와 같은 commit log 가 있다고 보자.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git log --oneline -n 5

4e61ca5 (HEAD -&amp;gt; main, origin/main, origin/HEAD) add c.txt
3bd328a add b.txt
be0d36b add a.txt
205a70c Initial commit&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;$ ls -l
total 8
-rw-r--r--@ 1 ask  staff  17  3 14 10:12 README.md
-rw-r--r--@ 1 ask  staff   0  3 14 10:15 a.txt
-rw-r--r--@ 1 ask  staff   0  3 14 10:16 b.txt
-rw-r--r--@ 1 ask  staff   0  3 14 10:17 c.txt&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Initial 커밋에는 &lt;a href=&quot;http://README.md&quot;&gt;README.md&lt;/a&gt; 파일이 추가되어 있고, 이후 각 커밋은 a.txt, b.txt, c.txt 가 추가되어 있는 상태이다. 여기서 a.txt 만 남기고 b.txt, c.txt 를 지운 상태의 돌아가고 싶다고 하면 a.txt 를 추가한 be0d36b add a.txt 커밋 상태로 돌아가면 된다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git reset --hard be0d36b
HEAD is now at be0d36b add a.txt&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;로그와 파일을 조회해 보면 정상적으로 commit 이 이전 상태로 돌아온 것을 알 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git log --oneline -n 5

be0d36b (HEAD -&amp;gt; main) add a.txt
205a70c Initial commit&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;$ ls -l
total 8
-rw-r--r--@ 1 ask  staff  17  3 14 10:12 README.md
-rw-r--r--@ 1 ask  staff   0  3 14 10:15 a.txt&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;reset 명령을 수행하면 커밋이 이전 상태로 돌아간 것이기 때문에 다시 원상태로 돌릴려면 원격 저장소에서 다시 pull 로 가져오면 된다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git pull 

Updating be0d36b..4e61ca5
Fast-forward
 b.txt | 0
 c.txt | 0
 2 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 b.txt
 create mode 100644 c.txt&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;$ git log --oneline -n 5

4e61ca5 (HEAD -&amp;gt; main, origin/main, origin/HEAD) add c.txt
3bd328a add b.txt
be0d36b add a.txt
205a70c Initial commit&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;파일도 원상태로 생성된 것을 알 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ ls -l
total 8
-rw-r--r--@ 1 ask  staff  17  3 14 10:12 README.md
-rw-r--r--@ 1 ask  staff   0  3 14 10:15 a.txt
-rw-r--r--@ 1 ask  staff   0  3 14 10:16 b.txt
-rw-r--r--@ 1 ask  staff   0  3 14 10:17 c.txt&lt;/code&gt;&lt;/pre&gt;&lt;h1&gt;git revert : 이전 commit 제거하는 신규 commit 을 추가&lt;/h1&gt;
&lt;p&gt;현재 커밋 로그는 다음과 같습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git log --oneline -n 5

4e61ca5 (HEAD -&amp;gt; main, origin/main, origin/HEAD) add c.txt
3bd328a add b.txt
be0d36b add a.txt
205a70c Initial commit&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;여기서 3bd328a add b.txt 을 삭제하고 싶을 때 revert 를 할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git revert 3bd328a --no-edit

[main 5a9e9f1] Revert &amp;quot;add b.txt&amp;quot;
 Date: Thu Mar 14 10:51:58 2024 +0900
 1 file changed, 0 insertions(+), 0 deletions(-)
 delete mode 100644 b.txt&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;git log 를 보면 다음과 같다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git log --oneline -n 5

5a9e9f1 (HEAD -&amp;gt; main) Revert &amp;quot;add b.txt&amp;quot;
4e61ca5 (origin/main, origin/HEAD) add c.txt
3bd328a add b.txt
be0d36b add a.txt
205a70c Initial commit&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;5a9e9f1 (HEAD -&amp;gt; main) Revert &amp;quot;add b.txt&amp;quot; 커밋 로그를 보면 revert 하면서 새로운 commit 이 생긴 것을 알 수 있다. reset 과는 다르게 commit 의 순서와 내용은 그대로 살아있으면서 revert 가 추가된 것이기 협업할 때 아무런 문제가 없다.&lt;/p&gt;
&lt;p&gt;리스트를 보면 b.txt 가 삭제되어 다음과 같다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ ls -l
total 8
-rw-r--r--@ 1 ask  staff  17  3 14 10:12 README.md
-rw-r--r--@ 1 ask  staff   0  3 14 10:15 a.txt
-rw-r--r--@ 1 ask  staff   0  3 14 10:38 c.txt&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;revert 와 reset 은 둘 다 파라미터로 commit hash 값을 넣는 것은 동일하나 동작되는 의미는 다르다. reset 은 해당 commit 으로 돌아가기 때문에 그 이후의 commit 은 없어지는 반면에 revert 는 해당 commit 만 제거하는 의미가 있다.&lt;/p&gt;
&lt;h2&gt;revert 를 다시 revert 할 수 있다&lt;/h2&gt;
&lt;p&gt;revert 하여 b.txt 를 삭제한 commit 은 5a9e9f1 (HEAD -&amp;gt; main) Revert &amp;quot;add b.txt&amp;quot; 이다. 이 commit 을 revert 하면 다시 b.txt 파일이 살아날 수 있다. revert 할 때 commit hash 값과 이를 가리키는 HEAD 도 같은 의미이기 때문에 HEAD 를 이용하여 revert 해보자.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git revert HEAD --no-edit

[main d2b2258] Revert &amp;quot;Revert &amp;quot;add b.txt&amp;quot;&amp;quot;
 Date: Thu Mar 14 11:00:28 2024 +0900
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 b.txt&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;$ git log --oneline -n 10

d2b2258 (HEAD -&amp;gt; main) Revert &amp;quot;Revert &amp;quot;add b.txt&amp;quot;&amp;quot;
5a9e9f1 Revert &amp;quot;add b.txt&amp;quot;
4e61ca5 (origin/main, origin/HEAD) add c.txt
3bd328a add b.txt
be0d36b add a.txt
205a70c Initial commit

$ ls -l
total 8
-rw-r--r--@ 1 ask  staff  17  3 14 10:12 README.md
-rw-r--r--@ 1 ask  staff   0  3 14 10:15 a.txt
-rw-r--r--@ 1 ask  staff   0  3 14 11:00 b.txt
-rw-r--r--@ 1 ask  staff   0  3 14 10:38 c.txt&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;여러 commit 을 revert 하기&lt;/h2&gt;
&lt;p&gt;commit hash 값을 나열하면 여러 commit 을 revert 할 수 있다.&lt;/p&gt;
&lt;p&gt;3bd328a add b.txt 커밋과 4e61ca5 (origin/main, origin/HEAD) add c.txt 커밋을 동시에 revert 해보자.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git revert --no-edit be0d36b 4e61ca5

[main 3b6ada1] Revert &amp;quot;add a.txt&amp;quot;
 Date: Thu Mar 14 11:11:07 2024 +0900
 1 file changed, 0 insertions(+), 0 deletions(-)
 delete mode 100644 a.txt
[main bd91431] Revert &amp;quot;add c.txt&amp;quot;
 Date: Thu Mar 14 11:11:07 2024 +0900
 1 file changed, 0 insertions(+), 0 deletions(-)
 delete mode 100644 c.txt&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;$ git log --oneline -n 20

bd91431 (HEAD -&amp;gt; main) Revert &amp;quot;add c.txt&amp;quot;
3b6ada1 Revert &amp;quot;add a.txt&amp;quot;
d2b2258 Revert &amp;quot;Revert &amp;quot;add b.txt&amp;quot;&amp;quot;
5a9e9f1 Revert &amp;quot;add b.txt&amp;quot;
4e61ca5 (origin/main, origin/HEAD) add c.txt
3bd328a add b.txt
be0d36b add a.txt
205a70c Initial commit&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;revert 가 잘 되었지만 각각의 revert 에 대한 커밋이 2개 추가되었다. 3b6ada1 Revert &amp;quot;add a.txt&amp;quot; , bd91431 (HEAD -&amp;gt; main) Revert &amp;quot;add c.txt&amp;quot;&lt;/p&gt;
&lt;h2&gt;여러 revert 를 하나의 commit 으로 만들기&lt;/h2&gt;
&lt;p&gt;앞에서 작업한 2개의 revert commit 을 원상태로 되돌려 보자. 원격으로 push 하지 않았으므로 reset 을 사용해도 문제가 없다.&lt;/p&gt;
&lt;p&gt;여기서는 d2b2258 Revert &amp;quot;Revert &amp;quot;add b.txt&amp;quot;&amp;quot; 커밋으로 돌아가면 된다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git reset --hard d2b2258
HEAD is now at d2b2258 Revert &amp;quot;Revert &amp;quot;add b.txt&amp;quot;&amp;quot;

$ git log --oneline -n 20
d2b2258 (HEAD -&amp;gt; main) Revert &amp;quot;Revert &amp;quot;add b.txt&amp;quot;&amp;quot;
5a9e9f1 Revert &amp;quot;add b.txt&amp;quot;
4e61ca5 (origin/main, origin/HEAD) add c.txt
3bd328a add b.txt
be0d36b add a.txt
205a70c Initial commit

$ ls -l
total 8
-rw-r--r--@ 1 ask  staff  17  3 14 10:12 README.md
-rw-r--r--@ 1 ask  staff   0  3 14 11:19 a.txt
-rw-r--r--@ 1 ask  staff   0  3 14 11:00 b.txt
-rw-r--r--@ 1 ask  staff   0  3 14 11:19 c.txt&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;revert -n 옵션을 사용하면 revert 할 때 index 는 사용하지만 commit 을 하지 않은 상태가 된다. 그러므로 git revert --continue 로 commit 을 진행하면 된다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; $ git revert -n be0d36b 4e61ca5&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;현재 상태를 보면 index 에 저장된 상태임을 알 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git status

On branch main
Your branch is ahead of &amp;#39;origin/main&amp;#39; by 2 commits.
  (use &amp;quot;git push&amp;quot; to publish your local commits)

You are currently reverting commit 4e61ca5.
  (all conflicts fixed: run &amp;quot;git revert --continue&amp;quot;)
  (use &amp;quot;git revert --skip&amp;quot; to skip this patch)
  (use &amp;quot;git revert --abort&amp;quot; to cancel the revert operation)

Changes to be committed:
  (use &amp;quot;git restore --staged &amp;lt;file&amp;gt;...&amp;quot; to unstage)
    deleted:    a.txt
    deleted:    c.txt&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;이제 commit 을 하면서 커밋 메세지를 추가할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git revert --continue&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;메세지는 다음과 같이 입력했다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Revert &amp;quot;add c.txt&amp;quot;
Revert &amp;quot;add a.txt&amp;quot;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;git log 를 보면 커밋은 a4b6156 (HEAD -&amp;gt; main) Revert &amp;quot;add c.txt&amp;quot; Revert &amp;quot;add a.txt&amp;quot; 하나만 생성되었음을 알 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git log --oneline -n 20

a4b6156 (HEAD -&amp;gt; main) Revert &amp;quot;add c.txt&amp;quot; Revert &amp;quot;add a.txt&amp;quot;
d2b2258 Revert &amp;quot;Revert &amp;quot;add b.txt&amp;quot;&amp;quot;
5a9e9f1 Revert &amp;quot;add b.txt&amp;quot;
4e61ca5 (origin/main, origin/HEAD) add c.txt
3bd328a add b.txt
be0d36b add a.txt
205a70c Initial commit

$ ls -l
total 8
-rw-r--r--@ 1 ask  staff  17  3 14 10:12 README.md
-rw-r--r--@ 1 ask  staff   0  3 14 11:00 b.txt&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;다음 설명을 위해서 다시 reset 을 하자. commit 하나만 뒤로가면 되므로 HEAD^1 을 사용해도 된다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git reset --hard HEAD^1&lt;/code&gt;&lt;/pre&gt;&lt;h1&gt;git revert: merge commit 에 대한 revert 하기&lt;/h1&gt;
&lt;p&gt;현재 커밋 로그는 다음과 같다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git log --oneline -n 20

d2b2258 (HEAD -&amp;gt; main) Revert &amp;quot;Revert &amp;quot;add b.txt&amp;quot;&amp;quot;
5a9e9f1 Revert &amp;quot;add b.txt&amp;quot;
4e61ca5 (origin/main, origin/HEAD) add c.txt
3bd328a add b.txt
be0d36b add a.txt
205a70c Initial commit

$ ls -l
total 8
-rw-r--r--@ 1 ask  staff  17  3 14 10:12 README.md
-rw-r--r--@ 1 ask  staff   0  3 14 11:34 a.txt
-rw-r--r--@ 1 ask  staff   0  3 14 11:00 b.txt
-rw-r--r--@ 1 ask  staff   0  3 14 11:34 c.txt&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;git push 를 해서 원격 저장소에 저장한 다음 merge commit 을 만드는 작업을 한다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git push

$ git switch -c merge_branch
$ touch d.txt
$ git add -A
$ git commit -m &amp;quot;add d.txt&amp;quot;

$ git push --set-upstream origin merge_branch &lt;/code&gt;&lt;/pre&gt;&lt;p&gt;github 에서 pr 을 올리고 main branch 로 merge 한다.&lt;/p&gt;
&lt;p&gt;이후에 main branch 에서 pull 한 다음에 커밋 로그를 보면 다음과 같다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git switch main

$ git pull

$ ls -l
total 8
-rw-r--r--@ 1 ask  staff  17  3 14 10:12 README.md
-rw-r--r--@ 1 ask  staff   0  3 14 11:34 a.txt
-rw-r--r--@ 1 ask  staff   0  3 14 11:00 b.txt
-rw-r--r--@ 1 ask  staff   0  3 14 11:34 c.txt
-rw-r--r--@ 1 ask  staff   0  3 14 11:44 d.txt

$ git log
commit 409bf49c1b05a39609207da03f28f782c3b8a0b9 (HEAD -&amp;gt; main, origin/main, origin/HEAD)
Merge: d2b2258 9fdd01f
Author: Seungkyu Ahn &amp;lt;seungkyua@gmail.com&amp;gt;
Date:   Thu Mar 14 11:42:42 2024 +0900

    Merge pull request #1 from seungkyua/merge_branch

    add d.txt

commit 9fdd01fb9b0eff870093f15e246c998ae1fac452 (origin/merge_branch, merge_branch)
Author: Seungkyu Ahn &amp;lt;seungkyua@gmail.com&amp;gt;
Date:   Thu Mar 14 11:40:46 2024 +0900

    add d.txt

commit d2b22584cb8108cd7bc1eaaaa5775e1f19f330fa
Author: Seungkyu Ahn &amp;lt;seungkyua@gmail.com&amp;gt;
Date:   Thu Mar 14 11:00:28 2024 +0900

    Revert &amp;quot;Revert &amp;quot;add b.txt&amp;quot;&amp;quot;

    This reverts commit 5a9e9f14b9b7403ad5aef1df83d14f1a1d4938dd.&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;첫번째 커밋 로그를 보면 Merge: d2b2258 9fdd01f 와 같이 Merge 임을 알 수 있다. merge 의 경우 revert 는 -m 옵션으로 첫번재 hash 값을 적용할지 두번째 hash 값을 적용할지를 결정해 주어야 한다.&lt;/p&gt;
&lt;p&gt;merge 바로 이전 커밋인 d2b2258 으로 revert 할 것이기 때문에 첫번재를 선택해 준다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git revert 409bf49c -m 1

[main d53c40d] Revert &amp;quot;Merge pull request #1 from seungkyua/merge_branch&amp;quot;
 1 file changed, 0 insertions(+), 0 deletions(-)
 delete mode 100644 d.txt&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;로그를 보면 revert 되었음을 알 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git log --oneline -n 20

d53c40d (HEAD -&amp;gt; main) Revert &amp;quot;Merge pull request #1 from seungkyua/merge_branch&amp;quot;
409bf49 (origin/main, origin/HEAD) Merge pull request #1 from seungkyua/merge_branch
9fdd01f (origin/merge_branch, merge_branch) add d.txt
d2b2258 Revert &amp;quot;Revert &amp;quot;add b.txt&amp;quot;&amp;quot;
5a9e9f1 Revert &amp;quot;add b.txt&amp;quot;
4e61ca5 add c.txt
3bd328a add b.txt
be0d36b add a.txt
205a70c Initial commit&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;$ ls -l
total 8
-rw-r--r--@ 1 ask  staff  17  3 14 10:12 README.md
-rw-r--r--@ 1 ask  staff   0  3 14 11:34 a.txt
-rw-r--r--@ 1 ask  staff   0  3 14 11:00 b.txt
-rw-r--r--@ 1 ask  staff   0  3 14 11:34 c.txt&lt;/code&gt;&lt;/pre&gt;&lt;h1&gt;patch 로 commit 삭제하기&lt;/h1&gt;
&lt;p&gt;commit 에 대한 패치 파일을 만들고 -R 옵션을 사용하여 패치 파일을 apply 하면 해당 패치 파일에 대한 commit 을 삭제할 수 있다.&lt;/p&gt;
&lt;p&gt;현재 커밋 로그는 다음과 같다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git log --oneline -n 20

d53c40d (HEAD -&amp;gt; main, origin/main, origin/HEAD) Revert &amp;quot;Merge pull request #1 from seungkyua/merge_branch&amp;quot;
409bf49 Merge pull request #1 from seungkyua/merge_branch
9fdd01f (origin/merge_branch, merge_branch) add d.txt
d2b2258 Revert &amp;quot;Revert &amp;quot;add b.txt&amp;quot;&amp;quot;
5a9e9f1 Revert &amp;quot;add b.txt&amp;quot;
4e61ca5 add c.txt
3bd328a add b.txt
be0d36b add a.txt
205a70c Initial commit&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;$ ls -l
total 8
-rw-r--r--@ 1 ask  staff  17  3 14 10:12 README.md
-rw-r--r--@ 1 ask  staff   0  3 14 11:34 a.txt
-rw-r--r--@ 1 ask  staff   0  3 14 11:00 b.txt
-rw-r--r--@ 1 ask  staff   0  3 14 11:34 c.txt&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;여기서 3bd328a add b.txt 에 대한 패치 파일을 만들어 보자.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git format-patch -1 3bd328a&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;아래와 같이 하나의 0001-add-b.txt.patch 패치 파일이 생성되었다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ ls -l
total 16
-rw-r--r--@ 1 ask  staff  368  3 14 13:46 0001-add-b.txt.patch
-rw-r--r--@ 1 ask  staff   17  3 14 10:12 README.md
-rw-r--r--@ 1 ask  staff    0  3 14 11:34 a.txt
-rw-r--r--@ 1 ask  staff    0  3 14 11:00 b.txt
-rw-r--r--@ 1 ask  staff    0  3 14 11:34 c.txt&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;이제 -R 옵션을 적용하여 patch 파일을 적용하자. -R 옵션은 reverse 로 패치 파일을 삭제하는 역할을 한다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git apply -R 0001-add-b.txt.patch&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;상태를 보면 다음과 같다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git status
On branch main
Your branch is up to date with &amp;#39;origin/main&amp;#39;.

Changes not staged for commit:
  (use &amp;quot;git add/rm &amp;lt;file&amp;gt;...&amp;quot; to update what will be committed)
  (use &amp;quot;git restore &amp;lt;file&amp;gt;...&amp;quot; to discard changes in working directory)
    deleted:    b.txt

Untracked files:
  (use &amp;quot;git add &amp;lt;file&amp;gt;...&amp;quot; to include in what will be committed)
    0001-add-b.txt.patch

no changes added to commit (use &amp;quot;git add&amp;quot; and/or &amp;quot;git commit -a&amp;quot;)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;파일 리스트를 보면 b.txt 가 삭제되어 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ ls -l
total 16
-rw-r--r--@ 1 ask  staff  368  3 14 13:46 0001-add-b.txt.patch
-rw-r--r--@ 1 ask  staff   17  3 14 10:12 README.md
-rw-r--r--@ 1 ask  staff    0  3 14 11:34 a.txt
-rw-r--r--@ 1 ask  staff    0  3 14 11:34 c.txt&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;이제 삭제된 파일을 stage 에 add 한 후 commit 한다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git add b.txt
$ git commit -m &amp;quot;-R patch to b.txt&amp;quot;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;커밋 로그를 보면 b.txt 가 삭제된 것을 알 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git log --oneline -n 20

44e55ce (HEAD -&amp;gt; main) -R patch to b.txt
d53c40d (origin/main, origin/HEAD) Revert &amp;quot;Merge pull request #1 from seungkyua/merge_branch&amp;quot;
409bf49 Merge pull request #1 from seungkyua/merge_branch
9fdd01f (origin/merge_branch, merge_branch) add d.txt
d2b2258 Revert &amp;quot;Revert &amp;quot;add b.txt&amp;quot;&amp;quot;
5a9e9f1 Revert &amp;quot;add b.txt&amp;quot;
4e61ca5 add c.txt
3bd328a add b.txt
be0d36b add a.txt
205a70c Initial commit&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;패치 파일이 있으니 apply 로 해당 commit 을 다시 살려보자. 실제로는 commit 을 살리는 것이 아니라 해당 commit 의 변경된 파일을 되살리는 것이다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git apply 0001-add-b.txt.patch
$ git add b.txt
$ git commit -m &amp;quot;restore b.txt using patch&amp;quot;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;아래 디렉토리에 b.txt 가 살아난 것을 알 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ ls -l
total 16
-rw-r--r--@ 1 ask  staff  368  3 14 13:46 0001-add-b.txt.patch
-rw-r--r--@ 1 ask  staff   17  3 14 10:12 README.md
-rw-r--r--@ 1 ask  staff    0  3 14 11:34 a.txt
-rw-r--r--@ 1 ask  staff    0  3 14 14:03 b.txt
-rw-r--r--@ 1 ask  staff    0  3 14 11:34 c.txt&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;필요없는 패치 파일은 삭제한다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ rm 0001-add-b.txt.patch&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;여러 커밋을 하나의 패치 파일로 만들기&lt;/h2&gt;
&lt;p&gt;현재 커밋 로그는 아래와 같다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git log --oneline -n 20

9aced43 (HEAD -&amp;gt; main, origin/main, origin/HEAD) restore b.txt using patch
44e55ce -R patch to b.txt
d53c40d Revert &amp;quot;Merge pull request #1 from seungkyua/merge_branch&amp;quot;
409bf49 Merge pull request #1 from seungkyua/merge_branch
9fdd01f (origin/merge_branch, merge_branch) add d.txt
d2b2258 Revert &amp;quot;Revert &amp;quot;add b.txt&amp;quot;&amp;quot;
5a9e9f1 Revert &amp;quot;add b.txt&amp;quot;
4e61ca5 add c.txt
3bd328a add b.txt
be0d36b add a.txt
205a70c Initial commit&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;여기서 be0d36b add a.txt , 3bd328a add b.txt, 4e61ca5 add c.txt 을 하나의 패치 파일로 만들고 싶으면 다음과 같이 하면 된다.&lt;/p&gt;
&lt;p&gt;시작 hash값 ^.. 종료 hash값&lt;/p&gt;
&lt;p&gt;만약 .. 만 사용하면 시간 hash값은 포함되지 않는다(여기서는 be0d36b add a.txt 커밋이 포함되지 않는다). 그러므로 시작 hash값을 포함하고 싶으면 ^.. 을 사용해야 한다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git format-patch be0d36b^..4e61ca5 --stdout &amp;gt; commits.patch&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;한가지 더 설명하자면 format-patch 는 커밋 히스토리까지 파일에 포함 시킨다. diff 를 사용하면 커밋 히스토리를 제외할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ git diff be0d36b^..4e61ca5 &amp;gt; diff.patch&lt;/code&gt;&lt;/pre&gt;</description>
      <category>git &amp;amp; github</category>
      <category>git diff</category>
      <category>git format-patch</category>
      <category>git reset</category>
      <category>git revert</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/321</guid>
      <comments>https://ahnseungkyu.com/321#entry321comment</comments>
      <pubDate>Thu, 14 Mar 2024 14:33:54 +0900</pubDate>
    </item>
    <item>
      <title>이것만 공부하세요 - helm chart 만드는 법</title>
      <link>https://ahnseungkyu.com/320</link>
      <description>&lt;p&gt;helm chart 를 만들기 위해서는 여러 기능들을 알아야 하지만 그 중에서 가장 많이 쓰고 헷갈리는 기능에 대해서 살펴 본다.&lt;/p&gt;
&lt;p&gt;기본적으로 실습할 수 있는 환경을 먼저 만들고 하나씩 공부해 본다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ helm create flow-control
$ cd flow-control&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;yaml 형태의 출력을 확인해 본다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ helm template .
---
# Source: flow-control/templates/serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: release-name-flow-control
  labels:
    helm.sh/chart: flow-control-0.1.0
    app.kubernetes.io/name: flow-control
    app.kubernetes.io/instance: release-name
    app.kubernetes.io/version: &amp;quot;1.16.0&amp;quot;
    app.kubernetes.io/managed-by: Helm
automountServiceAccountToken: true
---
# Source: flow-control/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: release-name-flow-control
  labels:
    helm.sh/chart: flow-control-0.1.0
    app.kubernetes.io/name: flow-control
    app.kubernetes.io/instance: release-name
    app.kubernetes.io/version: &amp;quot;1.16.0&amp;quot;
    app.kubernetes.io/managed-by: Helm
spec:
  type: ClusterIP
  ports:
    - port: 80
      targetPort: http
      protocol: TCP
      name: http
  selector:
    app.kubernetes.io/name: flow-control
    app.kubernetes.io/instance: release-name
---
# Source: flow-control/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: release-name-flow-control
  labels:
    helm.sh/chart: flow-control-0.1.0
    app.kubernetes.io/name: flow-control
    app.kubernetes.io/instance: release-name
    app.kubernetes.io/version: &amp;quot;1.16.0&amp;quot;
    app.kubernetes.io/managed-by: Helm
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: flow-control
      app.kubernetes.io/instance: release-name
  template:
    metadata:
      labels:
        helm.sh/chart: flow-control-0.1.0
        app.kubernetes.io/name: flow-control
        app.kubernetes.io/instance: release-name
        app.kubernetes.io/version: &amp;quot;1.16.0&amp;quot;
        app.kubernetes.io/managed-by: Helm
    spec:
      serviceAccountName: release-name-flow-control
      securityContext:
        {}
      containers:
        - name: flow-control
          securityContext:
            {}
          image: &amp;quot;nginx:1.16.0&amp;quot;
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 80
              protocol: TCP
          livenessProbe:
            httpGet:
              path: /
              port: http
          readinessProbe:
            httpGet:
              path: /
              port: http
          resources:
            {}
---
# Source: flow-control/templates/tests/test-connection.yaml
apiVersion: v1
kind: Pod
metadata:
  name: &amp;quot;release-name-flow-control-test-connection&amp;quot;
  labels:
    helm.sh/chart: flow-control-0.1.0
    app.kubernetes.io/name: flow-control
    app.kubernetes.io/instance: release-name
    app.kubernetes.io/version: &amp;quot;1.16.0&amp;quot;
    app.kubernetes.io/managed-by: Helm
  annotations:
    &amp;quot;helm.sh/hook&amp;quot;: test
spec:
  containers:
    - name: wget
      image: busybox
      command: [&amp;#39;wget&amp;#39;]
      args: [&amp;#39;release-name-flow-control:80&amp;#39;]
  restartPolicy: Never&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;제대로 출력된다면 필요없는 파일은 삭제하고 초기화 하자.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ rm -rf template/*
$ cat /dev/null &amp;gt; values.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;0. yaml 은 들여 쓰기가 중요하다.&lt;/h1&gt;
&lt;p&gt;가장 간단한 configmap 을 만들어서 value 값을 출력한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ values.yaml
---
favorite:
  drink: coffee
  food: pizza

$ vi template/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: &amp;quot;Hello World&amp;quot;
  drink: {{ .Values.favorite.drink | default &amp;quot;tea&amp;quot; | quote }}
  food: {{ .Values.favorite.food | upper | quote }}
  {{ if eq .Values.favorite.drink &amp;quot;coffee&amp;quot; }}
    mug: &amp;quot;true&amp;quot;
  {{ end }}

$ helm template .
--- output ---
Error: YAML parse error on flow-control/templates/configmap.yaml: error converting YAML to JSON: yaml: line 8: did not find expected key

Use --debug flag to render out invalid YAML&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;template 을 제너레이션하면 에러가 발생한다. 왜 그럴까?&lt;/p&gt;
&lt;p&gt;configmap.yaml 에 &lt;code&gt;mug: &amp;quot;true&amp;quot;&lt;/code&gt; 가 2칸 들여써 있어서 발생하는 에러이다. 이런 에러를 조심하면서 아래 실습을 해보자. &lt;/p&gt;
&lt;h1&gt;1. 조건문과 빈라인 없애기&lt;/h1&gt;
&lt;p&gt;configmap.yaml 을 수정해서 제대로 yaml 을 생성해 보자.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ vi template/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: &amp;quot;Hello World&amp;quot;
  drink: {{ .Values.favorite.drink | default &amp;quot;tea&amp;quot; | quote }}
  food: {{ .Values.favorite.food | upper | quote }}
  {{ if eq .Values.favorite.drink &amp;quot;coffee&amp;quot; }}
  mug: &amp;quot;true&amp;quot;
  {{ end }}

$ helm template .
---
# Source: flow-control/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: release-name-configmap
data:
  myvalue: &amp;quot;Hello World&amp;quot;
  drink: &amp;quot;coffee&amp;quot;
  food: &amp;quot;PIZZA&amp;quot;
                    --------------&amp;gt; 빈라인 발생한다.
  mug: &amp;quot;true&amp;quot;
                    --------------&amp;gt; 빈라인 발생한다.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;.Release.Name&lt;/code&gt;  은 helm 으로 설치할 때 파라미터로 넘기는 값인데 여기서는 설치가 아니므로 기본 값인 &lt;code&gt;release-name&lt;/code&gt; 으로 치환 되었고, &lt;code&gt;.Values.favorite.drink&lt;/code&gt; 는 values.yaml 에 지정한 키값으로 그에 해당하는 밸류 값이 제너레이트 될 때 출력된다.&lt;/p&gt;
&lt;p&gt;함수의 연속적 사용은 &lt;code&gt;|&lt;/code&gt; 라인으로 호출 가능하며 &lt;code&gt;default&lt;/code&gt; 는 키에 대한 값이 없을 때, &lt;code&gt;quote&lt;/code&gt; 는 값을 &lt;code&gt;&amp;quot;&lt;/code&gt; 으로 묶을 때 &lt;code&gt;upper&lt;/code&gt; 는 값을 대문자로 변환할 때 사용하는 내장 함수이다.&lt;/p&gt;
&lt;p&gt;비교 구문은 &lt;code&gt;if eq 값1 값2&lt;/code&gt; 와 같이 사용할 수 있다.&lt;/p&gt;
&lt;p&gt;출력하지 않는 곳에서는 빈라인이 발생하는데 이 부분을 다음과 같이 없애 줄 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;{{ if eq .Values.favorite.drink &amp;quot;coffee&amp;quot; }}mug: &amp;quot;true&amp;quot;{{ end }}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;하지만 가독성이 떨어지므로 &lt;code&gt;{{-&lt;/code&gt; 와 같이 표현하면 빈라인이 없어지면서 윗라인에 나란히 붙는 것과 같은 효과를 낼 수 있다. &lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;  {{- if eq .Values.favorite.drink &amp;quot;coffee&amp;quot; }}
  mug: &amp;quot;true&amp;quot;
  {{- end }}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;다시 yaml 을 생성해 보면 아래와 같이 빈라인이 없어졌음을 알 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ helm template .
---
# Source: flow-control/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: release-name-configmap
data:
  myvalue: &amp;quot;Hello World&amp;quot;
  drink: &amp;quot;coffee&amp;quot;
  food: &amp;quot;PIZZA&amp;quot;
  mug: &amp;quot;true&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;조건문 대신 다음과 같이 &lt;code&gt;with&lt;/code&gt; 를 사용하여 조건문과 키밸류 스쿱을 지정할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;### configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: &amp;quot;Hello World&amp;quot;
  {{- with .Values.hobby }}
  sports: {{ .sports }}
  {{- end }}

### values.yaml
hobby:
  sports: golf&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;with 와 함께 사용한 키는 해당 키에 대한 값이 있을 때만 &lt;code&gt;with ~ end&lt;/code&gt; 로 감싼 구문이 출력된다.  또한 감싼 구문 안에서는 스쿱이 재정의되어 hobby 아래의 키인 sports 를 &lt;code&gt;.sports&lt;/code&gt; 로 바로 사용할 수 있다.&lt;/p&gt;
&lt;p&gt;yaml 을 생성하면 다음과 같은 결과가 나온다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ helm template .

# Source: flow-control/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: release-name-configmap
data:
  myvalue: &amp;quot;Hello World&amp;quot;
  sports: golf&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;만약 values 에 sports 를 없애면 아래와 같이 출력되지 않는다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;### values.yaml
hobby: {}

# Source: flow-control/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: release-name-configmap
data:
  myvalue: &amp;quot;Hello World&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;hobby 아래의 키는 키밸류인 디셔너리 타입을 넣기 때문에  아래의 값을 모두 없애기 위해서&lt;code&gt;{}&lt;/code&gt; 빈 딕셔너리 값으로 지정했다. 만약 아래의 값이 리스트라면 &lt;code&gt;[]&lt;/code&gt; 와 같이 빈 리스트 값을 지정할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;with ~ end&lt;/code&gt; 로 감싼 구문에서 &lt;code&gt;root&lt;/code&gt; 영역의 value 를 활용하고 싶을 수 있다. 이 때는 &lt;code&gt;$&lt;/code&gt; 를 붙혀서 영역을 최상위 root 로 접근할 수 있다. 아래 예제에서 &lt;code&gt;$.Release.Name&lt;/code&gt; 을 참고한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;### configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: &amp;quot;Hello World&amp;quot;
  {{- with .Values.hobby }}
  sports: {{ .sports }}
  release: {{ $.Release.Name }}
  {{- end }}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;YAML&lt;/code&gt; 은 &lt;code&gt;JSON&lt;/code&gt; 의 수퍼셋이기 때문에 JSON 으로 표현하여 가독성을 높혀줄 수 도 있다. pod 를 만들 때 yaml 에 &lt;code&gt;args&lt;/code&gt; 를 추가할 수 있는데. 이 때 JSON 을 쓰면 읽기에 편하다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;args:
  - &amp;quot;--dirname&amp;quot;
  - &amp;quot;/foo&amp;quot;  &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위의 내용은 JSON 으로 아래와 같이 바꿀 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;args: [&amp;quot;--dirname&amp;quot;, &amp;quot;/foo&amp;quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;2. range 함수를 이용한 반복문&lt;/h1&gt;
&lt;p&gt;range 를 이용하여 반복문을 사용할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;### values.yaml
pizzaToppings:
  - mushrooms
  - cheese
  - peppers
  - onions

### configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  toppings: |-
    {{- range .Values.pizzaToppings }}
    - {{ . | title | quote }}
    {{- end }}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;pizzaToppings 의 값은 리스트이다(&lt;code&gt;-&lt;/code&gt; 기호가 값으로 붙었기 때문에 리스트임을 알 수 있다). 리스트로 값을 가져와서 출력하기 때문에 아래와 같은 결과가 나온다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# Source: flow-control/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: release-name-configmap
data:
  toppings: |-
    - &amp;quot;Mushrooms&amp;quot;
    - &amp;quot;Cheese&amp;quot;
    - &amp;quot;Peppers&amp;quot;
    - &amp;quot;Onions&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;한가지 &lt;code&gt;yaml&lt;/code&gt; 에서 toppings: 의 뒤에 따라온 &lt;code&gt;|-&lt;/code&gt; 기호의 의미는 멀티 라인 스트링을 받겠다는 의미이다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;tuple&lt;/code&gt; 을 사용하여 튜플로 만들어 쓸 수 도 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;### configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  sizes: |-
    {{- range tuple &amp;quot;small&amp;quot; &amp;quot;medium&amp;quot; &amp;quot;large&amp;quot; }}
    - {{ . }}
    {{- end }}

### 출력 결과
# Source: flow-control/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: release-name-configmap
data:
  sizes: |-
    - small
    - medium
    - large&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;$&lt;/code&gt; 와 &lt;code&gt;:=&lt;/code&gt; 를 이용하여 변수를 지정할 수 있다. 아래는 리스트에서 받은 값을 index 변수와 value 변수로 받아서 활용하는 부분이다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;### values.yaml
pizzaToppings:
  - mushrooms
  - cheese
  - peppers
  - onions

### configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  toppings: |-
    {{- range $index, $value := .Values.pizzaToppings }}
    - {{ $index }}: {{ $value }}
    {{- end }}

# Source: flow-control/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: release-name-configmap
data:
  toppings: |-
    - 0: mushrooms
    - 1: cheese
    - 2: peppers
    - 3: onions&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;map 값을 변수로 받아 처리할 수 도 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;### values.yaml
favorite:
  drink: coffee
  food: pizza

### configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  favorite: |-
    {{- range $key, $value := .Values.favorite }}
    {{ $key }}: {{ $value }}
    {{- end }}

# Source: flow-control/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: release-name-configmap
data:
  favorite: |-
    drink: coffee
    food: pizza&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;3. template 선언 및 활용&lt;/h1&gt;
&lt;p&gt;부분적으로 사용자 정의 template 을 만들어서 활용 할 수 있다.&lt;/p&gt;
&lt;h2&gt;define - tempate 사용&lt;/h2&gt;
&lt;p&gt;template 은 &lt;code&gt;define&lt;/code&gt; 으로 선언하고 &lt;code&gt;tempate&lt;/code&gt; 으로 활용할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;### configmap.yaml
{{- define &amp;quot;mychart.labels&amp;quot; }}
  labels:
    generator: helm
    date: {{ now | htmlDate }}
{{- end }}
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
  {{- template &amp;quot;mychart.labels&amp;quot; }}
data:
  myvalue: &amp;quot;Hello World&amp;quot;

# Source: flow-control/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: release-name-configmap
  labels:
    generator: helm
    date: 2023-10-31
data:
  myvalue: &amp;quot;Hello World&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위의 예제는 labels 에 &lt;code&gt;date: 날짜&lt;/code&gt;  를 추가로 넣는 부분을 &lt;code&gt;named template&lt;/code&gt; 을 만들어서 사용한 예제이다.&lt;/p&gt;
&lt;p&gt;chat 를 만들 때 configmap.yaml 과 같이 쿠버네티스 리소스들은 template 디렉토리 아래에 위치 시킨다고 했다. 이 디렉토리에 위치한 yaml 파일들은 자동으로 렌더링에 포함되는데 &lt;code&gt;_&lt;/code&gt; 로 시작하는 파일은 렌더링에서 제외한다. 그래서 보통 define 으로 정의한 함수들은 &lt;code&gt;_helper.tpl&lt;/code&gt; 파일을 만들어서 이곳에 위치 시킨다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;define&lt;/code&gt; 으로 정의된 named template (함수) 은 &lt;code&gt;template&lt;/code&gt; 으로 호출되기 전까지는 렌더링 되지 않는다. 이제 이 함수를 _helper.tpl 파일로 옮겨서 렌더링 결과를 살펴보자.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# _helper.tpl
{{- define &amp;quot;mychart.labels&amp;quot; }}
  labels:
    generator: helm
    date: {{ now | htmlDate }}
{{- end }}

# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
  {{- template &amp;quot;mychart.labels&amp;quot; }}
data:
  myvalue: &amp;quot;Hello World&amp;quot;

# Source: flow-control/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: release-name-configmap
  labels:
    generator: helm
    date: 2023-10-31
data:
  myvalue: &amp;quot;Hello World&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위의 예제에서 define 함수 내에서 &lt;code&gt;.Values&lt;/code&gt; 와 같이 value 를 가져오는 것은 하지 않았다. 아래와 같이 &lt;code&gt;{{ .Chart.Name }}&lt;/code&gt; 을 사용한다면 위의 방식으로는 값을 표현할 수 없다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# _helper.tpl
{{- define &amp;quot;mychart.labels&amp;quot; }}
  labels:
    generator: helm
    date: {{ now | htmlDate }}
    chart: {{ .Chart.Name }}
    version: {{ .Chart.Version }}
{{- end }} 

# Source: flow-control/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: release-name-configmap
  labels:
    generator: helm
    date: 2023-10-31
    chart:
    version:
data:
  myvalue: &amp;quot;Hello World&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이는 template 으로 호출할 때 뒤에 value 를 보내지 않아서 발생한 부분이다. 즉 &lt;code&gt;{{- template &amp;quot;mychart.labels&amp;quot; . }}&lt;/code&gt; 과 같이 마지막에 현재의 scope value 인 &lt;code&gt;.&lt;/code&gt; 을 넘겨 주어야 제대로 된 값이 출력된다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
  {{- template &amp;quot;mychart.labels&amp;quot; . }}
data:
  myvalue: &amp;quot;Hello World&amp;quot;

# Source: flow-control/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: release-name-configmap
  labels:
    generator: helm
    date: 2023-10-31
    chart: flow-control
    version: 0.1.0&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;define - include 사용&lt;/h2&gt;
&lt;p&gt;template 은 있는 그대로 output 을 보여주기 때문에 들여쓰기의 문제가 있을 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# _helper.tlp
{{- define &amp;quot;mychart.app&amp;quot; -}}
app_name: {{ .Chart.Name }}
app_version: &amp;quot;{{ .Chart.Version }}&amp;quot;
{{- end -}}

# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
  labels:
    {{ template &amp;quot;mychart.app&amp;quot; . }}
data:
  myvalue: &amp;quot;Hello World&amp;quot;
{{ template &amp;quot;mychart.app&amp;quot; . }}

# Source: flow-control/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: release-name-configmap
  labels:
    app_name: flow-control
app_version: &amp;quot;0.1.0&amp;quot;
data:
  myvalue: &amp;quot;Hello World&amp;quot;
app_name: flow-control
app_version: &amp;quot;0.1.0&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;app_name 과 app_version 이 출력된 것을 보면 define 에 정의된 들여쓰기 대로 그대로 출력되어 원하는 대로 출력되지 않는다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;include&lt;/code&gt; 와 &lt;code&gt;nindent&lt;/code&gt; 를 사용하면 원하는 들여쓰기가 가능하다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
  labels:
    {{ template &amp;quot;mychart.app&amp;quot; . }}
data:
  myvalue: &amp;quot;Hello World&amp;quot;
{{ template &amp;quot;mychart.app&amp;quot; . }}

# Source: flow-control/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: release-name-configmap
  labels:
    app_name: flow-control
    app_version: &amp;quot;0.1.0&amp;quot;
data:
  myvalue: &amp;quot;Hello World&amp;quot;
  app_name: flow-control
  app_version: &amp;quot;0.1.0&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;끝으로 &lt;code&gt;helm install&lt;/code&gt; 할 때 들여쓰기가 잘못되면 렌더링 오류가 나서 최종 결과를 볼 수 가 없다. 이를 해결할 수 있는 옵션이 &lt;code&gt;-disable-openapi-validation&lt;/code&gt; 이다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ helm install --dry-run --disable-openapi-validation mychart ./&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Kubernetes</category>
      <category>chart</category>
      <category>helm</category>
      <category>Helm chart</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/320</guid>
      <comments>https://ahnseungkyu.com/320#entry320comment</comments>
      <pubDate>Mon, 20 Nov 2023 12:35:58 +0900</pubDate>
    </item>
    <item>
      <title>springboot 컨테이너 이미지 사이즈 경량화 방법</title>
      <link>https://ahnseungkyu.com/319</link>
      <description>&lt;p&gt;스프링 부트 기반으로 개발한 어플리케이션을 컨테이너 이미지로 만들 때 이미지 사이즈를 줄이는 방법에 대해서 알아보자.&lt;/p&gt;
&lt;p&gt;먼저, sample source 를 다운 받는다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ git clone https://github.com/seungkyua/springboot-docker.git
$ cd springboot-docker&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;다운 받은 소스에서 mvn 으로 package 를 빌드한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ mvn package&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;빌드 후에 소스의 디렉토리 구조는 다음과 같다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ tree . -L 2
.
├── LICENSE
├── README.md
├── docker
│   ├── Dockerfile
│   ├── Dockerfile2
│   └── Dockerfile3
├── logs
│   └── access_log.log
├── pom.xml
├── scripts
│   └── run.sh
├── src
│   └── main
├── target
│   ├── classes
│   ├── example-0.0.1-SNAPSHOT.jar
│   ├── example-0.0.1-SNAPSHOT.jar.original
│   ├── generated-sources
│   ├── maven-archiver
│   └── maven-status
└── work
    └── Tomcat&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;오늘은 자바 소스는 상관없이 도커 이미지 빌드에 대해서만 설명하므로 Dockerfile 만 살펴보자.&lt;/p&gt;
&lt;h1&gt;컨테이너 이미지 만들기 - 기본편&lt;/h1&gt;
&lt;p&gt;docker/Dockerfile2  을 보면 아래와 같다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;FROM openjdk:17.0.2-jdk-slim
MAINTAINER Ahn Seungkyu

ARG JAR_FILE=example-0.0.1-SNAPSHOT.jar

RUN mkdir -p /app
WORKDIR /app

COPY target/${JAR_FILE} /app/app.jar
COPY scripts/run.sh .
ENTRYPOINT [&amp;quot;./run.sh&amp;quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;base 이미지로 &lt;code&gt;openjdk:17.0.2-jdk-slim&lt;/code&gt; 이미지를 사용하였고 target 아래의 빌드된 jar 파일을 복사하여 실행하는 방법이다.&lt;/p&gt;
&lt;p&gt;실행 명령어는 &lt;code&gt;scripts/run.sh&lt;/code&gt; 파일을 보면 알 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;#!/bin/sh

java ${JAVA_OPTS} -jar app.jar ${@}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;JAVA_OPTS 는 환경 변수 이므로 컨테이너를 실행할 때 해당 값을 전달하는 것이 가능하다.&lt;/p&gt;
&lt;p&gt;이제 컨테이너 이미지를 빌드하면 그 사이즈는 다음과 같다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ docker build -t seungkyua/springboot-docker -f docker/Dockerfile2 .

------- output -----------
[+] Building 2.6s (11/11) FINISHED                                                                                                                                                                                                               docker:desktop-linux
 =&amp;gt; [internal] load build definition from Dockerfile2                                                                                                                                                                                                            0.0s
 =&amp;gt; =&amp;gt; transferring dockerfile: 442B                                                                                                                                                                                                                             0.0s
 =&amp;gt; [internal] load .dockerignore                                                                                                                                                                                                                                0.0s
 =&amp;gt; =&amp;gt; transferring context: 2B                                                                                                                                                                                                                                  0.0s
 =&amp;gt; [internal] load metadata for docker.io/library/openjdk:17.0.2-jdk-slim                                                                                                                                                                                       2.2s
 =&amp;gt; [auth] library/openjdk:pull token for registry-1.docker.io                                                                                                                                                                                                   0.0s
 =&amp;gt; CACHED [1/5] FROM docker.io/library/openjdk:17.0.2-jdk-slim@sha256:aaa3b3cb27e3e520b8f116863d0580c438ed55ecfa0bc126b41f68c3f62f9774                                                                                                                          0.0s
 =&amp;gt; [internal] load build context                                                                                                                                                                                                                                0.0s
 =&amp;gt; =&amp;gt; transferring context: 291B                                                                                                                                                                                                                                0.0s
 =&amp;gt; [2/5] RUN mkdir -p /app                                                                                                                                                                                                                                      0.1s
 =&amp;gt; [3/5] WORKDIR /app                                                                                                                                                                                                                                           0.0s
 =&amp;gt; [4/5] COPY target/example-0.0.1-SNAPSHOT.jar /app/app.jar                                                                                                                                                                                                    0.1s
 =&amp;gt; [5/5] COPY scripts/run.sh .                                                                                                                                                                                                                                  0.0s
 =&amp;gt; exporting to image                                                                                                                                                                                                                                           0.1s
 =&amp;gt; =&amp;gt; exporting layers                                                                                                                                                                                                                                          0.1s
 =&amp;gt; =&amp;gt; writing image sha256:6d6ba6764805971eef0532e21ec28feb6308ddb04bb650a7d087ab689d0d65be                                                                                                                                                                     0.0s
 =&amp;gt; =&amp;gt; naming to docker.io/seungkyua/springboot-docker&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ docker image ls 
REPOSITORY                    TAG       IMAGE ID       CREATED          SIZE
seungkyua/springboot-docker   latest    6d6ba6764805   54 seconds ago   473MB&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이미지 크기가 473M 로 만들어졌다. 어플리케이션 jar 파일의 크기가 68M 이므로 JVM 을 포함하는 이미지가 405M 의 크기가 된다는 의미이다.&lt;/p&gt;
&lt;p&gt;보통 이미지를 작게하기 위해서 base 이미지 태그로 &lt;code&gt;alpine&lt;/code&gt; 이나 &lt;code&gt;slim&lt;/code&gt; 을 많이 사용한다. 여기서 slim 을 사용했는데도 이 정도 크기라면 사이즈가 작다고 할 수 없다.&lt;/p&gt;
&lt;p&gt;더 작은 사이즈를 만들기 위해서 alpine 이미지를 찾아서 적용해 보자.&lt;/p&gt;
&lt;p&gt;base 이미지를 &lt;code&gt;amazoncorretto&lt;/code&gt; 로 변경하고 다시 사이즈를 비교해 보자.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;FROM amazoncorretto:17-alpine
MAINTAINER Ahn Seungkyu

ARG JAR_FILE=example-0.0.1-SNAPSHOT.jar

RUN mkdir -p /app
WORKDIR /app

COPY target/${JAR_FILE} /app/app.jar
COPY scripts/run.sh .
ENTRYPOINT [&amp;quot;./run.sh&amp;quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ docker build -t seungkyua/springboot-docker -f docker/Dockerfile2 .

$ docker image ls
REPOSITORY                    TAG       IMAGE ID       CREATED          SIZE
seungkyua/springboot-docker   latest    ed08524545ba   31 seconds ago   358MB
&amp;lt;none&amp;gt;                        &amp;lt;none&amp;gt;    6d6ba6764805   7 minutes ago    473MB&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;조회되는 이미지를 보면 base 이미지만을 바꿨을 뿐인데 358M 로 줄어들었다.&lt;/p&gt;
&lt;h1&gt;컨테이너 이미지 만들기 - 멀티 스테이지&lt;/h1&gt;
&lt;p&gt;컨테이너 이미지 사이즈를 줄이기 위해서 멀티 스테이지를 써야 한다는 말을 들어봤을 것이다. 여기서도 사이즈를 줄이기 위해 멀티 스테이지를 사용해 보자.&lt;/p&gt;
&lt;p&gt;docker/Dockerfile3 를 보면 멀티 스테이지를 어떻게 구성하는지 알 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# syntax=docker/dockerfile:1
FROM maven:3.8.5-openjdk-17 as build
MAINTAINER Ahn Seungkyu

WORKDIR /app
COPY . /app
RUN --mount=type=cache,target=/root/.m2 mvn -Dmaven.wagon.http.ssl.insecure=true -Dmaven.wagon.http.ssl.allowall=true package

FROM amazoncorretto:17-alpine
MAINTAINER Ahn Seungkyu

ARG JAR_FILE=example-0.0.1-SNAPSHOT.jar

WORKDIR /app
COPY --from=build /app/target/${JAR_FILE} /app/app.jar
COPY scripts/run.sh /app/
ENTRYPOINT [&amp;quot;./run.sh&amp;quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;빌드하는 이미지와 런타임에서 실행되는 이미지가 나눠져 있다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;# syntax=docker/dockerfile:1&lt;/code&gt;  는 이미지 안에서 소스 빌드를 할 때 디펜던시가 있는 파일을 매번 가져오지 말고 한 번만 가져와서 캐싱하여 효율적으로 사용하고자 할 때 사용한다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;--mount=type=cache,target=/root/.m2&lt;/code&gt; 는 로컬에 저장해서 재활용하자는 의미이고 &lt;code&gt;-Dmaven.wagon.http.ssl.insecure=true -Dmaven.wagon.http.ssl.allowall=true&lt;/code&gt; 메이븐으로 패키지할 때 jvm 이 ssl 인증서 없이 사용하기 위해서 추가되었다. &lt;/p&gt;
&lt;p&gt;첫번째는 어플리케이션을 빌드하기 위해 필요한 이미지 정의이고 두번째는 빌드된 어플리케이션을 복사하는 이미지 정의로 두번째는 앞서 기본편에서 설명한 것과 동일하다.&lt;/p&gt;
&lt;p&gt;jar 파일만 빌드해서 복사하는 구조라 실제로 이미지 차이는 없을 것이다. 다만, 빌드를 이미지를 만들 때 로컬 환경 구성 없이도 만들 수 있다는 장점이 있다. &lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ docker build -t seungkyua/springboot-docker -f docker/Dockerfile3 .

$ docker image ls
REPOSITORY                    TAG       IMAGE ID       CREATED          SIZE
seungkyua/springboot-docker   latest    33ed3cbf0300   31 seconds ago   358MB
&amp;lt;none&amp;gt;                        &amp;lt;none&amp;gt;    ed08524545ba   4 minutes ago    358MB
&amp;lt;none&amp;gt;                        &amp;lt;none&amp;gt;    6d6ba6764805   7 minutes ago    473MB&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;컨테이너 이미지 만들기 - alpine 에 추가&lt;/h1&gt;
&lt;p&gt;여전히 사이즈가 358M 로 작지 않은 사이즈이다.&lt;/p&gt;
&lt;p&gt;이제 기본 alpine 이미지에 JRE 와 어플리케이션을 설치하는 방법으로 이미지 사이즈를 줄여보자.&lt;/p&gt;
&lt;p&gt;docker/Dockerfile 을 살펴보자.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;FROM amazoncorretto:17-alpine3.18 as builder-jre

RUN apk add --no-cache --repository=http://dl-cdn.alpinelinux.org/alpine/edge/main/ binutils=2.41-r0

RUN $JAVA_HOME/bin/jlink \
         --module-path &amp;quot;$JAVA_HOME/jmods&amp;quot; \
         --verbose \
         --add-modules ALL-MODULE-PATH \
         --strip-debug \
         --no-man-pages \
         --no-header-files \
         --compress=2 \
         --output /jre

#=========================================================================

# syntax=docker/dockerfile:1
FROM maven:3.8.5-openjdk-17 as build
MAINTAINER Ahn Seungkyu

WORKDIR /app
COPY . /app
RUN --mount=type=cache,target=/root/.m2 mvn -Dmaven.wagon.http.ssl.insecure=true -Dmaven.wagon.http.ssl.allowall=true package

#=========================================================================

FROM alpine:3.18.4
MAINTAINER Ahn Seungkyu

ENV JAVA_HOME=/jre
ENV PATH=&amp;quot;$JAVA_HOME/bin:$PATH&amp;quot;
ARG JAR_FILE=example-0.0.1-SNAPSHOT.jar

COPY --from=builder-jre /jre $JAVA_HOME

ARG APPLICATION_USER=appuser
RUN adduser --no-create-home -u 1000 -D $APPLICATION_USER

RUN mkdir /app &amp;amp;&amp;amp; chown -R $APPLICATION_USER /app

USER 1000

COPY --chown=1000:1000 --from=build /app/target/${JAR_FILE} /app/app.jar
COPY scripts/run.sh /app/

WORKDIR /app
EXPOSE 8080

ENTRYPOINT [&amp;quot;./run.sh&amp;quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이미지가 3개로 구성되어 있다.&lt;/p&gt;
&lt;p&gt;첫번째는 작은 사이즈의 jre 를 만드는 이미지, 두번째는 어플리케이션을 빌드하는 이미지, 마지막으로 세번째는 작은 &lt;code&gt;alpine&lt;/code&gt; 베이스 이미지에 jre 와 빌드된 어플리케이션 jar 파일을 복사하는 이미지이다.&lt;/p&gt;
&lt;p&gt;첫번째 이미지 만드는 부분에서 &lt;code&gt;binutils&lt;/code&gt; 을 설치하는데 다운 받을 리파지토리를 지정하여 에러가 없게 한다. &lt;code&gt;binutils&lt;/code&gt; 는 jre 을 만들 때 &lt;code&gt;strip-debug&lt;/code&gt; 옵션을 사용하기 위해서 설치한다.&lt;/p&gt;
&lt;p&gt;세번째 이미지 만드는 부분에서 사용자를 추가하는 로직이 있는데 이는 보안상 이미지내 실행 프로세스를 root 가 아닌 지정된 사용자로 하기 위해서 일반적으로 추가한다.&lt;/p&gt;
&lt;p&gt;이미지 사이즈는 다음과 같다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ docker build -t seungkyua/springboot-docker -f docker/Dockerfile .

$ docker image ls                                                   
REPOSITORY                    TAG       IMAGE ID       CREATED          SIZE
seungkyua/springboot-docker   latest    f5dc2f994864   28 seconds ago   168MB
&amp;lt;none&amp;gt;                        &amp;lt;none&amp;gt;    ed08524545ba   24 minutes ago   358MB
&amp;lt;none&amp;gt;                        &amp;lt;none&amp;gt;    6d6ba6764805   31 minutes ago   473MB&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이미지가 최종적으로 168M 로 줄어들었다.&lt;/p&gt;
&lt;p&gt;이제 실제 이미지가 정상적으로 실행되는지 확인해 보자.&lt;/p&gt;
&lt;p&gt;mysql 을 띄우고 어플리케이션을 띄운 후에 curl 로 데이터를 입력해 본다.&lt;/p&gt;
&lt;h3&gt;1. mysql 실행&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ mkdir -p ~/.docker-data/mysql

$ docker run --cap-add=sys_nice -d --restart=always -p 3306:3306 -e MYSQL_ROOT_PASSWORD=password \
-v ~/.docker-data/mysql:/var/lib/mysql \
--name mysql-ask mysql:8.0.34 \
--character-set-server=utf8mb4 \
--collation-server=utf8mb4_unicode_ci&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. database 생성&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ docker exec -it mysql-ask bash
# mysql -uroot -ppassword
mysql&amp;gt; create database if not exists order_service;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. 어플리케이션 실행&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ docker run -d --name springboot --rm -p 19090:19090 --link mysql-ask:localhost seungkyua/springboot-docker&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4. 데이터 조회&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ curl -X POST http://127.0.0.1:19090/orders \
   -H &amp;quot;Content-Type: application/json&amp;quot; \
   -d &amp;#39;{&amp;quot;customerId&amp;quot;: 1, &amp;quot;orderTotal&amp;quot;: 12.23}&amp;#39;

--- output ---
{&amp;quot;orderId&amp;quot;:1}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;정상적으로 어플리케이션이 실행되어 동작하는 것을 확인할 수 있다.&lt;/p&gt;</description>
      <category>Container</category>
      <category>Container Image</category>
      <category>springboot</category>
      <category>컨테이너 이미지 경량화</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/319</guid>
      <comments>https://ahnseungkyu.com/319#entry319comment</comments>
      <pubDate>Wed, 25 Oct 2023 11:18:10 +0900</pubDate>
    </item>
    <item>
      <title>Cluster API 다이어그램</title>
      <link>https://ahnseungkyu.com/318</link>
      <description>&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/Jbqn4/btsrZAtFXNN/ocK5MBYq2H4GvjWpkGo8G0/AWS%20Cluster%20API.pptx?attach=1&amp;amp;knm=tfile.pptx&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;AWS Cluster API.pptx&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;0.05MB&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;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;cluster api - kubeadm.png&quot; data-origin-width=&quot;2692&quot; data-origin-height=&quot;1612&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxPX9G/btsrYWjrZEB/P1pZ998dXKprHKZmq3knb1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxPX9G/btsrYWjrZEB/P1pZ998dXKprHKZmq3knb1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxPX9G/btsrYWjrZEB/P1pZ998dXKprHKZmq3knb1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxPX9G%2FbtsrYWjrZEB%2FP1pZ998dXKprHKZmq3knb1%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;863&quot; height=&quot;517&quot; data-filename=&quot;cluster api - kubeadm.png&quot; data-origin-width=&quot;2692&quot; data-origin-height=&quot;1612&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;cluster api - eks.png&quot; data-origin-width=&quot;2388&quot; data-origin-height=&quot;1444&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/t4Zc6/btsrYAuezU4/tLpf7ysryNOP7YqcCrX5xk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/t4Zc6/btsrYAuezU4/tLpf7ysryNOP7YqcCrX5xk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/t4Zc6/btsrYAuezU4/tLpf7ysryNOP7YqcCrX5xk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ft4Zc6%2FbtsrYAuezU4%2FtLpf7ysryNOP7YqcCrX5xk%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;2388&quot; height=&quot;1444&quot; data-filename=&quot;cluster api - eks.png&quot; data-origin-width=&quot;2388&quot; data-origin-height=&quot;1444&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Kubernetes</category>
      <category>cluster api</category>
      <category>eks</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/318</guid>
      <comments>https://ahnseungkyu.com/318#entry318comment</comments>
      <pubDate>Wed, 23 Aug 2023 19:00:21 +0900</pubDate>
    </item>
    <item>
      <title>RBAC 과 Service Accounts 를 사용하여 사용자 권한 제어하기 (Kubernetes v1.24 이상)</title>
      <link>https://ahnseungkyu.com/317</link>
      <description>&lt;p&gt;Kubernetes 에서 ServiceAccount 를 생성하면 1.22 버전까지는 자동으로 token 을 생성하였다. 그러나 1.23 부터는 토큰을 자동으로 생성해 주지 않기 때문에 수동으로 생성해야 한다.&lt;/p&gt;
&lt;p&gt;이 바뀐 기능은 ServiceAcount 와 RBAC 을 연동하여 권한을 제어하고자 할 때 문제가 되므로 수동으로 만드는 방법을 살펴본다.&lt;/p&gt;
&lt;h1&gt;1. 네임스페이스 - SA 생성&lt;/h1&gt;
&lt;p&gt;먼저 테스트할 네임스페이스를 만든다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ kubectl create ns ask&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ask 네임스페이스에 서비스 어카운트를 생성한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ kubectl create sa ask-sa -n ask&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;1.24 버전부터는 sa 를 생성해도 token 이 자동으로 생성되지 않는다.&lt;/p&gt;
&lt;p&gt;참고: &lt;a href=&quot;https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.24.md#no-really-you-must-read-this-before-you-upgrade&quot;&gt;https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.24.md#no-really-you-must-read-this-before-you-upgrade&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;token 은 Secret 타입이므로 Secret 을 조회해 보면 token이 자동 생성되지 않았음을 알 수 있다.&lt;/p&gt;
&lt;p&gt;참고: &lt;a href=&quot;https://kubernetes.io/docs/concepts/configuration/secret/#service-account-token-secrets&quot;&gt;https://kubernetes.io/docs/concepts/configuration/secret/#service-account-token-secrets&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;2. Token 생성&lt;/h1&gt;
&lt;p&gt;ask-sa 에 해당하는 token 을 수동으로 생성한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ cat &amp;lt;&amp;lt;EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
  name: ask-sa
  namespace: ask
  annotations:
    kubernetes.io/service-account.name: ask-sa
type: kubernetes.io/service-account-token
EOF&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;token 을 생성할 때 어노테이션으로 연결될 서비스 어카운트를 지정한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ kubectl get secret -n ask
NAME     TYPE                                  DATA   AGE
ask-sa   kubernetes.io/service-account-token   3      7s &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;조회를 하면 service-account-toke 타입으로 secret 이 생성되었음을 알 수 있다.&lt;/p&gt;
&lt;p&gt;혹은 token 을 수동으로 생성하는 방법도 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ kubectl create token ask-sa --bound-object-kind Secret --bound-object-name ask-sa --duration=999999h  -n ask

------- output -----------
xxxxxxxxxxxxxxxxxxxxxxx&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;base64 로 변환하여 secret 에 &lt;code&gt;data.token&lt;/code&gt; 값으로 저장한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ kubectl create token ask-sa --bound-object-kind Secret --bound-object-name ask-sa --duration=999999h  -n ask | base64 -w 0

------- output -----------
xxxxxxxxxxxxxxxxxxxxxxx&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ kubectl edit secret ask-sa -n ask
...
data:
  token: xxxxxxxxxxxxxxxxxxxx
...&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;3. Role 과 RoleBinding 생성&lt;/h1&gt;
&lt;p&gt;Role 과 RoleBinding 은 네임스페이스 별로 연결된다. 그러므로 생성한 권한은 해당 네임스페이스에만 권한이 주어진다.&lt;/p&gt;
&lt;p&gt;먼저 Role 을 생성한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt; $ cat &amp;lt;&amp;lt;EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: ask-role
  namespace: ask
rules:
- apiGroups: [&amp;quot;&amp;quot;, &amp;quot;*&amp;quot;]
  resources: [&amp;quot;*&amp;quot;]
  verbs: [&amp;quot;*&amp;quot;]
EOF&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;apiGroup&lt;/code&gt; 에서 &lt;code&gt;&amp;quot;&amp;quot;&lt;/code&gt; 은 &lt;code&gt;core API group&lt;/code&gt; 으로 다음의 출력으로 확인할 수 있다.&lt;/p&gt;
&lt;p&gt;APIVERSION 이 &lt;code&gt;v1&lt;/code&gt; 인 리소스들이 core API group 이 되면 이들에 대해서 권한을 사용하겠다는 뜻이다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ kubectl api-resources -o wide
NAME                              SHORTNAMES       APIVERSION      NAMESPACED   KIND                             VERBS
bindings                                           v1              true         Binding                          [create]
componentstatuses                 cs               v1              false        ComponentStatus                  [get list]
configmaps                        cm               v1              true         ConfigMap                        [create delete deletecollection get list patch update watch]
endpoints                         ep               v1              true         Endpoints                        [create delete deletecollection get list patch update watch]
events                            ev               v1              true         Event                            [create delete deletecollection get list patch update watch]
limitranges                       limits           v1              true         LimitRange                       [create delete deletecollection get list patch update watch]
namespaces                        ns               v1              false        Namespace                        [create delete get list patch update watch]
nodes                             no               v1              false        Node                             [create delete deletecollection get list patch update watch]
persistentvolumeclaims            pvc              v1              true         PersistentVolumeClaim            [create delete deletecollection get list patch update watch]
persistentvolumes                 pv               v1              false        PersistentVolume                 [create delete deletecollection get list patch update watch]
pods                              po               v1              true         Pod                              [create delete deletecollection get list patch update watch]
podtemplates                                       v1              true         PodTemplate                      [create delete deletecollection get list patch update watch]
replicationcontrollers            rc               v1              true         ReplicationController            [create delete deletecollection get list patch update watch]
resourcequotas                    quota            v1              true         ResourceQuota                    [create delete deletecollection get list patch update watch]
secrets                                            v1              true         Secret                           [create delete deletecollection get list patch update watch]
serviceaccounts                   sa               v1              true         ServiceAccount                   [create delete deletecollection get list patch update watch]
services                          svc              v1              true         Service                          [create delete deletecollection get list patch update watch]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;다음은 Rolebinding을 생성한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ cat &amp;lt;&amp;lt;EOF | kubectl apply -f - 
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: ask-role-binding
  namespace: ask
subjects:
- kind: ServiceAccount
  name: ask-sa
  namespace: ask
roleRef:
  kind: Role
  name: ask-role
  apiGroup: rbac.authorization.k8s.io
EOF&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ServiceAcount 인 &lt;code&gt;ask-sa&lt;/code&gt; 와 &lt;code&gt;ask-role&lt;/code&gt; Role 을 서로 연결 시킨 다는 의미이다.&lt;/p&gt;
&lt;p&gt;이렇게 되면 이제 &lt;code&gt;ask-sa&lt;/code&gt; sa 는 &lt;code&gt;ask-role&lt;/code&gt; role 에 대한 권한만을 사용할 수 있다.&lt;/p&gt;
&lt;h1&gt;4. kubeconfig 생성&lt;/h1&gt;
&lt;p&gt;sa 를 만들었으니 이를 연동할 kubeconfig 를 만들어 본다.&lt;/p&gt;
&lt;p&gt;token 을 조회해 보자.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ kubectl get secret -n ask ask-sa -ojsonpath={.data.token} | base64 -d

----- output -----
xxxxxxxxxxxxxxxxxxxxxxxxx&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;token 값으로 kubeconfig 의 user 접속 token 에 넣는다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: xxxxxxxxxxxxxxxxxxxxxxxx
server: https://xxxxxxxxxx.ap-northeast-2.eks.amazonaws.com
  name: mycluster
contexts:
- context:
    cluster: mycluster
    user: ask-sa
    namespace: ask
  name: mycluster
current-context: mycluster
kind: Config
users:
- name: ask-sa
  user:
    token: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위의 kubeconfig 로 접속하면 ask 네임스페이스에 대해서 kubectl 명령어를 실행할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ kubectl --kubeconfig ask.kubeconfig get pods
Error from server (Forbidden): pods is forbidden: User &amp;quot;system:serviceaccount:ask:ask-sa&amp;quot; cannot list resource &amp;quot;pods&amp;quot; in API group &amp;quot;&amp;quot; in the namespace &amp;quot;default&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;default 네임스페이스에는 권한이 없으므로 권한 없음 에러가 리턴된다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ kubectl --kubeconfig ask.kubeconfig get pods -n ask
No resources found in ask namespace.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ask 네임스페이스의 파드는 정상적으로 조회된다.&lt;/p&gt;</description>
      <category>Kubernetes</category>
      <category>Kubernetes 1.24</category>
      <category>No auto gerneration</category>
      <category>RBAC with Service Accounts</category>
      <category>token</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/317</guid>
      <comments>https://ahnseungkyu.com/317#entry317comment</comments>
      <pubDate>Thu, 17 Aug 2023 15:59:45 +0900</pubDate>
    </item>
    <item>
      <title>프라이빗 컨테이너 이미지 저장소 HA(High Available) 로 구성하기 (feat. Harbor)</title>
      <link>https://ahnseungkyu.com/316</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;컨테이너 이미지 저장소를 독립적으로 구성하는 방법을 살펴본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 컨테이너 이미지는 CNCF 의 프로젝트 중에 하나인 Harbor 를 사용하여 구성한다. Helm chart 가 잘 되어 있어 쿠버네티스 위에서 설치하는 것은 매우 쉬운데 운영 환경에 걸맞는 HA 구성은 여러가지 고려해야 할 사항들이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 이번에는 Harbor 를 HA 로 구성하는 방법을 알아본다.&lt;/p&gt;
&lt;h1&gt;Harbor HA Architecture&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Harbor 를 HA 로 구성하려면 아래의 전제 조건이 필요하다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Kubernetes cluster 1.10 이상&lt;/li&gt;
&lt;li&gt;Helm 2.8.0 이상&lt;/li&gt;
&lt;li&gt;High Available 하게 설치된 Ingress Controller&lt;/li&gt;
&lt;li&gt;High Available 하게 설치된 PostgreSQL 데이터베이스&lt;/li&gt;
&lt;li&gt;High Available 하게 설치된 Redis&lt;/li&gt;
&lt;li&gt;Shared storage 로 된 PVC&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 중에서 1, 2, 3 번은 구성되어 있다고 가정하고 이후를 살펴본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 Public Cloud 는 AWS 를 사용했고 쿠버네티스 클러스터는 EKS 를 사용했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아키텍처는 아래 그림과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1632&quot; data-origin-height=&quot;918&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SGaKh/btsqJTIkCcW/ojT84dlvjIf2PpDkKJJly0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SGaKh/btsqJTIkCcW/ojT84dlvjIf2PpDkKJJly0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SGaKh/btsqJTIkCcW/ojT84dlvjIf2PpDkKJJly0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSGaKh%2FbtsqJTIkCcW%2FojT84dlvjIf2PpDkKJJly0%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;1632&quot; height=&quot;918&quot; data-origin-width=&quot;1632&quot; data-origin-height=&quot;918&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[출처: &lt;a href=&quot;https://goharbor.io/docs/1.10/img/ha.png&quot;&gt;https://goharbor.io/docs/1.10/img/ha.png&lt;/a&gt;]&lt;/p&gt;
&lt;h1&gt;PostgreSQL 데이터 베이스 구성&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS 의 RDS 를 사용했으며 Harbor 에서 사용할 필요한 user 생성과 권한을 부여한다.&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;# psql -U postgres
postgres=# CREATE DATABASE registry;
postgres=# CREATE USER harbor WITH ENCRYPTED PASSWORD 'xxxxxxx';
postgres=# GRANT ALL PRIVILEGES ON DATABASE registry TO harbor;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어드민 권한으로 데이터베이스에 접속하여 Harbor 에서 사용할 &lt;code&gt;registry&lt;/code&gt; database 를 생성한다. user 는 &lt;code&gt;harbor&lt;/code&gt; 이고 필요한 password 를 생성한 다음 registry 데이터베이스의 모든 권한을 harbor 유저에 부여한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테이블과 스퀀스를 다루기 위해서는 아래 추가적으로 권한을 부여해야 한다. (아래 권한이 추가되지 않으면 harbor 유저로 테이블과 시퀀스에 대한 생성/조회/삭제/수정을 하지 못한다.&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;postgres=# \c registry
registry=# GRANT ALL ON ALL TABLES IN SCHEMA public TO harbor;
registry=# GRANT ALL ON ALL SEQUENCES IN SCHEMA public TO harbor;&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Redis 구성&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Harbor 는 캐시로 레디스를 사용하며 이 때 레디스 구성은 독립 혹은 레디스 + 센티널(sentinel) 구성만을 지원한다. 한마디로 클러스터 모드의 레디스는 지원하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS Elasticache Redis 서비스는 센티널을 지원하지 않아 굳이 Elasticache 서비스를 사용할 이유가 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Elasticache 서비스의 레디스 구성으로 1개의 컨트롤노드 - 멀티 워커노드 로 하여 데이터 복제는 가능하나 1개의 컨트롤 노드가 무너지면 역시 장애가 발생하므로 서비스를 사용하여 구성하지 않았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 후 살펴볼 Harbor Helm chart 에서 쿠버네티스 위에 레디스를 1개로 띄우는 internal 생성 방식을 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;레디스 구성을 HA 로 하고 싶다면, 레디스를 멀티 노드 센티널 구성으로 쿠버네티스 위에 띄우는 방법도 있으니 이는 레디스 설치 문서를 참고하면 된다. (센티널 구성일 때 Harbor chart 의 value 값은 코멘트로 적혀있으니 쉽게 이해할 수 있다)&lt;/p&gt;
&lt;h1&gt;Shared Storage 구성&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS 에서 지원하는 공유 스토리지는 &lt;code&gt;EFS&lt;/code&gt; 가 있다. EFS 는 &lt;code&gt;NFSv4&lt;/code&gt; 프로토콜을 지원하니 공유 스토리지로 사용 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 AWS EFS 서비스에서 파일스토리지를 생성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성된 EFS 는 실제로 파일시스템의 스토리지가 생성된 것은 아니다. 일종의 정보를 생성한 것이며 필요에 따라 실제 스토리지를 생성하고 할당 받는 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿠버네티스에서는 &lt;code&gt;Provisioner&lt;/code&gt;, &lt;code&gt;StroageClass&lt;/code&gt; &lt;code&gt;PVC&lt;/code&gt;, &lt;code&gt;PV&lt;/code&gt; 라는 스토리지 표준 관리 방법이 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;879&quot; data-origin-height=&quot;466&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TeGk4/btsqRgvqU9s/7xpFMOWC5mzAnMuKDkBcyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TeGk4/btsqRgvqU9s/7xpFMOWC5mzAnMuKDkBcyK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TeGk4/btsqRgvqU9s/7xpFMOWC5mzAnMuKDkBcyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTeGk4%2FbtsqRgvqU9s%2F7xpFMOWC5mzAnMuKDkBcyK%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;879&quot; height=&quot;466&quot; data-origin-width=&quot;879&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;[출처: &lt;a href=&quot;https://d2908q01vomqb2.cloudfront.net/e1822db470e60d090affd0956d743cb0e7cdf113/2022/10/28/4.Dynamic-Provisioning.png&quot;&gt;https://d2908q01vomqb2.cloudfront.net/e1822db470e60d090affd0956d743cb0e7cdf113/2022/10/28/4.Dynamic-Provisioning.png&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;흔히 Provisioner 라고 말하는 &lt;code&gt;CSI Driver&lt;/code&gt; 를 설치한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EKS 에서는 추가 기능으로 &lt;code&gt;Amazon EFS CSI Driver&lt;/code&gt; 를 추가할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 권한에서 중요한 한가지가 있는데 EKS node 에서 사용하는 role 에 (role 명은 eks 의 태그 정보를 확인해 보면 된다) &lt;code&gt;AmazonEFSCSIDriverPolicy&lt;/code&gt; 정책이 반드시 추가되어 있어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 스토리지 클래스를 설치하자.&lt;/p&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;$ curl -Lo efs-sc.yaml https://raw.githubusercontent.com/kubernetes-sigs/aws-efs-csi-driver/master/examples/kubernetes/dynamic_provisioning/specs/storageclass.yaml

$ vi efs-sc.yaml
--- 
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: taco-efs-storage
provisioner: efs.csi.aws.com
parameters:
  provisioningMode: efs-ap
  fileSystemId: fs-xxxxxxx  # EFS 에서 생성한 fs id
  directoryPerms: &quot;700&quot;

$ kubectl apply -f efs-sc.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변경해야 할 것은 &lt;code&gt;fileSystemId&lt;/code&gt; 로 앞서 EFS 에서 생성한 파일스토리지의 &lt;code&gt;fs id&lt;/code&gt; 값으로 변경해 준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스토리지클래스가 잘 작동하는지 확인하기 위해서 아래와 같이 테스트 파드를 생성해 본다.&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;$ kubectl create ns harbor-ask

$ vi efs-test-pod.yaml
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: efs-claim
  namespace: harbor-ask
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: taco-efs-storage
  resources:
    requests:
      storage: 5Gi
---
apiVersion: v1
kind: Pod
metadata:
  name: efs-app
  namespace: harbor-ask
spec:
  containers:
    - name: app
      image: centos
      command: [&quot;/bin/sh&quot;]
      args: [&quot;-c&quot;, &quot;while true; do echo $(date -u) &amp;gt;&amp;gt; /data/out; sleep 5; done&quot;]
      volumeMounts:
        - name: persistent-storage
          mountPath: /data
  volumes:
    - name: persistent-storage
      persistentVolumeClaim:
        claimName: efs-claim

$ kubectl apply -f efs-test-pod.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pod 가 생성되고 Pod 로 접속하면 &lt;code&gt;/data/out&lt;/code&gt; 파일에 시간이 출력되고 있으면 정상적으로 작동하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PVC 를 생성할 때 &lt;code&gt;accessModes&lt;/code&gt; 가 &lt;code&gt;ReadWriteMany&lt;/code&gt; 인 것도 확인하자.&lt;/p&gt;
&lt;h1&gt;Harbor chart 로 HA 설치&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 필요한 사전 구성은 마쳤으니 chart 로 설치를 진행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 chart 를 등록하고 다운 받는다.&lt;/p&gt;
&lt;pre class=&quot;gams&quot;&gt;&lt;code&gt;$ helm repo add harbor https://helm.goharbor.io
$ helm repo update

$ helm fetch harbor/harbor --untar&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;차트를 다운 받을 필요는 없으니 관련 values.yaml 을 확인하기 위해서 참고용으로 다운 받았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필요한 value 를 설정한다.&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;$ vi ask-values.yaml
---
harborAdminPassword: &quot;xxxxx&quot;

expose:
  type: ingress
  tls:
    enabled: true
    certSource: secret
    secret:
      secretName: &quot;taco-cat-tls&quot;
  ingress:
    hosts:
      core: harbor.xxx
    className: &quot;nginx&quot;

externalURL: https://harbor.xxx&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;harborAdminPassword&lt;/code&gt; 는 Harbor 웹 화면에서 &lt;code&gt;admin&lt;/code&gt; 계정으로 접속할 때 필요한 패스워드 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;expose&lt;/code&gt; 는 ingress 에 노출되는 값이며 도메인이 &lt;code&gt;harbor.xxx&lt;/code&gt; 으로 DNS 에 연결되어 있으며 (DNS 가 없으면 로컬 컴퓨터에 &lt;code&gt;/etc/hosts&lt;/code&gt; 파일에 등록해서 사용한다), 도메인 인증서는 앞에서 생성한 &lt;code&gt;harbor-ask&lt;/code&gt; 네임스페이스에 &lt;code&gt;taco-cat-tls&lt;/code&gt; 라는 secret 이름으로 저장되어 있다.&lt;/p&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;persistence:
  enabled: true
  resourcePolicy: &quot;keep&quot;
  persistentVolumeClaim:
    registry:
      storageClass: &quot;taco-efs-storage&quot;
      accessMode: ReadWriteMany
      size: 1024Gi
    jobservice:
      jobLog:
        storageClass: &quot;taco-efs-storage&quot;
        accessMode: ReadWriteMany
        size: 128Gi
    redis:
      storageClass: &quot;taco-efs-storage&quot;
      accessMode: ReadWriteMany
      size: 256Gi
    trivy:
      storageClass: &quot;taco-efs-storage&quot;
      accessMode: ReadWriteMany
      size: 128Gi
  imageChartStorage:
    disableredirect: false
    type: filesystem
    filesystem:
      rootdirectory: /storage&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;persistence&lt;/code&gt; 는 Harbor 컴포넌트에서 사용하는 스토리지 정보이다. Harbor 차트에서 설치하는 컴포넌트는 &lt;code&gt;registry&lt;/code&gt; , &lt;code&gt;jobservice&lt;/code&gt; , &lt;code&gt;redis&lt;/code&gt; , &lt;code&gt;trivy&lt;/code&gt; , &lt;code&gt;core&lt;/code&gt;, &lt;code&gt;portal&lt;/code&gt; 등이 있으며 스토리지가 필요한 컴포넌트만 기술하면 된다.&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;registry:
  replicas: 2
portal:
  replicas: 2
core:
  replicas: 2
jobservice:
  replicas: 2
trivy:
  enabled: true
  replicas: 2
notary:
  enabled: false
cache:
  enabled: true
  expireHours: 24&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 컴포넌트의 Pod 갯수를 넣는다. HA 구성 이므로 최소 2 이상을 넣는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;notary&lt;/code&gt; 는 이미지 서명 관련 컴포넌트로 이번 구성에서는 설치하지 않았다.&lt;/p&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;database:
  type: external
  external:
    host: xxxxxx.ap-northeast-2.rds.amazonaws.com
    port: &quot;5432&quot;
    username: &quot;harbor&quot;
    password: &quot;xxxxxxx&quot;
    coreDatabase: &quot;registry&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RDS 에 만들어진 외부 데이터베이스 정보를 넣는다.&lt;/p&gt;
&lt;pre class=&quot;vim&quot;&gt;&lt;code&gt;redis:
  type: internal&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;레디스는 내부에서 단일 Pod 로 생성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체 values 는 다음과 같다.&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;$ vi ask-ha-values.yaml
---
harborAdminPassword: &quot;xxxxxx&quot;

expose:
  type: ingress
  tls:
    enabled: true
    certSource: secret
    secret:
      secretName: &quot;taco-cat-tls&quot;
  ingress:
    hosts:
      core: harbor.xxx
    className: &quot;nginx&quot;

externalURL: https://harbor.xxx

persistence:
  enabled: true
  resourcePolicy: &quot;keep&quot;
  persistentVolumeClaim:
    registry:
      storageClass: &quot;taco-efs-storage&quot;
      accessMode: ReadWriteMany
      size: 1024Gi
    jobservice:
      jobLog:
        storageClass: &quot;taco-efs-storage&quot;
        accessMode: ReadWriteMany
        size: 128Gi
    redis:
      storageClass: &quot;taco-efs-storage&quot;
      accessMode: ReadWriteMany
      size: 256Gi
    trivy:
      storageClass: &quot;taco-efs-storage&quot;
      accessMode: ReadWriteMany
      size: 128Gi
  imageChartStorage:
    disableredirect: false
    type: filesystem
    filesystem:
      rootdirectory: /storage

registry:
  replicas: 2
portal:
  replicas: 2
core:
  replicas: 2
jobservice:
  replicas: 2
trivy:
  enabled: true
  replicas: 2
notary:
  enabled: false
cache:
  enabled: true
  expireHours: 24

database:
  type: external
  external:
    host: xxxxxx.ap-northeast-2.rds.amazonaws.com
    port: &quot;5432&quot;
    username: &quot;harbor&quot;
    password: &quot;xxxxxxx&quot;
    coreDatabase: &quot;registry&quot;

redis:
  type: internal&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿠버네티스에 배포한다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ helm upgrade -i harbor-ask harbor/harbor --version 1.12.3 -n harbor-ask -f ask-ha-values.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;설치 확인&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Harbor 웹에 접속하여 사용자(tks)와 프로젝트(tks)를 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 프로젝트의 &lt;code&gt;Members&lt;/code&gt; 탭에는 사용자가 등록되어 있어야 한다. (그래야 컨테이너 이미지를 올릴 수 있는 권한이 있다)&lt;/p&gt;
&lt;pre class=&quot;elixir&quot;&gt;&lt;code&gt;$ docker login harbor.xxx -u tks
Password:

$ docker pull hello-world
$ docker tag hello-world harbor.xxx/tks/hello-world
$ docker push harbor.xxx/tks/hello-world&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Kubernetes</category>
      <category>Container Image Registry</category>
      <category>Harbor</category>
      <category>Harbor HA</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/316</guid>
      <comments>https://ahnseungkyu.com/316#entry316comment</comments>
      <pubDate>Thu, 10 Aug 2023 13:51:14 +0900</pubDate>
    </item>
    <item>
      <title>SpringBoot 으로 MSA 구현하기(1) - Java 에서 자주 쓰는 코드</title>
      <link>https://ahnseungkyu.com/315</link>
      <description>&lt;p&gt;MSA 패턴(CQRS, SAGA 등)을 코드로 구현하기 위해서 SpringBoot 으로  REST API 어플리케이션을 만드는 것을 정리하고 있는데 자료 구조외에 자주쓰게 되는 코드들이 있어서 이를 정리해 봤다.&lt;/p&gt;
&lt;p&gt;어플리케이션 개발에 Java 를 사용하는 이유는 아직 우리나라에서는 Java 가 많이 쓰이기 때문이다.  SpringBoot 으로 어느 정도 정리되면 이후에는 Gin (Go 언어 기반 웹 프레임워크)으로 정리할 예정이다. &lt;/p&gt;
&lt;h2&gt;1. null check&lt;/h2&gt;
&lt;p&gt;Primitive Type 보다는 Object 를 많이 사용하기 때문에  null check  를 항상 해야 된다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;String nullString = null;
String emptyString = &amp;quot;&amp;quot;;

if (Objects.isNull(nullString))
    System.out.println(&amp;quot;nullString is null&amp;quot;);

if (Objects.nonNull(emptyString))
    System.out.println(&amp;quot;emptyString is not null&amp;quot;);

--------- output -----------
nullString is null
emptyString is not null&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Objects 클래스를 사용하여 가독성있게 null 체크를 할 수 있다.&lt;/p&gt;
&lt;h2&gt;2. null check &amp;amp; default value 세팅&lt;/h2&gt;
&lt;p&gt;null check 와 기본 값 세팅을 메소드 체이닝으로 바로 할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;BigDecimal bd = null;

BigDecimal defaultValue = Optional.ofNullable(bd).orElse(BigDecimal.ZERO);
System.out.println(defaultValue);

--------- output -----------
0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Optional.ofNullable&lt;/code&gt; 은 static 메소드로 &lt;code&gt;null&lt;/code&gt;  혹은 &lt;code&gt;객체&lt;/code&gt; 를 담고있는 Optional 을 리턴한다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Optional.orElse&lt;/code&gt; 는 메소드로 객체의 값이 &lt;code&gt;null&lt;/code&gt; 일 경우 넘겨주는 아큐먼트로 그 값을 채운다.&lt;/p&gt;
&lt;p&gt;여기서는 &lt;a href=&quot;http://BigDecimal.ZERO&quot;&gt;BigDecimal.ZERO&lt;/a&gt; 로 채워진 것을 알 수 있다.&lt;/p&gt;
&lt;h2&gt;3.  null check &amp;amp; throw Exception&lt;/h2&gt;
&lt;p&gt;null check 와 null 일 때 예외를 던질 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;BigDecimal bd = null;

Optional.ofNullable(bd).orElseThrow(() -&amp;gt; new IllegalArgumentException(&amp;quot;db is null&amp;quot;));
System.out.println(defaultValue);

--------- output -----------
Exception in thread &amp;quot;main&amp;quot; java.lang.IllegalArgumentException: db is null
    at com.ask.example.Main.lambda$setDefaultValue$0(Main.java:45)
    at java.base/java.util.Optional.orElseThrow(Optional.java:403)
    at com.ask.example.Main.setDefaultValue(Main.java:45)
    at com.ask.example.Main.main(Main.java:24)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;orElseThrow&lt;/code&gt; 메소드는 function 을 파라미터로 받으며 여기서는 람다함수를 사용하여 간단히 IllegalArgumentException 을 생성하여 던진다.&lt;/p&gt;
&lt;h2&gt;4. Array 와 List 를 Stream 으로 만들기&lt;/h2&gt;
&lt;p&gt;Stream은 Java 8부터 추가된 기능으로, Collection(Array, List, Map 등)과 같은 데이터 요소들을 처리하는데 도움을 주는 기능이다. Stream을 이용하면 다양한 작업을 수행할 수 있다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;필터링(Filtering): &lt;code&gt;filter()&lt;/code&gt; 메서드를 사용하여 특정 조건을 만족하는 요소들만 걸러낼 수 있다.&lt;/li&gt;
&lt;li&gt;변환(Mapping): &lt;code&gt;map()&lt;/code&gt; 메서드를 사용하여 요소들을 다른 형태로 변환할 수 있다.&lt;/li&gt;
&lt;li&gt;소팅(Sorting): &lt;code&gt;sorted()&lt;/code&gt; 메서드를 사용하여 요소들을 정렬할 수 있다.&lt;/li&gt;
&lt;li&gt;그룹화(Grouping): &lt;code&gt;collect()&lt;/code&gt; 메서드를 사용하여 요소들을 그룹화할 수 있다.&lt;/li&gt;
&lt;li&gt;집계(Reduction): &lt;code&gt;reduce()&lt;/code&gt; 메서드를 사용하여 요소들을 축소하여 하나의 값으로 만들 수 있다.&lt;/li&gt;
&lt;li&gt;제한(Limiting): &lt;code&gt;limit()&lt;/code&gt; 메서드를 사용하여 스트림의 크기를 제한할 수 있다.&lt;/li&gt;
&lt;li&gt;건너뛰기(Skipping): &lt;code&gt;skip()&lt;/code&gt; 메서드를 사용하여 스트림의 앞부분 요소들을 건너뛸 수 있다.&lt;/li&gt;
&lt;li&gt;병렬 처리(Parallel Processing): &lt;code&gt;parallelStream()&lt;/code&gt; 메서드를 사용하여 스트림 요소들을 병렬로 처리할 수 있다.&lt;/li&gt;
&lt;li&gt;중복 제거(Distinct): &lt;code&gt;distinct()&lt;/code&gt; 메서드를 사용하여 스트림의 중복 요소들을 제거할 수 있다.&lt;/li&gt;
&lt;li&gt;조인(Joining): &lt;code&gt;joining()&lt;/code&gt; 메서드를 사용하여 문자열 요소들을 합쳐서 하나의 문자열로 만들 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;먼저 Stream 을 만들어 보자.&lt;/p&gt;
&lt;h3&gt;배열을 Stream 으로 만들기&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;String[] fruits = { &amp;quot;apple&amp;quot;, &amp;quot;banana&amp;quot;, &amp;quot;orange&amp;quot;, &amp;quot;grape&amp;quot;, &amp;quot;banana&amp;quot; };
Stream stream = Arrays.stream(fruits);
System.out.println(stream);

--------- output -----------
java.util.stream.ReferencePipeline$Head@36baf30c&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;List 를 Stream 으로 만들기&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;List&amp;lt;String&amp;gt; fruits = new ArrayList&amp;lt;String&amp;gt;(
        Arrays.asList(&amp;quot;apple&amp;quot;, &amp;quot;banana&amp;quot;, &amp;quot;orange&amp;quot;, &amp;quot;grape&amp;quot;, &amp;quot;banana&amp;quot;));
Stream stream = fruits.stream();
System.out.println(stream);

--------- output -----------
java.util.stream.ReferencePipeline$Head@36baf30c&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;5. Stream 을 다른 Collection 으로 바꾸기&lt;/h2&gt;
&lt;p&gt;Stream 은 Collectors 클래스를 사용하여 다른 Collection 으로 쉽게 변경이 가능하다.&lt;/p&gt;
&lt;h3&gt;Stream → Set 으로 변경 (중복 제거)&lt;/h3&gt;
&lt;p&gt;참고로 distinct 로도 중복 제거가 가능하다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;List&amp;lt;String&amp;gt; fruits = new ArrayList&amp;lt;String&amp;gt;(
        Arrays.asList(&amp;quot;apple&amp;quot;, &amp;quot;banana&amp;quot;, &amp;quot;orange&amp;quot;, &amp;quot;grape&amp;quot;, &amp;quot;banana&amp;quot;));
Set&amp;lt;String&amp;gt; newSet = fruits.stream()
        .collect(Collectors.toSet());
newSet.forEach(item -&amp;gt; System.out.println(item));

--------- output -----------
banana
orange
apple
grape&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;중복된 banana 는 하나만 출력된다.&lt;/p&gt;
&lt;h3&gt;Stream → LinkedList 로 변경&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;List&amp;lt;String&amp;gt; fruits = new ArrayList&amp;lt;String&amp;gt;(
        Arrays.asList(&amp;quot;apple&amp;quot;, &amp;quot;banana&amp;quot;, &amp;quot;orange&amp;quot;, &amp;quot;grape&amp;quot;, &amp;quot;banana&amp;quot;));
List&amp;lt;String&amp;gt; newList = fruits.stream()
        .collect(Collectors.toCollection(
                LinkedList::new
        ));
newList.forEach(item -&amp;gt; System.out.println(item));

--------- output -----------
apple
banana
orange
grape
banana&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Stream → Map 으로 변경&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;List&amp;lt;String&amp;gt; fruits = new ArrayList&amp;lt;String&amp;gt;(
        Arrays.asList(&amp;quot;apple&amp;quot;, &amp;quot;banana&amp;quot;, &amp;quot;orange&amp;quot;, &amp;quot;grape&amp;quot;, &amp;quot;banana&amp;quot;));
Map&amp;lt;String, Integer&amp;gt; newMap = fruits.stream()
        .collect(Collectors.toSet()).stream()
        .collect(Collectors.toMap(
                Function.identity(),
                String::length
        ));
newMap.forEach((key, value) -&amp;gt; System.out.println(key + &amp;quot; &amp;quot; + value));

--------- output -----------
banana 6
orange 6
apple 5
grape 5&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Map 은 중복 키를 가질 수 없기 때문에  Set 으로 변환한 다음에  Map 으로 변환하였다.&lt;/p&gt;
&lt;p&gt;여기서  &lt;code&gt;Function.identity()&lt;/code&gt; 는 item 그 자체의 값으로  &lt;code&gt;apple&lt;/code&gt; 과 같은 리스트의 요소를 가리키며,  Map의 키로 사용되었다.  &lt;code&gt;String::Length&lt;/code&gt; 는 스트링 객체의 길이를 구하는 메소드를 호출한 리턴 값으로 Map 의 값으로 사용되었다.&lt;/p&gt;
&lt;h2&gt;6. Stream 과 데이터 변경 메소드들&lt;/h2&gt;
&lt;h3&gt;Stream.map()&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;map()&lt;/code&gt; 은 Item 각각에 대해서 다른 형태로 변경할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;List&amp;lt;String&amp;gt; fruits = new ArrayList&amp;lt;String&amp;gt;(
        Arrays.asList(&amp;quot;apple&amp;quot;, &amp;quot;banana&amp;quot;, &amp;quot;orange&amp;quot;, &amp;quot;grape&amp;quot;, &amp;quot;banana&amp;quot;));
List&amp;lt;String&amp;gt; newList = fruits.stream()
        .map(item -&amp;gt; item.toUpperCase())
        .collect(Collectors.toList());
newList.forEach(item -&amp;gt; System.out.println(item));

--------- output -----------
APPLE
BANANA
ORANGE
GRAPE
BANANA&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;map()&lt;/code&gt; 은 아규먼트로 &lt;code&gt;function&lt;/code&gt; 을 받으며 결과로 Stream 을 반환한다. 아규먼트로 들어가는 함수는 각 요소를 변경하여 반환하는 함수이어야 한다.&lt;/p&gt;
&lt;h3&gt;Stream.flatMap()&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;flatMap()&lt;/code&gt; 은 중첩된 Collection 을 한꺼풀 벗긴다고 생각하면 된다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;List&amp;lt;List&amp;lt;String&amp;gt;&amp;gt; listInList = Arrays.asList(
        Arrays.asList(&amp;quot;apple&amp;quot;, &amp;quot;banana&amp;quot;),
        Arrays.asList(&amp;quot;orange&amp;quot;, &amp;quot;grape&amp;quot;, &amp;quot;banana&amp;quot;));

List&amp;lt;String&amp;gt; newList = listInList.stream()
        .flatMap(Collection::stream)
        .distinct()
        .collect(Collectors.toList());
newList.forEach(item -&amp;gt; System.out.println(item));

--------- output -----------
apple
banana
orange
grape&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;flatMap()&lt;/code&gt; 도 &lt;code&gt;function&lt;/code&gt; 를 아규먼트로 받고 결과를 Stream 으로 변환한다.  단 아규먼트로 들어가는 함수는 각 요소에 영향을 주면서 &lt;code&gt;Stream&lt;/code&gt; 을 반환하는 함수이어야 한다. &lt;/p&gt;
&lt;h2&gt;6. enum 활용&lt;/h2&gt;
&lt;p&gt;enum 은 enum 타입이 반환된다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;enum Gender {
    MALE(&amp;quot;male&amp;quot;),
    FEMALE(&amp;quot;female&amp;quot;);

    private final String param;

    Gender(String param) {
        this.param = param;
    }

    String getParam() {
        return this.param;
    }
}

System.out.println(Gender.MALE.getParam());

--------- output -----------
male&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Gender.MALE&lt;/code&gt; 값은 &lt;code&gt;enum Gender&lt;/code&gt;  타입이다. &lt;/p&gt;
&lt;p&gt;하지만 아래와 같이 문자열을 enum  값으로 변환할 수 있다. 이 방법은 &lt;code&gt;Json&lt;/code&gt; 을 marshal , unmarshal 할 때 많이 사용된다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;enum Gender {
    MALE(&amp;quot;male&amp;quot;),
    FEMALE(&amp;quot;female&amp;quot;);

    private final String param;

    private static final Map&amp;lt;String, Gender&amp;gt; paramMap =
            Arrays.stream(Gender.values())
                    .collect(Collectors.toMap(
                            Gender::getParam,
                            Function.identity()
                    ));

    Gender(String param) {
        this.param = param;
    }

    static Gender fromParam(String param) {
        return Optional.ofNullable(param)
                .map(paramMap::get)
                .orElseThrow(() -&amp;gt; new IllegalArgumentException(&amp;quot;param is not valid&amp;quot;));
    }

    String getParam() {
        return this.param;
    }
}

System.out.println(Gender.fromParam(&amp;quot;male&amp;quot;));

--------- output -----------
MALE&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;static 으로 &lt;code&gt;Map&amp;lt;String, Gender&amp;gt;&lt;/code&gt; 변수를 선언하여 거기에 값을 채워넣고, static  &lt;code&gt;fromParam&lt;/code&gt; 메소드를 사용하여  String 값으로 &lt;code&gt;Gender&lt;/code&gt; 값을 가져온다.&lt;/p&gt;
&lt;h2&gt;7. Map 의 종류&lt;/h2&gt;
&lt;p&gt;Map 에는 다음과 같은 종류가 있다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;HashMap : key - value 로 저장되며 key 의 중복을 허용하지 않는다&lt;/li&gt;
&lt;li&gt;TreeMap : HashMap 의 기능에 key 가 정렬되어 있다.&lt;/li&gt;
&lt;li&gt;LinkedHashMap: HashMap 의 기능에 key 입력 순서대로 출력된다.&lt;/li&gt;
&lt;li&gt;MultiValueMap: HashMap 가 다른 점이 key 의 중복을 허용한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;다만, MultiValueMap 을 사용하기 위해서는  &lt;code&gt;spring-core&lt;/code&gt; 패키지를 import 해야 한다. (apache commons 의 commons-collections4 에도 MultiValueMap 은 있지만 spring-core 가 더 사용하기 편하다) &lt;/p&gt;
&lt;p&gt;pom.xml  에 아래와 같은 dependcy 를 추가한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;dependencies&amp;gt;
    &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;spring-core&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;6.0.9&amp;lt;/version&amp;gt;
    &amp;lt;/dependency&amp;gt;
&amp;lt;/dependencies&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;MultiValueMap&amp;lt;String, String&amp;gt; map = new LinkedMultiValueMap&amp;lt;&amp;gt;();
map.add(&amp;quot;Accept-Encoding&amp;quot;, &amp;quot;compress;q=0.5&amp;quot;);
map.add(&amp;quot;Accept-Encoding&amp;quot;, &amp;quot;gzip;q=1.0&amp;quot;);

map.forEach((key, value) -&amp;gt; System.out.println(key + &amp;quot; &amp;quot; + value));

--------- output -----------
Accept-Encoding [compress;q=0.5, gzip;q=1.0]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;REST API 를 만들 때 Header 에 값을 넣기 위해서 위와 같이 MultiValueMap 을 사용한다.&lt;/p&gt;</description>
      <category>프로그래밍/Java</category>
      <category>java</category>
      <category>MSA</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/315</guid>
      <comments>https://ahnseungkyu.com/315#entry315comment</comments>
      <pubDate>Thu, 27 Jul 2023 08:24:29 +0900</pubDate>
    </item>
    <item>
      <title>Custom Controller 3 - CronJob 구현하기</title>
      <link>https://ahnseungkyu.com/314</link>
      <description>&lt;p&gt;Kubernetes 에는 이미 CronJob 이라는 리소스 타입이 있지만, Kubebuilder 을 이용하여 Custom Controller 로 재작성 해보는 연습을 해보도록 하자.&lt;/p&gt;
&lt;h2&gt;Project 구조 만들기&lt;/h2&gt;
&lt;p&gt;먼저, Project 구조를 만들기 위해 아래와 같이 &lt;code&gt;kubebuilder init&lt;/code&gt; 명령어를 실행한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ mkdir -p cronjob-kubebuilder
$ cd cronjob-kubebuilder

$ kubebuilder init --domain tutorial.kubebuilder.io --repo tutorial.kubebuilder.io/project&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;도메인을 &lt;code&gt;tutorial.kubebuilder.io&lt;/code&gt; 로 했으므로 모든 API Group 은 &lt;code&gt;&amp;lt;group&amp;gt;.tutorial.kubebuilder.io&lt;/code&gt; 방식으로 정해지게 된다. 또한 특별히 프로젝트 이름은 지정하지 않았는데, &lt;code&gt;--project-name=&amp;lt;dns1123-label-string&amp;gt;&lt;/code&gt; 과 같이 옵션을 추가하지 않으면 폴더의 이름이 기본적으로 프로젝트 이름이 된다. (여기서 프로젝트명은 DNS-1123 label 규칙을 따라야 한다)&lt;/p&gt;
&lt;p&gt;한가지 주의해야 할 점은 &lt;code&gt;cronjob-kubebuilder&lt;/code&gt; 디렉토리는 &lt;code&gt;$GOPATH&lt;/code&gt; 경로 아래에 있어서는 안된다. 이는 &lt;code&gt;Go modules&lt;/code&gt; 의 규칙 때문인데 좀 더 자세히 알고 싶으면 &lt;a href=&quot;https://go.dev/blog/using-go-modules&quot;&gt;https://go.dev/blog/using-go-modules&lt;/a&gt; 블로그 포스트를 읽어보자. &lt;/p&gt;
&lt;p&gt;만들어진 프로젝트의 구조는 다음과 같다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ tree -L 2
.
├── Dockerfile
├── Makefile
├── PROJECT
├── README.md
├── cmd
│   └── main.go
├── config
│   ├── default
│   ├── manager
│   ├── prometheus
│   └── rbac
├── go.mod
├── go.sum
└── hack
    └── boilerplate.go.txt

7 directories, 8 files&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;go.mod&lt;/code&gt; 파일은 모듈 디펜던시를 표시하고, &lt;code&gt;Makefile&lt;/code&gt; 은 custom controller  를 빌드하고 디플로이 할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;config&lt;/code&gt; 디렉토리 아래에는 Kustomize 로 작성되어 &lt;code&gt;CustomResourceDefinition&lt;/code&gt;, &lt;code&gt;RBAC&lt;/code&gt;, &lt;code&gt;WebhookConfiguration&lt;/code&gt; 등의 yaml 파일들이 정의되어 있다.&lt;/p&gt;
&lt;p&gt;특히, &lt;code&gt;config/manager&lt;/code&gt; 디렉토리에는 Cluster 에 Custom Controller 를 파드 형태로 배포할 수 있는 Kustomize yaml 이 있고, &lt;code&gt;config/rbac&lt;/code&gt; 디렉토리에는 서비스 어카운트로 Custom Controller 의 권한이 정의되어 있다. &lt;/p&gt;
&lt;p&gt;Custom Controller 의 Entrypoint 는 &lt;code&gt;cmd/main.go&lt;/code&gt; 파일이다.&lt;/p&gt;
&lt;p&gt;처음 필요한 모듈을 임포트 한 것을 보면 아래 2개가 보인다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;core &lt;code&gt;controller-runtime&lt;/code&gt; 라이브러리&lt;/li&gt;
&lt;li&gt;기본 controller-runtime 로깅인 &lt;code&gt;Zap&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;package main

import (
    &amp;quot;flag&amp;quot;
    &amp;quot;fmt&amp;quot;
    &amp;quot;os&amp;quot;

    _ &amp;quot;k8s.io/client-go/plugin/pkg/client/auth&amp;quot;

    &amp;quot;k8s.io/apimachinery/pkg/runtime&amp;quot;
    utilruntime &amp;quot;k8s.io/apimachinery/pkg/util/runtime&amp;quot;
    clientgoscheme &amp;quot;k8s.io/client-go/kubernetes/scheme&amp;quot;
    _ &amp;quot;k8s.io/client-go/plugin/pkg/client/auth/gcp&amp;quot;
    ctrl &amp;quot;sigs.k8s.io/controller-runtime&amp;quot;
    &amp;quot;sigs.k8s.io/controller-runtime/pkg/cache&amp;quot;
    &amp;quot;sigs.k8s.io/controller-runtime/pkg/healthz&amp;quot;
    &amp;quot;sigs.k8s.io/controller-runtime/pkg/log/zap&amp;quot;
    // +kubebuilder:scaffold:imports
)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;모든 컨트롤러에는 &lt;code&gt;Scheme&lt;/code&gt; 이 필요하다. 스킴은 &lt;code&gt;Kind&lt;/code&gt; 와 &lt;code&gt;Go types&lt;/code&gt; 간의 매핑을 제공해 준다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;var (
    scheme   = runtime.NewScheme()
    setupLog = ctrl.Log.WithName(&amp;quot;setup&amp;quot;)
)

func init() {
    utilruntime.Must(clientgoscheme.AddToScheme(scheme))

    //+kubebuilder:scaffold:scheme
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;main function&lt;/code&gt; 에는 아래의 내용들이 들어가 있다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;기본 플래그 셋업&lt;/li&gt;
&lt;li&gt;&lt;code&gt;manager&lt;/code&gt; 를 생성하여 모든 Custom Controller 의 실행을 추적하고, shared cache 세팅하고, &lt;code&gt;scheme&lt;/code&gt; 을 아규먼트로 넘기주어 클라이언트를 API 서버에 설정한다.&lt;/li&gt;
&lt;li&gt;manager 를 실행하면 manager 가 모든 컨트롤러와 웹혹을 실행한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;func main() {
    var metricsAddr string
    var enableLeaderElection bool
    var probeAddr string
    flag.StringVar(&amp;amp;metricsAddr, &amp;quot;metrics-bind-address&amp;quot;, &amp;quot;:8080&amp;quot;, &amp;quot;The address the metric endpoint binds to.&amp;quot;)
    flag.StringVar(&amp;amp;probeAddr, &amp;quot;health-probe-bind-address&amp;quot;, &amp;quot;:8081&amp;quot;, &amp;quot;The address the probe endpoint binds to.&amp;quot;)
    flag.BoolVar(&amp;amp;enableLeaderElection, &amp;quot;leader-elect&amp;quot;, false,
        &amp;quot;Enable leader election for controller manager. &amp;quot;+
            &amp;quot;Enabling this will ensure there is only one active controller manager.&amp;quot;)
    opts := zap.Options{
        Development: true,
    }
    opts.BindFlags(flag.CommandLine)
    flag.Parse()

    ctrl.SetLogger(zap.New(zap.UseFlagOptions(&amp;amp;opts)))

    mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
        Scheme:                 scheme,
        MetricsBindAddress:     metricsAddr,
        Port:                   9443,
        HealthProbeBindAddress: probeAddr,
        LeaderElection:         enableLeaderElection,
        LeaderElectionID:       &amp;quot;80807133.tutorial.kubebuilder.io&amp;quot;,
    })
    if err != nil {
        setupLog.Error(err, &amp;quot;unable to start manager&amp;quot;)
        os.Exit(1)
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;manager&lt;/code&gt; 생성 시에 컨트롤러가 특정 네임스페이스의 리소스만을 감시할 수 있도록 할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;    mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
        Scheme:                 scheme,
        Namespace:              namespace,
        MetricsBindAddress:     metricsAddr,
        Port:                   9443,
        HealthProbeBindAddress: probeAddr,
        LeaderElection:         enableLeaderElection,
        LeaderElectionID:       &amp;quot;80807133.tutorial.kubebuilder.io&amp;quot;,
    })&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이렇게 특정 네임스페이스를 지정한 경우에는 권한을 &lt;code&gt;ClusterRole&lt;/code&gt; 과 &lt;code&gt;ClusterRoleBinding&lt;/code&gt; 에서 &lt;code&gt;Role&lt;/code&gt; 과 &lt;code&gt;RoleBinding&lt;/code&gt; 으로 변경하는 것을 권장한다.&lt;/p&gt;
&lt;p&gt;그리고 &lt;code&gt;MutiNamespacedCacheBuilder&lt;/code&gt; 를 사용하면 특정 네임스페이스의 묶음의 리소스만을 감시하게 제한할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;    var namespaces []string // List of Namespaces
    cache.Options.Namespaces = namespaces

    mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
        Scheme:                 scheme,
        NewCache:               cache.MultiNamespacedCacheBuilder(namespaces),
        MetricsBindAddress:     fmt.Sprintf(&amp;quot;%s:%d&amp;quot;, metricsHost, metricsPort),
        Port:                   9443,
        HealthProbeBindAddress: probeAddr,
        LeaderElection:         enableLeaderElection,
        LeaderElectionID:       &amp;quot;80807133.tutorial.kubebuilder.io&amp;quot;,
    }) &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;MultiNamespacedCacheBuilder&lt;/code&gt; 는 deprecated api 이므로 &lt;code&gt;cache.Options.Namespaces&lt;/code&gt; 를 사용한다. (&lt;a href=&quot;https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/cache#Options&quot;&gt;https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/cache#Options&lt;/a&gt;)&lt;/p&gt;
&lt;h2&gt;Groups, Versions, Kinds and Resources&lt;/h2&gt;
&lt;p&gt;쿠버네티스에서 API 에 대해서 이야기할 때는 groups, versions, kinds and resources 4개의 용어를 사용한다.&lt;/p&gt;
&lt;p&gt;쿠버네티스의 API Group 은 단순히 관련 기능의 모음이다. 각 Group 에는 하나 이상의 Version 이 있으며, 이름에서 알 수 있듯이 시간이 지남에 따라 API의 작동 방식을 변경할 수 있다.&lt;/p&gt;
&lt;p&gt;각 API group-version 에는 하나 이상의 API type 이 포함되며, 이를 Kind 라고 부른다. Kind 는 Version 간에 양식을 변경할 수 있지만, 각 양식은 어떻게든 다른 양식의 모든 데이터를 저장할 수 있어야 한다(데이터를 필드 또는 주석에 저장할 수 있음). 즉, 이전 API 버전을 사용해도 최신 데이터가 손실되거나 손상되지 않는다.&lt;/p&gt;
&lt;p&gt;Resource 란 간단히 말해서 API 안에서 Kind 를 사용하는 것이다. 종종, Kind 와 Resource 는 일대일로 매핑된다. 예를 들어, Pod Resource 는 Pod Kind 에 해당한다. 그러나 때로는 여러 Resource 에서 동일한 Kind를 반환할 수도 있다. 예를 들어, Scale Kind 는 deployments/scale 또는 replicasets/scale 과 같은 모든 scale 하위 리소스에 의해 반환된다. 이것이 바로 Kubernetes HorizontalPodAutoscaler 가 서로 다른 resource 와 상호 작용할 수 있는 이유다. 그러나 CRD를 사용하면 각 Kind 는 단일 resource 에 해당한다.&lt;/p&gt;
&lt;p&gt;resource 는 항상 소문자이며, 관례에 따라 소문자 형태의 Kind를 사용한다.&lt;/p&gt;
&lt;p&gt;특정 group-version 에서 어떤 kind 를 지칭할 때는 줄여서 GroupVersionKind 혹은 줄여서 GVK 라고 부른다. 같은 방식으로 resource 도 GroupVersionResource 혹은 GVR 이라고 부른다.&lt;/p&gt;
&lt;p&gt;GVK 는 패키지에서 Go type 에 해당한다. &lt;/p&gt;
&lt;p&gt;API 는 왜 만들어야 할까?&lt;/p&gt;
&lt;p&gt;Kind 에 대해서 Custom Resource (CR) 과 Custom Resource Definition (CRD) 을 만들어야 한다. 그 이유는 CustomResourceDefinitions 으로 Kubernetes API 를 확장할 수 있기 때문이다.&lt;/p&gt;
&lt;p&gt;새롭게 만드는 API 는 쿠버네티스에게 custom object 를 가리치는 방법이다. &lt;/p&gt;
&lt;p&gt;기본으로 CRD 는 customized Objects 의 정의이며, CR 은 그것에 대한 인스턴스이다.&lt;/p&gt;
&lt;h2&gt;API 추가&lt;/h2&gt;
&lt;p&gt;아래 명령으로 새로운 Kind 를 추가하자.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ kubebuilder create api --group batch --version v1 --kind CronJob&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Create Resource  와 Create Controller 를 하겠냐고 물으면 &lt;code&gt;y&lt;/code&gt; 로 대답한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ tree -L 2
.
├── Dockerfile
├── Makefile
├── PROJECT
├── README.md
├── api
│   └── v1
├── bin
│   └── controller-gen
├── cmd
│   └── main.go
├── config
│   ├── crd
│   ├── default
│   ├── manager
│   ├── prometheus
│   ├── rbac
│   └── samples
├── go.mod
├── go.sum
├── hack
│   └── boilerplate.go.txt
└── internal
    └── controller &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이 경우 &lt;code&gt;batch.tutorial.kubebuilder.io/v1&lt;/code&gt; 에 해당하는 &lt;code&gt;api/v1&lt;/code&gt; 디렉토리가 생성된다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;api/v1/cronjob_types.go&lt;/code&gt; 파일을 보면, 모든 쿠버네티스 Kind 에 공통으로 포함된 metadata 를 가리키는 &lt;code&gt;meta/v1&lt;/code&gt; API group 을 임포트 하고 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;package v1

import (
    metav1 &amp;quot;k8s.io/apimachinery/pkg/apis/meta/v1&amp;quot;
)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;다음으로 Kind 의 &lt;code&gt;Spec&lt;/code&gt; 과 &lt;code&gt;Status&lt;/code&gt; 에 대한 type 을 정의 한다.&lt;/p&gt;
&lt;p&gt;쿠버네티스는 원하는 상태(Spec)를 실제 클러스터 상태(Status) 및 외부 상태와 조정한 다음 관찰한 것(Status)를 기록하는 방식으로 작동한다. 따라서 모든 기능 object 는 spec 과 status 를 포함한다. ConfigMap 과 같은 몇몇 타입은 원하는 상태를 인코딩하지 않기 때문에 이 패턴을 따르지 않지만 대부분의 타입은 이 패턴을 따른다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;// EDIT THIS FILE!  THIS IS SCAFFOLDING FOR YOU TO OWN!
// NOTE: json tags are required.  Any new fields you add must have json tags for the fields to be serialized.

// CronJobSpec defines the desired state of CronJob
type CronJobSpec struct {
    // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
    // Important: Run &amp;quot;make&amp;quot; to regenerate code after modifying this file
}

// CronJobStatus defines the observed state of CronJob
type CronJobStatus struct {
    // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
    // Important: Run &amp;quot;make&amp;quot; to regenerate code after modifying this file
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;실제 Kind 에 해당하는 타입인 CronJob 과 CronJobList 를 정의한다. CronJob 은 루트 타입이며, CronJob kind를 설명한다. 모든 쿠버네티스 오브젝트와 마찬가지로, API version 과 Kind 를 설명하는 TypeMeta를 포함하며, name, namespace, labes 과 같은 것을 보유하는 ObjectMeta 도 포함한다.&lt;/p&gt;
&lt;p&gt;CronJobList 는 단순히 여러 CronJob 을 위한 컨테이너이다. LIST와 같은 대량 작업에 사용되는 Kind 이다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;//+kubebuilder:object:root=true
//+kubebuilder:subresource:status

// CronJob is the Schema for the cronjobs API
type CronJob struct {
    metav1.TypeMeta   `json:&amp;quot;,inline&amp;quot;`
    metav1.ObjectMeta `json:&amp;quot;metadata,omitempty&amp;quot;`

    Spec   CronJobSpec   `json:&amp;quot;spec,omitempty&amp;quot;`
    Status CronJobStatus `json:&amp;quot;status,omitempty&amp;quot;`
}

//+kubebuilder:object:root=true

// CronJobList contains a list of CronJob
type CronJobList struct {
    metav1.TypeMeta `json:&amp;quot;,inline&amp;quot;`
    metav1.ListMeta `json:&amp;quot;metadata,omitempty&amp;quot;`
    Items           []CronJob `json:&amp;quot;items&amp;quot;`
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;마지막으로 API group 에 Go 타입을 추가한다. 이렇게 하면 이 API group 의 타입을 모든 Scheme 에 추가할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;func init() {
    SchemeBuilder.Register(&amp;amp;CronJob{}, &amp;amp;CronJobList{})
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;API 설계&lt;/h2&gt;
&lt;p&gt;쿠버네티스에는 API를 설계하는 방법에 대한 몇 가지 규칙이 있다. 즉, 직렬화된 모든 필드는 &lt;code&gt;camelCase&lt;/code&gt; 여야 하며 JSON 구조체 태그를 사용하여 이를 지정한다. 또한, 필드가 비어 있을 때 직렬화에서 필드를 생략해야 한다는 것을 표시하기 위해 &lt;code&gt;omitempty&lt;/code&gt; 구조체 태그를 사용할 수도 있다.&lt;/p&gt;
&lt;p&gt;필드는 대부분의 기본 유형을 사용할 수 있다. 다만 숫자는 예외이다. API 호환성을 위해 정수의 경우 &lt;code&gt;int32&lt;/code&gt; 및 &lt;code&gt;int64&lt;/code&gt;, 소수의 경우 &lt;code&gt;resource.Quantity&lt;/code&gt; 와 같이 3가지 형식의 숫자를 허용한다.&lt;/p&gt;
&lt;p&gt;Quantity 는 10진수에 대한 특수 표기법으로, 머신 간에 이식성을 높이기 위해 명시적으로 고정된 표현을 가지고 있다.&lt;/p&gt;
&lt;p&gt;예를 들어 &lt;code&gt;2m&lt;/code&gt; 값은 십진수 표기법에서 &lt;code&gt;0.002&lt;/code&gt; 를 의미한다. &lt;code&gt;2Ki&lt;/code&gt; 는 십진수로 &lt;code&gt;2048&lt;/code&gt; 을 의미하고, &lt;code&gt;2K&lt;/code&gt; 는 십진수로 &lt;code&gt;2000&lt;/code&gt; 을 의미한다. 분수를 지정하려면 정수를 사용할 수 있는 접미사로 전환하면 된다(예: &lt;code&gt;2.5&lt;/code&gt; 는 &lt;code&gt;2500m&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;지원되는 베이스는 두 가지이다: 10과 2(각각 10진수 및 2진수라고 함)이다. 10진수는 &amp;quot;nomal&amp;quot; SI 접미사(예: &lt;code&gt;M&lt;/code&gt; 및 &lt;code&gt;K&lt;/code&gt;)로 표시되며, 2진수는 &amp;quot;mebi&amp;quot; 표기법(예: &lt;code&gt;Mi&lt;/code&gt; 및 &lt;code&gt;Ki&lt;/code&gt;)으로 지정된다. 메가바이트와 메비바이트를 생각하면 된다.&lt;/p&gt;
&lt;p&gt;우리가 사용하는 또 다른 특수 유형이 하나 더 있는데, 바로 &lt;code&gt;metav1.Time&lt;/code&gt; 이다. 이것은 고정된 이식 가능한 직렬화 형식을 가지고 있다는 점을 제외하면 &lt;code&gt;time.Time&lt;/code&gt; 과 동일하게 작동한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;package v1

import (
    batchv1 &amp;quot;k8s.io/api/batch/v1&amp;quot;
    corev1 &amp;quot;k8s.io/api/core/v1&amp;quot;
    metav1 &amp;quot;k8s.io/apimachinery/pkg/apis/meta/v1&amp;quot;
)

// EDIT THIS FILE!  THIS IS SCAFFOLDING FOR YOU TO OWN!
// NOTE: json tags are required.  Any new fields you add must have json tags for the fields to b&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;CronJob 을 세부적으로 살펴보자.&lt;/p&gt;
&lt;p&gt;먼저 spec 을 보면, spec 에는 원하는 상태가 저장되므로 controller 에 대한 모든 &amp;quot;입력&amp;quot; 은 여기에 저장된다.&lt;/p&gt;
&lt;p&gt;기본적으로 크론잡에는 다음과 같은 요소가 필요하다:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;스케줄 (CronJob 내의 cron)&lt;/li&gt;
&lt;li&gt;실행할 Job 에 대한 template (CronJob 내의 job)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;편하게 만들어줄 몇 가지 추가 기능도 필요하다:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;job 시작에 대한 deadline (이 deadline 을 놓치면 다음 예정된 시간까지 기다리게 된다)&lt;/li&gt;
&lt;li&gt;여러 job 이 한 번에 실행될 경우 어떻게 할 것인가(기다릴 것인가? 기존 job 을 중지할 것인가? 둘 다 실행할 것인가?)&lt;/li&gt;
&lt;li&gt;CronJob 에 문제가 있을 경우, CronJob 실행을 일시 중지하는 방법&lt;/li&gt;
&lt;li&gt;이전 job 기록에 대한 limit&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;자신의 상태를 읽지 않기 때문에 job 이 실행되었는지 여부를 추적할 수 있는 다른 방법이 필요하다. 이를 위해 적어도 하나의 이전 job 을 사용할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;// CronJobSpec defines the desired state of CronJob
type CronJobSpec struct {
    //+kubebuilder:validation:MinLength=0

    // The schedule in Cron format, see https://en.wikipedia.org/wiki/Cron.
    Schedule string `json:&amp;quot;schedule&amp;quot;`

    //+kubebuilder:validation:Minimum=0

    // Optional deadline in seconds for starting the job if it misses scheduled
    // time for any reason.  Missed jobs executions will be counted as failed ones.
    // +optional
    StartingDeadlineSeconds *int64 `json:&amp;quot;startingDeadlineSeconds,omitempty&amp;quot;`

    // Specifies how to treat concurrent executions of a Job.
    // Valid values are:
    // - &amp;quot;Allow&amp;quot; (default): allows CronJobs to run concurrently;
    // - &amp;quot;Forbid&amp;quot;: forbids concurrent runs, skipping next run if previous run hasn&amp;#39;t finished yet;
    // - &amp;quot;Replace&amp;quot;: cancels currently running job and replaces it with a new one
    // +optional
    ConcurrencyPolicy ConcurrencyPolicy `json:&amp;quot;concurrencyPolicy,omitempty&amp;quot;`

    // This flag tells the controller to suspend subsequent executions, it does
    // not apply to already started executions.  Defaults to false.
    // +optional
    Suspend *bool `json:&amp;quot;suspend,omitempty&amp;quot;`

    // Specifies the job that will be created when executing a CronJob.
    JobTemplate batchv1.JobTemplateSpec `json:&amp;quot;jobTemplate&amp;quot;`

    //+kubebuilder:validation:Minimum=0

    // The number of successful finished jobs to retain.
    // This is a pointer to distinguish between explicit zero and not specified.
    // +optional
    SuccessfulJobsHistoryLimit *int32 `json:&amp;quot;successfulJobsHistoryLimit,omitempty&amp;quot;`

    //+kubebuilder:validation:Minimum=0

    // The number of failed finished jobs to retain.
    // This is a pointer to distinguish between explicit zero and not specified.
    // +optional
    FailedJobsHistoryLimit *int32 `json:&amp;quot;failedJobsHistoryLimit,omitempty&amp;quot;`
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ConcurrencyPolicy 는 실제로는 string 이지만, 재사용과 유효성 검사를 쉽게 할 수 있으므로 타입을 재정의 했다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;// ConcurrencyPolicy describes how the job will be handled.
// Only one of the following concurrent policies may be specified.
// If none of the following policies is specified, the default one
// is AllowConcurrent.
// +kubebuilder:validation:Enum=Allow;Forbid;Replace
type ConcurrencyPolicy string

const (
    // AllowConcurrent allows CronJobs to run concurrently.
    AllowConcurrent ConcurrencyPolicy = &amp;quot;Allow&amp;quot;

    // ForbidConcurrent forbids concurrent runs, skipping next run if previous
    // hasn&amp;#39;t finished yet.
    ForbidConcurrent ConcurrencyPolicy = &amp;quot;Forbid&amp;quot;

    // ReplaceConcurrent cancels currently running job and replaces it with a new one.
    ReplaceConcurrent ConcurrencyPolicy = &amp;quot;Replace&amp;quot;
)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;다음은 관찰된 상태를 저장하는 status 를 디자인해 보자. &lt;/p&gt;
&lt;p&gt;현재 실행중인 job 목록과 마지막으로 job 을 성공적으로 실행한 시간을 유지한다. 그리고 직렬화를 위해서 &lt;code&gt;time.Time&lt;/code&gt; 대신 &lt;code&gt;metav1.Time&lt;/code&gt; 을 사용한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;// CronJobStatus defines the observed state of CronJob
type CronJobStatus struct {
    // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
    // Important: Run &amp;quot;make&amp;quot; to regenerate code after modifying this file

    // A list of pointers to currently running jobs.
    // +optional
    Active []corev1.ObjectReference `json:&amp;quot;active,omitempty&amp;quot;`

    // Information when was the last time the job was successfully scheduled.
    // +optional
    LastScheduleTime *metav1.Time `json:&amp;quot;lastScheduleTime,omitempty&amp;quot;`
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Controller 구현&lt;/h2&gt;
&lt;p&gt;컨트롤러는 쿠버네티스와 모든 operator 의 핵심이다.&lt;/p&gt;
&lt;p&gt;컨트롤러의 역할은 주어진 오브젝트에 대해 실세계의 실제 상태(클러스터 상태와 잠재적으로 외부 상태(예: Kubelet의 경우 컨테이너 실행 또는 Cloud Provider 의 경우 로드밸런서)가 오브젝트의 원하는 상태와 일치하는지 확인하는 것이다. 각 컨트롤러는 하나의 루트 Kind 에 중점을 두지만 다른 Kind 와 상호 작용할 수 있다.&lt;/p&gt;
&lt;p&gt;이 프로세스를 &lt;code&gt;reconciling&lt;/code&gt; 이라고 부른다.&lt;/p&gt;
&lt;p&gt;controller-runtime 에서 특정 kind 에 대한 reconciling 을 구현하는 로직을 &lt;code&gt;Reconciler&lt;/code&gt; 라고 한다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;internal/controller/cronjob_controller.go&lt;/code&gt; 파일을 살펴 보자.&lt;/p&gt;
&lt;p&gt;기본으로 임포트하는 모듈이 있는데, core controller-runtime 라이브러리와 client 패키지, API 타입 패키지가 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;package controllers

import (
    &amp;quot;context&amp;quot;

    &amp;quot;k8s.io/apimachinery/pkg/runtime&amp;quot;
    ctrl &amp;quot;sigs.k8s.io/controller-runtime&amp;quot;
    &amp;quot;sigs.k8s.io/controller-runtime/pkg/client&amp;quot;
    &amp;quot;sigs.k8s.io/controller-runtime/pkg/log&amp;quot;

    batchv1 &amp;quot;tutorial.kubebuilder.io/project/api/v1&amp;quot;
)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;컨트롤러의 기본 로직은 다음과 같다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;명명된 CronJob을 로드한다.&lt;/li&gt;
&lt;li&gt;모든 active job 을 나열하고, status 를 업데이트 한다.&lt;/li&gt;
&lt;li&gt;히스토리 수 제한에 따라 오래된 job 을 정리한다.&lt;/li&gt;
&lt;li&gt;Suspend 값이 세팅되었는지 확인 (값이 세팅된 경우 다른 작업을 수행하지 않음)&lt;/li&gt;
&lt;li&gt;다음 예약된 실행 가져오기&lt;/li&gt;
&lt;li&gt;새로운 job 이 스케줄에 맞고, deadline 이 지나지 않았으며, 동시성 정책에 의해 차단되지 않은 경우 실행&lt;/li&gt;
&lt;li&gt;실행 중인 job 이 보이거나 (자동으로 수행됨) 다음 예약된 실행 시간이 되면 Requeue 한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;임포트 모듈을 추가한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;package controller

import (
    &amp;quot;context&amp;quot;
    &amp;quot;fmt&amp;quot;
    &amp;quot;sort&amp;quot;
    &amp;quot;time&amp;quot;

    &amp;quot;github.com/robfig/cron&amp;quot;
    kbatch &amp;quot;k8s.io/api/batch/v1&amp;quot;
    corev1 &amp;quot;k8s.io/api/core/v1&amp;quot;
    metav1 &amp;quot;k8s.io/apimachinery/pkg/apis/meta/v1&amp;quot;
    &amp;quot;k8s.io/apimachinery/pkg/runtime&amp;quot;
    ref &amp;quot;k8s.io/client-go/tools/reference&amp;quot;
    ctrl &amp;quot;sigs.k8s.io/controller-runtime&amp;quot;
    &amp;quot;sigs.k8s.io/controller-runtime/pkg/client&amp;quot;
    &amp;quot;sigs.k8s.io/controller-runtime/pkg/log&amp;quot;

    batchv1 &amp;quot;tutorial.kubebuilder.io/project/api/v1&amp;quot;
)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;테스트를 위해서 Clock 을 추가한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;// CronJobReconciler reconciles a CronJob object
type CronJobReconciler struct {
    client.Client
    Scheme *runtime.Scheme
    Clock
}

type realClock struct{}

func (_ realClock) Now() time.Time { return time.Now() }

// clock knows how to get the current time.
// It can be used to fake out timing for testing.
type Clock interface {
    Now() time.Time
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;RBAC 을 위해 batch group 의 job 을 핸들링 할 수 있는 권한을 추가한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;//+kubebuilder:rbac:groups=batch.tutorial.kubebuilder.io,resources=cronjobs,verbs=get;list;watch;create;update;patch;delete
//+kubebuilder:rbac:groups=batch.tutorial.kubebuilder.io,resources=cronjobs/status,verbs=get;update;patch
//+kubebuilder:rbac:groups=batch.tutorial.kubebuilder.io,resources=cronjobs/finalizers,verbs=update
//+kubebuilder:rbac:groups=batch,resources=jobs,verbs=get;list;watch;create;update;patch;delete
//+kubebuilder:rbac:groups=batch,resources=jobs/status,verbs=get&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;annotation 을 위한 변수를 추가한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;var (
    scheduledTimeAnnotation = &amp;quot;batch.tutorial.kubebuilder.io/scheduled-at&amp;quot;
)

// Reconcile is part of the main kubernetes reconciliation loop which aims to
// move the current state of the cluster closer to the desired state.
// TODO(user): Modify the Reconcile function to compare the state specified by
// the CronJob object against the actual cluster state, and then
// perform operations to make the cluster state reflect the state specified by
// the user.
//
// For more details, check Reconcile and its Result here:
// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.15.0/pkg/reconcile
func (r *CronJobReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
    log := log.FromContext(ctx)&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;1. 이름으로 CronJob 을 로드한다&lt;/h3&gt;
&lt;p&gt;client 를 사용하여 CronJob 을 가져온다. 모든 client 의 메소드에는 취소가 가능하게 context 를 아규먼트로 받는다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;    var cronJob batchv1.CronJob
    if err := r.Get(ctx, req.NamespacedName, &amp;amp;cronJob); err != nil {
        log.Error(err, &amp;quot;unable to fetch CronJob&amp;quot;)
        // we&amp;#39;ll ignore not-found errors, since they can&amp;#39;t be fixed by an immediate
        // requeue (we&amp;#39;ll need to wait for a new notification), and we can get them
        // on deleted requests.
        return ctrl.Result{}, client.IgnoreNotFound(err)
    }&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. 모든 active job 을 나열하고 status 를 업데이트 한다.&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;    var childJobs kbatch.JobList
    if err := r.List(ctx, &amp;amp;childJobs, client.InNamespace(req.Namespace), client.MatchingFields{jobOwnerKey: req.Name}); err != nil {
        log.Error(err, &amp;quot;unable to list child Jobs&amp;quot;)
        return ctrl.Result{}, err
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;active job 을 조회했으면 이를 active, successful, failded job 으로 분류한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;    // find the active list of jobs
    var activeJobs []*kbatch.Job
    var successfulJobs []*kbatch.Job
    var failedJobs []*kbatch.Job
    var mostRecentTime *time.Time // find the last run so we can update the status&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;    isJobFinished := func(job *kbatch.Job) (bool, kbatch.JobConditionType) {
        for _, c := range job.Status.Conditions {
            if (c.Type == kbatch.JobComplete || c.Type == kbatch.JobFailed) &amp;amp;&amp;amp; c.Status == corev1.ConditionTrue {
                return true, c.Type
            }
        }

        return false, &amp;quot;&amp;quot;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;    getScheduledTimeForJob := func(job *kbatch.Job) (*time.Time, error) {
        timeRaw := job.Annotations[scheduledTimeAnnotation]
        if len(timeRaw) == 0 {
            return nil, nil
        }

        timeParsed, err := time.Parse(time.RFC3339, timeRaw)
        if err != nil {
            return nil, err
        }
        return &amp;amp;timeParsed, nil
    }
    for i, job := range childJobs.Items {
        _, finishedType := isJobFinished(&amp;amp;job)
        switch finishedType {
        case &amp;quot;&amp;quot;: // ongoing
            activeJobs = append(activeJobs, &amp;amp;childJobs.Items[i])
        case kbatch.JobFailed:
            failedJobs = append(failedJobs, &amp;amp;childJobs.Items[i])
        case kbatch.JobComplete:
            successfulJobs = append(successfulJobs, &amp;amp;childJobs.Items[i])
        }

        // We&amp;#39;ll store the launch time in an annotation, so we&amp;#39;ll reconstitute that from
        // the active jobs themselves.
        scheduledTimeForJob, err := getScheduledTimeForJob(&amp;amp;job)
        if err != nil {
            log.Error(err, &amp;quot;unable to parse schedule time for child job&amp;quot;, &amp;quot;job&amp;quot;, &amp;amp;job)
            continue
        }
        if scheduledTimeForJob != nil {
            if mostRecentTime == nil {
                mostRecentTime = scheduledTimeForJob
            } else if mostRecentTime.Before(*scheduledTimeForJob) {
                mostRecentTime = scheduledTimeForJob
            }
        }
    }

    if mostRecentTime != nil {
        cronJob.Status.LastScheduleTime = &amp;amp;metav1.Time{Time: *mostRecentTime}
    } else {
        cronJob.Status.LastScheduleTime = nil
    }
    cronJob.Status.Active = nil
    for _, activeJob := range activeJobs {
        jobRef, err := ref.GetReference(r.Scheme, activeJob)
        if err != nil {
            log.Error(err, &amp;quot;unable to make reference to active job&amp;quot;, &amp;quot;job&amp;quot;, activeJob)
            continue
        }
        cronJob.Status.Active = append(cronJob.Status.Active, *jobRef)
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;디버깅을 위해서 log 를 남긴다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;    log.V(1).Info(&amp;quot;job count&amp;quot;, &amp;quot;active jobs&amp;quot;, len(activeJobs), &amp;quot;successful jobs&amp;quot;, len(successfulJobs), &amp;quot;failed jobs&amp;quot;, len(failedJobs))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;status 를 업데이트 한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;    if err := r.Status().Update(ctx, &amp;amp;cronJob); err != nil {
        log.Error(err, &amp;quot;unable to update CronJob status&amp;quot;)
        return ctrl.Result{}, err
    }&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. 히스토리 수 제한에 따른 오래된 job 삭제하기&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;    // NB: deleting these are &amp;quot;best effort&amp;quot; -- if we fail on a particular one,
    // we won&amp;#39;t requeue just to finish the deleting.
    if cronJob.Spec.FailedJobsHistoryLimit != nil {
        sort.Slice(failedJobs, func(i, j int) bool {
            if failedJobs[i].Status.StartTime == nil {
                return failedJobs[j].Status.StartTime != nil
            }
            return failedJobs[i].Status.StartTime.Before(failedJobs[j].Status.StartTime)
        })
        for i, job := range failedJobs {
            if int32(i) &amp;gt;= int32(len(failedJobs))-*cronJob.Spec.FailedJobsHistoryLimit {
                break
            }
            if err := r.Delete(ctx, job, client.PropagationPolicy(metav1.DeletePropagationBackground)); client.IgnoreNotFound(err) != nil {
                log.Error(err, &amp;quot;unable to delete old failed job&amp;quot;, &amp;quot;job&amp;quot;, job)
            } else {
                log.V(0).Info(&amp;quot;deleted old failed job&amp;quot;, &amp;quot;job&amp;quot;, job)
            }
        }
    }

    if cronJob.Spec.SuccessfulJobsHistoryLimit != nil {
        sort.Slice(successfulJobs, func(i, j int) bool {
            if successfulJobs[i].Status.StartTime == nil {
                return successfulJobs[j].Status.StartTime != nil
            }
            return successfulJobs[i].Status.StartTime.Before(successfulJobs[j].Status.StartTime)
        })
        for i, job := range successfulJobs {
            if int32(i) &amp;gt;= int32(len(successfulJobs))-*cronJob.Spec.SuccessfulJobsHistoryLimit {
                break
            }
            if err := r.Delete(ctx, job, client.PropagationPolicy(metav1.DeletePropagationBackground)); (err) != nil {
                log.Error(err, &amp;quot;unable to delete old successful job&amp;quot;, &amp;quot;job&amp;quot;, job)
            } else {
                log.V(0).Info(&amp;quot;deleted old successful job&amp;quot;, &amp;quot;job&amp;quot;, job)
            }
        }
    }&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4. Suspend 값이 세팅되었는지 확인&lt;/h3&gt;
&lt;p&gt;CronJob 객체에 suspend 값이 세팅되어 있다면 CronJob 을 일시 중단한다. CronJob 을 삭제하지 않고 잠시 멈추고 싶을 때 사용할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;    if cronJob.Spec.Suspend != nil &amp;amp;&amp;amp; *cronJob.Spec.Suspend {
        log.V(1).Info(&amp;quot;cronjob suspended, skipping&amp;quot;)
        return ctrl.Result{}, nil
    }&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;5. 다음 예약된 실행 가져오기&lt;/h3&gt;
&lt;p&gt;잠시 멈춤 상태가 아니라면 다음 스케줄을 가져온다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;    getNextSchedule := func(cronJob *batchv1.CronJob, now time.Time) (lastMissed time.Time, next time.Time, err error) {
        sched, err := cron.ParseStandard(cronJob.Spec.Schedule)
        if err != nil {
            return time.Time{}, time.Time{}, fmt.Errorf(&amp;quot;Unparseable schedule %q: %v&amp;quot;, cronJob.Spec.Schedule, err)
        }

        // for optimization purposes, cheat a bit and start from our last observed run time
        // we could reconstitute this here, but there&amp;#39;s not much point, since we&amp;#39;ve
        // just updated it.
        var earliestTime time.Time
        if cronJob.Status.LastScheduleTime != nil {
            earliestTime = cronJob.Status.LastScheduleTime.Time
        } else {
            earliestTime = cronJob.ObjectMeta.CreationTimestamp.Time
        }
        if cronJob.Spec.StartingDeadlineSeconds != nil {
            // controller is not going to schedule anything below this point
            schedulingDeadline := now.Add(-time.Second * time.Duration(*cronJob.Spec.StartingDeadlineSeconds))

            if schedulingDeadline.After(earliestTime) {
                earliestTime = schedulingDeadline
            }
        }
        if earliestTime.After(now) {
            return time.Time{}, sched.Next(now), nil
        }

        starts := 0
        for t := sched.Next(earliestTime); !t.After(now); t = sched.Next(t) {
            lastMissed = t
            // An object might miss several starts. For example, if
            // controller gets wedged on Friday at 5:01pm when everyone has
            // gone home, and someone comes in on Tuesday AM and discovers
            // the problem and restarts the controller, then all the hourly
            // jobs, more than 80 of them for one hourly scheduledJob, should
            // all start running with no further intervention (if the scheduledJob
            // allows concurrency and late starts).
            //
            // However, if there is a bug somewhere, or incorrect clock
            // on controller&amp;#39;s server or apiservers (for setting creationTimestamp)
            // then there could be so many missed start times (it could be off
            // by decades or more), that it would eat up all the CPU and memory
            // of this controller. In that case, we want to not try to list
            // all the missed start times.
            starts++
            if starts &amp;gt; 100 {
                // We can&amp;#39;t get the most recent times so just return an empty slice
                return time.Time{}, time.Time{}, fmt.Errorf(&amp;quot;Too many missed start times (&amp;gt; 100). Set or decrease .spec.startingDeadlineSeconds or check clock skew.&amp;quot;)
            }
        }
        return lastMissed, sched.Next(now), nil
    }&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;    // figure out the next times that we need to create
    // jobs at (or anything we missed).
    missedRun, nextRun, err := getNextSchedule(&amp;amp;cronJob, r.Now())
    if err != nil {
        log.Error(err, &amp;quot;unable to figure out CronJob schedule&amp;quot;)
        // we don&amp;#39;t really care about requeuing until we get an update that
        // fixes the schedule, so don&amp;#39;t return an error
        return ctrl.Result{}, nil
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;requeue 할 값을 준비만 해 놓는다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;    scheduledResult := ctrl.Result{RequeueAfter: nextRun.Sub(r.Now())} // save this so we can re-use it elsewhere
    log = log.WithValues(&amp;quot;now&amp;quot;, r.Now(), &amp;quot;next run&amp;quot;, nextRun)&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;6. 새로운 job 이 스케줄에 맞고, deadline 이 지나지 않았으며, 동시성 정책에 의해 차단되지 않은 경우 실행&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;    if missedRun.IsZero() {
        log.V(1).Info(&amp;quot;no upcoming scheduled times, sleeping until next&amp;quot;)
        return scheduledResult, nil
    }

    // make sure we&amp;#39;re not too late to start the run
    log = log.WithValues(&amp;quot;current run&amp;quot;, missedRun)
    tooLate := false
    if cronJob.Spec.StartingDeadlineSeconds != nil {
        tooLate = missedRun.Add(time.Duration(*cronJob.Spec.StartingDeadlineSeconds) * time.Second).Before(r.Now())
    }
    if tooLate {
        log.V(1).Info(&amp;quot;missed starting deadline for last run, sleeping till next&amp;quot;)
        // TODO(directxman12): events
        return scheduledResult, nil
    }&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;    // figure out how to run this job -- concurrency policy might forbid us from running
    // multiple at the same time...
    if cronJob.Spec.ConcurrencyPolicy == batchv1.ForbidConcurrent &amp;amp;&amp;amp; len(activeJobs) &amp;gt; 0 {
        log.V(1).Info(&amp;quot;concurrency policy blocks concurrent runs, skipping&amp;quot;, &amp;quot;num active&amp;quot;, len(activeJobs))
        return scheduledResult, nil
    }

    // ...or instruct us to replace existing ones...
    if cronJob.Spec.ConcurrencyPolicy == batchv1.ReplaceConcurrent {
        for _, activeJob := range activeJobs {
            // we don&amp;#39;t care if the job was already deleted
            if err := r.Delete(ctx, activeJob, client.PropagationPolicy(metav1.DeletePropagationBackground)); client.IgnoreNotFound(err) != nil {
                log.Error(err, &amp;quot;unable to delete active job&amp;quot;, &amp;quot;job&amp;quot;, activeJob)
                return ctrl.Result{}, err
            }
        }
    }&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;    constructJobForCronJob := func(cronJob *batchv1.CronJob, scheduledTime time.Time) (*kbatch.Job, error) {
        // We want job names for a given nominal start time to have a deterministic name to avoid the same job being created twice
        name := fmt.Sprintf(&amp;quot;%s-%d&amp;quot;, cronJob.Name, scheduledTime.Unix())

        job := &amp;amp;kbatch.Job{
            ObjectMeta: metav1.ObjectMeta{
                Labels:      make(map[string]string),
                Annotations: make(map[string]string),
                Name:        name,
                Namespace:   cronJob.Namespace,
            },
            Spec: *cronJob.Spec.JobTemplate.Spec.DeepCopy(),
        }
        for k, v := range cronJob.Spec.JobTemplate.Annotations {
            job.Annotations[k] = v
        }
        job.Annotations[scheduledTimeAnnotation] = scheduledTime.Format(time.RFC3339)
        for k, v := range cronJob.Spec.JobTemplate.Labels {
            job.Labels[k] = v
        }
        if err := ctrl.SetControllerReference(cronJob, job, r.Scheme); err != nil {
            return nil, err
        }

        return job, nil
    }&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;    // actually make the job...
    job, err := constructJobForCronJob(&amp;amp;cronJob, missedRun)
    if err != nil {
        log.Error(err, &amp;quot;unable to construct job from template&amp;quot;)
        // don&amp;#39;t bother requeuing until we get a change to the spec
        return scheduledResult, nil
    }

    // ...and create it on the cluster
    if err := r.Create(ctx, job); err != nil {
        log.Error(err, &amp;quot;unable to create Job for CronJob&amp;quot;, &amp;quot;job&amp;quot;, job)
        return ctrl.Result{}, err
    }

    log.V(1).Info(&amp;quot;created Job for CronJob run&amp;quot;, &amp;quot;job&amp;quot;, job)&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;7. 실행 중인 job 이 보이거나 (자동으로 수행됨) 다음 예약된 실행 시간이 되면 Requeue 한다.&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;    // we&amp;#39;ll requeue once we see the running job, and update our status
    return scheduledResult, nil
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Setup&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;var (
    jobOwnerKey = &amp;quot;.metadata.controller&amp;quot;
    apiGVStr    = batchv1.GroupVersion.String()
)

// SetupWithManager sets up the controller with the Manager.
func (r *CronJobReconciler) SetupWithManager(mgr ctrl.Manager) error {
    // set up a real clock, since we&amp;#39;re not in a test
    if r.Clock == nil {
        r.Clock = realClock{}
    }

    if err := mgr.GetFieldIndexer().IndexField(context.Background(), &amp;amp;kbatch.Job{}, jobOwnerKey, func(rawObj client.Object) []string {
        // grab the job object, extract the owner...
        job := rawObj.(*kbatch.Job)
        owner := metav1.GetControllerOf(job)
        if owner == nil {
            return nil
        }
        // ...make sure it&amp;#39;s a CronJob...
        if owner.APIVersion != apiGVStr || owner.Kind != &amp;quot;CronJob&amp;quot; {
            return nil
        }

        // ...and if so, return it
        return []string{owner.Name}
    }); err != nil {
        return err
    }

    return ctrl.NewControllerManagedBy(mgr).
        For(&amp;amp;batchv1.CronJob{}).
        Owns(&amp;amp;kbatch.Job{}).
        Complete(r)
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Webhook 생성&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ kubebuilder create webhook --group batch --version v1 --kind CronJob --defaulting --programmatic-validation&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;api/v1/cronjob_webhook.go&lt;/code&gt; 파일이 생성된다. 해당 파일에 체크 로직을 추가한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;// Default implements webhook.Defaulter so a webhook will be registered for the type
func (r *CronJob) Default() {
    cronjoblog.Info(&amp;quot;default&amp;quot;, &amp;quot;name&amp;quot;, r.Name)

    if r.Spec.ConcurrencyPolicy == &amp;quot;&amp;quot; {
        r.Spec.ConcurrencyPolicy = AllowConcurrent
    }
    if r.Spec.Suspend == nil {
        r.Spec.Suspend = new(bool)
    }
    if r.Spec.SuccessfulJobsHistoryLimit == nil {
        r.Spec.SuccessfulJobsHistoryLimit = new(int32)
        *r.Spec.SuccessfulJobsHistoryLimit = 3
    }
    if r.Spec.FailedJobsHistoryLimit == nil {
        r.Spec.FailedJobsHistoryLimit = new(int32)
        *r.Spec.FailedJobsHistoryLimit = 1
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;var _ webhook.Validator = &amp;amp;CronJob{}

// ValidateCreate implements webhook.Validator so a webhook will be registered for the type
func (r *CronJob) ValidateCreate() error {
    cronjoblog.Info(&amp;quot;validate create&amp;quot;, &amp;quot;name&amp;quot;, r.Name)

    return r.validateCronJob()
}

// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type
func (r *CronJob) ValidateUpdate(old runtime.Object) error {
    cronjoblog.Info(&amp;quot;validate update&amp;quot;, &amp;quot;name&amp;quot;, r.Name)

    return r.validateCronJob()
}

// ValidateDelete implements webhook.Validator so a webhook will be registered for the type
func (r *CronJob) ValidateDelete() error {
    cronjoblog.Info(&amp;quot;validate delete&amp;quot;, &amp;quot;name&amp;quot;, r.Name)

    // TODO(user): fill in your validation logic upon object deletion.
    return nil
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;func (r *CronJob) validateCronJob() error {
    var allErrs field.ErrorList
    if err := r.validateCronJobName(); err != nil {
        allErrs = append(allErrs, err)
    }
    if err := r.validateCronJobSpec(); err != nil {
        allErrs = append(allErrs, err)
    }
    if len(allErrs) == 0 {
        return nil
    }

    return apierrors.NewInvalid(
        schema.GroupKind{Group: &amp;quot;batch.tutorial.kubebuilder.io&amp;quot;, Kind: &amp;quot;CronJob&amp;quot;},
        r.Name, allErrs)
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;func (r *CronJob) validateCronJobSpec() *field.Error {
    // The field helpers from the kubernetes API machinery help us return nicely
    // structured validation errors.
    return validateScheduleFormat(
        r.Spec.Schedule,
        field.NewPath(&amp;quot;spec&amp;quot;).Child(&amp;quot;schedule&amp;quot;))
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;func validateScheduleFormat(schedule string, fldPath *field.Path) *field.Error {
    if _, err := cron.ParseStandard(schedule); err != nil {
        return field.Invalid(fldPath, schedule, err.Error())
    }
    return nil
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;func (r *CronJob) validateCronJobName() *field.Error {
    if len(r.ObjectMeta.Name) &amp;gt; validationutils.DNS1035LabelMaxLength-11 {
        // The job name length is 63 character like all Kubernetes objects
        // (which must fit in a DNS subdomain). The cronjob controller appends
        // a 11-character suffix to the cronjob (`-$TIMESTAMP`) when creating
        // a job. The job name length limit is 63 characters. Therefore cronjob
        // names must have length &amp;lt;= 63-11=52. If we don&amp;#39;t validate this here,
        // then job creation will fail later.
        return field.Invalid(field.NewPath(&amp;quot;metadata&amp;quot;).Child(&amp;quot;name&amp;quot;), r.Name, &amp;quot;must be no more than 52 characters&amp;quot;)
    }
    return nil
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Controller 배포 및 실행&lt;/h2&gt;
&lt;p&gt;CR 과 CRD yaml 을 만드는 명령어를 수행한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ make manifests&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;CRD 를 배포한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;
$ make install&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;WebHook 를 로컬에서 다른 터미널로 실행한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ export ENABLE_WEBHOOKS=false
$ make run&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;config/samples/batch_v1_cronjob.yaml&lt;/code&gt; 파일에 값을 추가한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;apiVersion: batch.tutorial.kubebuilder.io/v1
kind: CronJob
metadata:
  labels:
    app.kubernetes.io/name: cronjob
    app.kubernetes.io/instance: cronjob-sample
    app.kubernetes.io/part-of: cronjob-kubebuilder
    app.kubernetes.io/managed-by: kustomize
    app.kubernetes.io/created-by: cronjob-kubebuilder
  name: cronjob-sample
spec:
  schedule: &amp;quot;*/1 * * * *&amp;quot;
  startingDeadlineSeconds: 60
  concurrencyPolicy: Allow # explicitly specify, but Allow is also default.
  jobTemplate:
    spec:
      template:
        spec:
          containers:
            - name: hello
              image: busybox
              args:
                - /bin/sh
                - -c
                - date; echo Hello from the Kubernetes cluster
          restartPolicy: OnFailure&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Reference site&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://book.kubebuilder.io/cronjob-tutorial&quot;&gt;https://book.kubebuilder.io/cronjob-tutorial&lt;/a&gt;/&lt;/li&gt;
&lt;li&gt;cronJob webhook source:&lt;br&gt;&lt;a href=&quot;https://github.com/kubernetes-sigs/kubebuilder/blob/master/docs/book/src/cronjob-tutorial/testdata/project/api/v1/cronjob_webhook.go&quot;&gt;https://github.com/kubernetes-sigs/kubebuilder/blob/master/docs/book/src/cronjob-tutorial/testdata/project/api/v1/cronjob_webhook.go&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Writing a Kubernetes Operator from Scratch Using Kubebuilder:&lt;br&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=LLVoyXjYlYM&amp;amp;list=PL8pIiPkgexmmHAppEre9eHAiYqLxGFbOY&amp;amp;index=7&quot;&gt;https://www.youtube.com/watch?v=LLVoyXjYlYM&amp;amp;list=PL8pIiPkgexmmHAppEre9eHAiYqLxGFbOY&amp;amp;index=7&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;PVC Operator Sample Source:&lt;br&gt;&lt;a href=&quot;https://github.com/civo/operator-demo/blob/main/controllers/demovolume_controller.go&quot;&gt;https://github.com/civo/operator-demo/blob/main/controllers/demovolume_controller.go&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;elastic cloud-on-k8s source:&lt;br&gt;&lt;a href=&quot;https://github.com/elastic/cloud-on-k8s/blob/main/pkg/apis/elasticsearch/v1/elasticsearch_types.go&quot;&gt;https://github.com/elastic/cloud-on-k8s/blob/main/pkg/apis/elasticsearch/v1/elasticsearch_types.go&lt;/a&gt;&lt;br&gt;&lt;a href=&quot;https://github.com/elastic/cloud-on-k8s/blob/main/pkg/controller/elasticsearch/elasticsearch_controller.go&quot;&gt;https://github.com/elastic/cloud-on-k8s/blob/main/pkg/controller/elasticsearch/elasticsearch_controller.go&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Develop on Kubernetes Series — Operator Dev — Understanding and Dissecting Kubebuilder:&lt;br&gt;&lt;a href=&quot;https://yash-kukreja-98.medium.com/develop-on-kubernetes-series-operator-dev-understanding-and-dissecting-kubebuilder-4321d3ecd7d6&quot;&gt;https://yash-kukreja-98.medium.com/develop-on-kubernetes-series-operator-dev-understanding-and-dissecting-kubebuilder-4321d3ecd7d6&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Learning Concurrent Reconciling:&lt;br&gt;&lt;a href=&quot;https://openkruise.io/blog/learning-concurrent-reconciling/&quot;&gt;https://openkruise.io/blog/learning-concurrent-reconciling/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Operator Pattern: &lt;a href=&quot;https://kubernetes.io/docs/concepts/extend-kubernetes/operator/&quot;&gt;https://kubernetes.io/docs/concepts/extend-kubernetes/operator/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Best practices for building Kubernetes Operators and stateful apps:&lt;br&gt;&lt;a href=&quot;https://cloud.google.com/blog/products/containers-kubernetes/best-practices-for-building-kubernetes-operators-and-stateful-apps&quot;&gt;https://cloud.google.com/blog/products/containers-kubernetes/best-practices-for-building-kubernetes-operators-and-stateful-apps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Kubernetes Controllers at Scale: Clients, Caches, Conflicts, Patches Explained:&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@timebertt/kubernetes-controllers-at-scale-clients-caches-conflicts-patches-explained-aa0f7a8b4332&quot;&gt;https://medium.com/@timebertt/kubernetes-controllers-at-scale-clients-caches-conflicts-patches-explained-aa0f7a8b4332&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Kubernetes API guidelines: &lt;a href=&quot;https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md&quot;&gt;https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Golang controller-runtime: &lt;a href=&quot;https://pkg.go.dev/sigs.k8s.io/controller-runtime&quot;&gt;https://pkg.go.dev/sigs.k8s.io/controller-runtime&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Extend the Kubernetes API with CustomResourceDefinitions: &lt;a href=&quot;https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/&quot;&gt;https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Kubernetes</category>
      <category>CronJob Sample</category>
      <category>Custom Controller</category>
      <category>Kubebuilder</category>
      <category>Kubernetes Operator Pattern</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/314</guid>
      <comments>https://ahnseungkyu.com/314#entry314comment</comments>
      <pubDate>Wed, 12 Jul 2023 09:51:55 +0900</pubDate>
    </item>
    <item>
      <title>Custom Controller 2 - Kubebuilder Architecture</title>
      <link>https://ahnseungkyu.com/313</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Kubebuilder 의 아키텍처에 대해서 살펴보고 Kubebuilder 로 프로젝트를 생성하는 방법을 알아본다.&lt;/p&gt;
&lt;h1&gt;Kubebuilder Architeture&lt;/h1&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2644&quot; data-origin-height=&quot;2374&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nrTgI/btsjFSQdaw2/IRH2hPSDbJQJHiw1qYOObK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nrTgI/btsjFSQdaw2/IRH2hPSDbJQJHiw1qYOObK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nrTgI/btsjFSQdaw2/IRH2hPSDbJQJHiw1qYOObK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnrTgI%2FbtsjFSQdaw2%2FIRH2hPSDbJQJHiw1qYOObK%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;2644&quot; height=&quot;2374&quot; data-origin-width=&quot;2644&quot; data-origin-height=&quot;2374&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[출처: &lt;a href=&quot;https://book.kubebuilder.io/architecture.html&quot;&gt;https://book.kubebuilder.io/architecture.html&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;위의 다이어그램에서 Kubebuilder 는 controller-runtime 모듈을 사용하는 것을 알 수 있다. 또한 사용자의 비즈니스 로직은 Reconciler 에 위치 시킨다는 것을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;Kubebuilder 로 프로젝트 생성&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Kubebuilder 를 사용하기 위해서 사전 준비 작업이 필요하다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;br /&gt;사전 준비 작업&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://golang.org/dl/&quot;&gt;go&lt;/a&gt; version v1.19.0+&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/install/&quot;&gt;docker&lt;/a&gt; version 17.03+.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://kubernetes.io/docs/tasks/tools/install-kubectl/&quot;&gt;kubectl&lt;/a&gt; version v1.11.3+.&lt;/li&gt;
&lt;li&gt;Access to a Kubernetes v1.11.3+ cluster.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Kubebuilder 설치&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kubebuilder 는 간단히 다운 받아서 설치할 수 있다. &lt;code&gt;~/bin/&lt;/code&gt; 디렉토리가 &lt;code&gt;path&lt;/code&gt; 로 잡혀있기 때문에 다운 받은 바이너리 파일을 이 곳으로 이동시켰다.&lt;/p&gt;
&lt;pre class=&quot;groovy&quot;&gt;&lt;code&gt;$ cd ~/Documents/tmp

$ curl -L -o kubebuilder https://go.kubebuilder.io/dl/latest/$(go env GOOS)/$(go env GOARCH)
$ chmod +x kubebuilder
$ mv ~/Documents/tmp/kubebuilder ~/bin/kubebuilder

$ kubebuilder version
--- output ---
Version: main.version{KubeBuilderVersion:&quot;3.10.0&quot;, KubernetesVendor:&quot;1.26.1&quot;, GitCommit:&quot;0fa57405d4a892efceec3c5a902f634277e30732&quot;, BuildDate:&quot;2023-04-15T08:10:35Z&quot;, GoOs:&quot;darwin&quot;, GoArch:&quot;amd64&quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;kustomize 설치&lt;/h3&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;$ cd ~/Documents/tmp

$ curl -s &quot;https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh&quot;  | bash
$ mv ~/Documents/tmp/kustomize ~/bin/kustomize

$ kustomize version
--- output ---
v5.0.3&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;kind 설치 및 cluster 생성&lt;/h3&gt;
&lt;pre class=&quot;inform7&quot;&gt;&lt;code&gt;$ cd ~/Documents/tmp

$ [ $(uname -m) = x86_64 ]&amp;amp;&amp;amp; curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.19.0/kind-darwin-amd64
$ chmod +x kind
$ mv ~/Documents/tmp/kind ~/bin/kind

$ kind version
--- output ---
kind v0.19.0 go1.20.4 darwin/amd64

$ kind create cluster&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;kubectl 설치&lt;/h3&gt;
&lt;pre class=&quot;groovy&quot;&gt;&lt;code&gt;$ cd ~/Documents/tmp

$ curl -LO &quot;https://dl.k8s.io/release/v1.27.1/bin/darwin/amd64/kubectl&quot;
$ chmod +x kubectl
$ mv kubectl ~/bin/kubectl

$ kubectl version
Client Version: version.Info{Major:&quot;1&quot;, Minor:&quot;27&quot;, GitVersion:&quot;v1.27.1&quot;, GitCommit:&quot;4c9411232e10168d7b050c49a1b59f6df9d7ea4b&quot;, GitTreeState:&quot;clean&quot;, BuildDate:&quot;2023-04-14T13:21:19Z&quot;, GoVersion:&quot;go1.20.3&quot;, Compiler:&quot;gc&quot;, Platform:&quot;darwin/amd64&quot;}
Kustomize Version: v5.0.1
Server Version: version.Info{Major:&quot;1&quot;, Minor:&quot;27&quot;, GitVersion:&quot;v1.27.1&quot;, GitCommit:&quot;4c9411232e10168d7b050c49a1b59f6df9d7ea4b&quot;, GitTreeState:&quot;clean&quot;, BuildDate:&quot;2023-05-12T19:03:40Z&quot;, GoVersion:&quot;go1.20.3&quot;, Compiler:&quot;gc&quot;, Platform:&quot;linux/amd64&quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;br /&gt;프로젝트 생성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kubebuilder 명령어로 간단히 프로젝트와 API 를 생성할 수 있다. 즉, 필요한 코드들이 자동으로 생성된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 프로젝트를 생성한다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;$ mkdir -p guestbook-kubebuilder
$ cd guestbook-kubebuilder

$ kubebuilder init --domain my.domain --repo my.domain/guestbook
--- output ---
Writing kustomize manifests for you to edit...
Writing scaffold for you to edit...
Get controller runtime:
$ go get sigs.k8s.io/controller-runtime@v0.14.4
go: downloading sigs.k8s.io/controller-runtime v0.14.4
go: downloading k8s.io/apimachinery v0.26.1
go: downloading github.com/prometheus/client_golang v1.14.0
go: downloading k8s.io/client-go v0.26.1
go: downloading k8s.io/utils v0.0.0-20221128185143-99ec85e7a448
go: downloading github.com/prometheus/client_model v0.3.0
go: downloading k8s.io/api v0.26.1
go: downloading k8s.io/component-base v0.26.1
go: downloading golang.org/x/time v0.3.0
go: downloading k8s.io/apiextensions-apiserver v0.26.1
go: downloading github.com/matttproud/golang_protobuf_extensions v1.0.2
go: downloading golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10
go: downloading github.com/imdario/mergo v0.3.6
go: downloading k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280
go: downloading golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b
Update dependencies:
$ go mod tidy
go: downloading go.uber.org/goleak v1.2.0
Next: define a resource with:
$ kubebuilder create api&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;다음으로 api 를 생성한다.&lt;/p&gt;
&lt;pre class=&quot;groovy&quot;&gt;&lt;code&gt;$ kubebuilder create api --group webapp --version v1 --kind Guestbook
--- output ---
Create Resource [y/n]
y
Create Controller [y/n]
y
Writing kustomize manifests for you to edit...
Writing scaffold for you to edit...
api/v1/guestbook_types.go
api/v1/groupversion_info.go
internal/controller/suite_test.go
internal/controller/guestbook_controller.go
Update dependencies:
$ go mod tidy
Running make:
$ make generate
mkdir -p /Users/ahnsk/Documents/github.com/seungkyua/guestbook-kubebuilder/bin
test -s /Users/ahnsk/Documents/github.com/seungkyua/guestbook-kubebuilder/bin/controller-gen &amp;amp;&amp;amp; /Users/ahnsk/Documents/github.com/seungkyua/guestbook-kubebuilder/bin/controller-gen --version | grep -q v0.11.3 || \
    GOBIN=/Users/ahnsk/Documents/github.com/seungkyua/guestbook-kubebuilder/bin go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.11.3
go: downloading sigs.k8s.io/controller-tools v0.11.3
go: downloading golang.org/x/tools v0.4.0
go: downloading k8s.io/utils v0.0.0-20221107191617-1a15be271d1d
go: downloading github.com/mattn/go-colorable v0.1.9
/Users/ahnsk/Documents/github.com/seungkyua/guestbook-kubebuilder/bin/controller-gen object:headerFile=&quot;hack/boilerplate.go.txt&quot; paths=&quot;./...&quot;
Next: implement your new API and generate the manifests (e.g. CRDs,CRs) with:
$ make manifests&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CR 이나 CRD 를 수정하면 마지막의 &lt;code&gt;make manifests&lt;/code&gt; 를 수행하여 다신 generation 해야 한다고 친절히 알려주고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CR 과 CRD 는 아래 &lt;code&gt;guestbook_types.go&lt;/code&gt; 파일에 struct 로 생성되어 있다. 이곳을 원하는 대로 변경하면 된다.&lt;/p&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;br /&gt;테스트로 아래과 같이 변경하자.&lt;/p&gt;
&lt;pre class=&quot;rust&quot;&gt;&lt;code&gt;// GuestbookSpec defines the desired state of Guestbook
type GuestbookSpec struct {
    // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
    // Important: Run &quot;make&quot; to regenerate code after modifying this file

    // Quantity of instances
    // +kubebuilder:validation:Minimum=1
    // +kubebuilder:validation:Maximum=10
    Size int32 `json:&quot;size&quot;`

    // Name of the ConfigMap for GuestbookSpec's configuration
    // +kubebuilder:validation:MaxLength=15
    // +kubebuilder:validation:MinLength=1
    ConfigMapName string `json:&quot;configMapName&quot;`

    // +kubebuilder:validation:Enum=Phone;Address;Name
    Type string `json:&quot;alias,omitempty&quot;`
}

// GuestbookStatus defines the observed state of Guestbook
type GuestbookStatus struct {
    // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
    // Important: Run &quot;make&quot; to regenerate code after modifying this file

    // PodName of the active Guestbook node.
    Active string `json:&quot;active&quot;`

    // PodNames of the standby Guestbook nodes.
    Standby []string `json:&quot;standby&quot;`
}

//+kubebuilder:object:root=true
//+kubebuilder:subresource:status

// Guestbook is the Schema for the guestbooks API
type Guestbook struct {
    metav1.TypeMeta   `json:&quot;,inline&quot;`
    metav1.ObjectMeta `json:&quot;metadata,omitempty&quot;`

    Spec   GuestbookSpec   `json:&quot;spec,omitempty&quot;`
    Status GuestbookStatus `json:&quot;status,omitempty&quot;`
}

//+kubebuilder:object:root=true

// GuestbookList contains a list of Guestbook
type GuestbookList struct {
    metav1.TypeMeta `json:&quot;,inline&quot;`
    metav1.ListMeta `json:&quot;metadata,omitempty&quot;`
    Items           []Guestbook `json:&quot;items&quot;`
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Guestbook&lt;/code&gt; struct 에 있는 &lt;code&gt;metav1.TypeMeta&lt;/code&gt; 와 &lt;code&gt;metav1.ObjectMeta&lt;/code&gt; 를 설명하면, 전자는 우리가 흔히 보는 yaml 파일에서 &lt;code&gt;apiVersion&lt;/code&gt; 과 &lt;code&gt;Kind&lt;/code&gt; 이고 후자는 &lt;code&gt;metadata&lt;/code&gt; 의 &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;namespace&lt;/code&gt; 등을 나타낸다. 다음에 우리가 정의한 &lt;code&gt;Spec&lt;/code&gt; 과 &lt;code&gt;Status&lt;/code&gt; 가 있음을 알 수 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;br /&gt;&lt;br /&gt;테스트 방법 1 - Cluster 밖에서 테스트 하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CRD 를 cluster 에 설치한다.&lt;/p&gt;
&lt;pre class=&quot;groovy&quot;&gt;&lt;code&gt;$ make install
--- output ---
/Users/ahnsk/Documents/github.com/seungkyua/guestbook-kubebuilder/bin/controller-gen rbac:roleName=manager-role crd webhook paths=&quot;./...&quot; output:crd:artifacts:config=config/crd/bases
test -s /Users/ahnsk/Documents/github.com/seungkyua/guestbook-kubebuilder/bin/kustomize || { curl -Ss &quot;https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh&quot; --output install_kustomize.sh &amp;amp;&amp;amp; bash install_kustomize.sh 5.0.0 /Users/ahnsk/Documents/github.com/seungkyua/guestbook-kubebuilder/bin; rm install_kustomize.sh; }
v5.0.0
kustomize installed to /Users/ahnsk/Documents/github.com/seungkyua/guestbook-kubebuilder/bin/kustomize
/Users/ahnsk/Documents/github.com/seungkyua/guestbook-kubebuilder/bin/kustomize build config/crd | kubectl apply -f -
customresourcedefinition.apiextensions.k8s.io/guestbooks.webapp.my.domain created&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;controller 를 실행시킨다. (터미널에서 포그라운드로 실행한다)&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ make run
--- output ---
test -s /Users/ahnsk/Documents/github.com/seungkyua/guestbook-kubebuilder/bin/controller-gen &amp;amp;&amp;amp; /Users/ahnsk/Documents/github.com/seungkyua/guestbook-kubebuilder/bin/controller-gen --version | grep -q v0.11.3 || \
        GOBIN=/Users/ahnsk/Documents/github.com/seungkyua/guestbook-kubebuilder/bin go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.11.3
/Users/ahnsk/Documents/github.com/seungkyua/guestbook-kubebuilder/bin/controller-gen rbac:roleName=manager-role crd webhook paths=&quot;./...&quot; output:crd:artifacts:config=config/crd/bases
/Users/ahnsk/Documents/github.com/seungkyua/guestbook-kubebuilder/bin/controller-gen object:headerFile=&quot;hack/boilerplate.go.txt&quot; paths=&quot;./...&quot;
go fmt ./...
go vet ./...

go run ./cmd/main.go
2023-05-24T17:18:18+09:00       INFO    controller-runtime.metrics      Metrics server is starting to listen    {&quot;addr&quot;: &quot;:8080&quot;}
2023-05-24T17:18:18+09:00       INFO    setup   starting manager
2023-05-24T17:18:18+09:00       INFO    Starting server {&quot;kind&quot;: &quot;health probe&quot;, &quot;addr&quot;: &quot;[::]:8081&quot;}
2023-05-24T17:18:18+09:00       INFO    Starting server {&quot;path&quot;: &quot;/metrics&quot;, &quot;kind&quot;: &quot;metrics&quot;, &quot;addr&quot;: &quot;[::]:8080&quot;}
2023-05-24T17:18:18+09:00       INFO    Starting EventSource    {&quot;controller&quot;: &quot;guestbook&quot;, &quot;controllerGroup&quot;: &quot;webapp.my.domain&quot;, &quot;controllerKind&quot;: &quot;Guestbook&quot;, &quot;source&quot;: &quot;kind source: *v1.Guestbook&quot;}
2023-05-24T17:18:18+09:00       INFO    Starting Controller     {&quot;controller&quot;: &quot;guestbook&quot;, &quot;controllerGroup&quot;: &quot;webapp.my.domain&quot;, &quot;controllerKind&quot;: &quot;Guestbook&quot;}
2023-05-24T17:18:18+09:00       INFO    Starting workers        {&quot;controller&quot;: &quot;guestbook&quot;, &quot;controllerGroup&quot;: &quot;webapp.my.domain&quot;, &quot;controllerKind&quot;: &quot;Guestbook&quot;, &quot;worker count&quot;: 1}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 앞서 api 를 생성할 때 &lt;code&gt;Create Resource [y/n] y&lt;/code&gt; 로 했다면 CR 이 &lt;code&gt;config/samples&lt;/code&gt; 디렉토리 아래에 생성되어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;여기에 Spec 부분만 추가한다.&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;$ tree config/samples
config/samples
├── kustomization.yaml
└── webapp_v1_guestbook.yaml

$ vi config/samples/webapp_v1_guestbook.yaml
--- output ---
apiVersion: webapp.my.domain/v1
kind: Guestbook
metadata:
  labels:
    app.kubernetes.io/name: guestbook
    app.kubernetes.io/instance: guestbook-sample
    app.kubernetes.io/part-of: guestbook-kubebuilder
    app.kubernetes.io/managed-by: kustomize
    app.kubernetes.io/created-by: guestbook-kubebuilder
  name: guestbook-sample
spec:
  # TODO(user): Add fields here
  size: 1
  configMapName: &quot;myconfig&quot;
  alias: &quot;Address&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;터미널을 새로 열어서 이를 설치한다.&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;$ kubectl apply -k config/samples/
--- output ---
guestbook.webapp.my.domain/guestbook-sample created

$ kubectl get guestbook
--- output ---           
NAME               AGE
guestbook-sample   29s&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;br /&gt;테스트 방법 2 - Cluster 안에서 돌리기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;controller 를 cluster 안에서 돌리기 위해서는 먼저 이미지를 만들어야 한다.&lt;/p&gt;
&lt;pre class=&quot;gauss&quot;&gt;&lt;code&gt;$ docker login -u seungkyua
--- output ---         
Password: 
Login Succeeded

$ make docker-build docker-push IMG=docker.io/seungkyua/guestbook-kubebuilder:1.0&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;다음은 image 를 가지고 deploy 한다.&lt;/p&gt;
&lt;pre class=&quot;roboconf&quot;&gt;&lt;code&gt;$ make deploy IMG=docker.io/seungkyua/guestbook-kubebuilder:1.0
--- output ---
test -s /Users/ahnsk/Documents/github.com/seungkyua/guestbook-kubebuilder/bin/controller-gen &amp;amp;&amp;amp; /Users/ahnsk/Documents/github.com/seungkyua/guestbook-kubebuilder/bin/controller-gen --version | grep -q v0.11.3 || \
        GOBIN=/Users/ahnsk/Documents/github.com/seungkyua/guestbook-kubebuilder/bin go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.11.3
/Users/ahnsk/Documents/github.com/seungkyua/guestbook-kubebuilder/bin/controller-gen rbac:roleName=manager-role crd webhook paths=&quot;./...&quot; output:crd:artifacts:config=config/crd/bases
test -s /Users/ahnsk/Documents/github.com/seungkyua/guestbook-kubebuilder/bin/kustomize || { curl -Ss &quot;https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh&quot; --output install_kustomize.sh &amp;amp;&amp;amp; bash install_kustomize.sh 5.0.0 /Users/ahnsk/Documents/github.com/seungkyua/guestbook-kubebuilder/bin; rm install_kustomize.sh; }
cd config/manager &amp;amp;&amp;amp; /Users/ahnsk/Documents/github.com/seungkyua/guestbook-kubebuilder/bin/kustomize edit set image controller=docker.io/seungkyua/guestbook-kubebuilder:1.0
/Users/ahnsk/Documents/github.com/seungkyua/guestbook-kubebuilder/bin/kustomize build config/default | kubectl apply -f -
# Warning: 'patchesStrategicMerge' is deprecated. Please use 'patches' instead. Run 'kustomize edit fix' to update your Kustomization automatically.
namespace/guestbook-kubebuilder-system created
customresourcedefinition.apiextensions.k8s.io/guestbooks.webapp.my.domain configured
serviceaccount/guestbook-kubebuilder-controller-manager created
role.rbac.authorization.k8s.io/guestbook-kubebuilder-leader-election-role created
clusterrole.rbac.authorization.k8s.io/guestbook-kubebuilder-manager-role created
clusterrole.rbac.authorization.k8s.io/guestbook-kubebuilder-metrics-reader created
clusterrole.rbac.authorization.k8s.io/guestbook-kubebuilder-proxy-role created
rolebinding.rbac.authorization.k8s.io/guestbook-kubebuilder-leader-election-rolebinding created
clusterrolebinding.rbac.authorization.k8s.io/guestbook-kubebuilder-manager-rolebinding created
clusterrolebinding.rbac.authorization.k8s.io/guestbook-kubebuilder-proxy-rolebinding created
service/guestbook-kubebuilder-controller-manager-metrics-service created
deployment.apps/guestbook-kubebuilder-controller-manager created&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 가 설치된 것을 알 수 있다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;$ kubectl get pods -n guestbook-kubebuilder-system 
--- output ---
NAME                                                        READY   STATUS    RESTARTS   AGE
guestbook-kubebuilder-controller-manager-5f74f9d765-r68gn   2/2     Running   0          2m55s&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;br /&gt;삭제하기&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;crd 삭제&lt;/h3&gt;
&lt;pre class=&quot;elixir&quot;&gt;&lt;code&gt;$ make uninstall&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Cluster 에 설치된 controller 삭제&lt;/h3&gt;
&lt;pre class=&quot;elixir&quot;&gt;&lt;code&gt;$ make undeploy&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Kubernetes</category>
      <category>Architecture</category>
      <category>Custom Controller</category>
      <category>Kubebuilder</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/313</guid>
      <comments>https://ahnseungkyu.com/313#entry313comment</comments>
      <pubDate>Mon, 12 Jun 2023 16:38:49 +0900</pubDate>
    </item>
    <item>
      <title>Kubernetes 기반의 어플리케이션 배포 시스템 구축 방법</title>
      <link>https://ahnseungkyu.com/312</link>
      <description>&lt;p&gt;DevOps 는 개발자와 운영자의 역할을 함께 수행하는 것으로 개발과 운영의 책임을 공동으로 진다. 처음 이 단어를 접한 것이 2011년 OpenStack Summit 에 참석했을 때인데 클라우드, 그 중에서 IaaS(Infrastructure as a Service)가 널리 퍼지기 시작했을 때다. DevOps 는 클라우드 기반에서 빠르게 개발하고, 배포하고, 운영하기 위해서 스타트업 회사를 중심으로 빠르게 퍼지기 시작했다.&lt;/p&gt;
&lt;p&gt;아래는 클라우드 가상머신 기반의 DevOps 영역 중 CI/CD 에 대한 프로세스이다. 개발 언어는 Java 를 기준으로 표현하였으며, 이하 모든 설명은 Java 를 기준으로 설명한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/csFDSn/btsg9DuhhJV/HOpP7tx0cnr6LYQ3zmg5x1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/csFDSn/btsg9DuhhJV/HOpP7tx0cnr6LYQ3zmg5x1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/csFDSn/btsg9DuhhJV/HOpP7tx0cnr6LYQ3zmg5x1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcsFDSn%2Fbtsg9DuhhJV%2FHOpP7tx0cnr6LYQ3zmg5x1%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h1&gt;문제&lt;/h1&gt;
&lt;p&gt;2015년 7월 쿠버네티스 1.0 버전이 릴리즈 되면서 DevOps 는 가상머신이 아니라 컨테이너 기반으로 점차 변화하였다. 쿠버네티스 이전의 Ops는 가상머신을 빠르게 만들고 개발된 소스 코드를 자동으로 통합 빌드하여 배포하는 영역이었다. 하지만 쿠버네티스가 나오고, 컨테이너 관리가 효율적/안정적으로 변하면서 Ops 는 소스 코드 통합 빌드, 컨테이너 이미지 만들기와 쿠버네티스에 배포, 운영하는 영역으로 바뀌었다. 즉, Ops 영역을 맡은 운영자는 컨테이너도 알아야 하고, 쿠버네티스도 알아야 한다는 의미이다.&lt;/p&gt;
&lt;p&gt;결국 쿠버네티스 기반의 DevOps 는 소스 코드 개발, 통합 빌드, 컨테이너 이미지화, 배포의 영역 모두를 의미한다. 이를 간략하게 프로세스로 표시하면 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cZT6gL/btsg26EeT2I/bkksYB27SvxpRSF10eLTm0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cZT6gL/btsg26EeT2I/bkksYB27SvxpRSF10eLTm0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cZT6gL/btsg26EeT2I/bkksYB27SvxpRSF10eLTm0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcZT6gL%2Fbtsg26EeT2I%2FbkksYB27SvxpRSF10eLTm0%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;여기서 부터 문제가 발생한다. 기존의 Dev 역할은 인프라스트럭처가 가상 머신이든 쿠버네티스이든 상관이 없지만 Ops 역할은 컨테이너와 쿠버네티스라는 새로운 기술을 알아야 하는데 해당 기술을 습득하기까지는 어느 정도의 기술 허들을 넘어야 하고 일정 기간이 지나야 한다. (클라우드 기술이 널리 퍼지기까지 기간을 생각해 보면 쉽게 이해될 것이다)&lt;/p&gt;
&lt;p&gt;또한 배포 영역을 생각해 보면 결코 쉬운 문제가 아니다. 배포 전략에는 아래와 같은 3가지 방법이 존재한다. (크게는 4가지 이지만 가장 단순한 Recreate 배포는 생략하였다) &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;이미지 출처: 쿠버네티스 패턴 (책만출판사)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;사족이지만 카나리아 배포를 “까나리”라고 발음하지 말자. “까나리”는 액젓이다.&lt;/p&gt;
&lt;h1&gt;해결책&lt;/h1&gt;
&lt;p&gt;개발자는 개발의 영역 즉, Dev 영역에 집중하게 하자. 어려운 Ops 영역은 시스템으로 자동으로 동작하도록 제공하자.&lt;/p&gt;
&lt;p&gt;앞서 간단히 살펴본 개발/배포 프로세스를 다시 살펴보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zMT8z/btshbetCiVQ/XtAOYg7Qy7ZYrK3fnkt6Vk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zMT8z/btshbetCiVQ/XtAOYg7Qy7ZYrK3fnkt6Vk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zMT8z/btshbetCiVQ/XtAOYg7Qy7ZYrK3fnkt6Vk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzMT8z%2FbtshbetCiVQ%2FXtAOYg7Qy7ZYrK3fnkt6Vk%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;개발자가 IDE 툴을 통해 프로그램을 개발한다.&lt;/li&gt;
&lt;li&gt;Maven 혹은 Gradle 로 소스 코드를 빌드한다. 로컬 빌드, Jenkins 혹은 기타 다른 CI 툴을 활용한 빌드 결과물로 jar 혹은 war 파일이 생성된다. 일반적으로 스프링 부트 프로젝트는 jar 파일로 만들어지며, war 파일은 일반 스프링 프로젝트이다. 해당 결과 파일은 저장소(e.q. nexus)에 저장된다.&lt;/li&gt;
&lt;li&gt;jar 혹은 war 파일을 로컬 빌드 혹은 기타 다른 CI 툴을 활용하여 컨테이너 이미지로 빌드한다.&lt;/li&gt;
&lt;li&gt;빌드된 컨테이너 이미지를 이미지 저장소에 저장한다.&lt;/li&gt;
&lt;li&gt;쿠버네티스에 배포하기 위해 deployment.yaml, service.yaml 등을 포함한 helm chart 를 만들고 이를 서버에 배포한다. 배포할 때는 배포 전략에 따라서 Rolling update, Blue-Green, Canary 로 배포한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;1번과 2번은 개발자가 이제까지 하던 방식 그대로 개발하면 된다. 우리가 시스템으로 만들어 제공해야 할 부분은 3, 4, 5 번 영역이다.&lt;/p&gt;
&lt;h1&gt;구현 방법&lt;/h1&gt;
&lt;p&gt;해당 시스템에 대한 아키텍처를 구성하면 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cxEhQe/btsg9POECWW/RTjr4Xtv7bGoeLpE0qNis1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cxEhQe/btsg9POECWW/RTjr4Xtv7bGoeLpE0qNis1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cxEhQe/btsg9POECWW/RTjr4Xtv7bGoeLpE0qNis1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcxEhQe%2Fbtsg9POECWW%2FRTjr4Xtv7bGoeLpE0qNis1%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2&gt;사용 오픈소스 S/W&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Nexus&lt;ul&gt;
&lt;li&gt;Maven 저장소로 사용되며 테스트 용도의 jar 파일을 저장하고 다운로드 할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Keycloak&lt;ul&gt;
&lt;li&gt;인증 서버로 활용&lt;/li&gt;
&lt;li&gt;OIDC 접속 백엔드로 활용할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Argo Workflow&lt;ul&gt;
&lt;li&gt;CNCF Graduated Project&lt;/li&gt;
&lt;li&gt;워크플로우 서버로 파이프라인을 설계하고 실행할 수 있음.&lt;/li&gt;
&lt;li&gt;워크플로우 템플릿을 작성하면 재사용 가능함&lt;/li&gt;
&lt;li&gt;워크플로우 실행은 컨테이너 단위로 실행됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Harbor&lt;ul&gt;
&lt;li&gt;CNCF Graduated Project&lt;/li&gt;
&lt;li&gt;이미지 저장소로 활용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Gitea&lt;ul&gt;
&lt;li&gt;Helm chart 저장소로 활용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Helm&lt;ul&gt;
&lt;li&gt;Helm chart template 관리&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Argo Rollout&lt;ul&gt;
&lt;li&gt;배포 전략을 다양하게 지원함&lt;/li&gt;
&lt;li&gt;지원 배포 전략: Rolling update, Blue-Green, Canary&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;프로세스 설명&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;사용자는 cli (golang)로 앱 배포를 요청한다.&lt;/li&gt;
&lt;li&gt;API 서버 (golang) 는 해당 요청을 받아서 Argo workflow 를 호출한다.&lt;/li&gt;
&lt;li&gt;Argo Workflow 에서 Nexus 로 부터 jar 파일을 가져온다.&lt;/li&gt;
&lt;li&gt;Argo Workflow 에서 jar 파일을 컨테이너 이미지 파일로 빌드하고 이미지 저장소인 하버에 저장한다.&lt;/li&gt;
&lt;li&gt;Argo Workflow 에서 이미지를 가져온다.&lt;/li&gt;
&lt;li&gt;Argo Workflow 에서 Helm chart 템플릿을 가져온다.&lt;/li&gt;
&lt;li&gt;Argo Workflow 에서 Helm chart 와 이미지를 조합하여 Argo Rollout 으로 배포한다.&lt;/li&gt;
&lt;li&gt;Argo Rollout 은 초기 배포를 Blue 로 배포한다. 배포된 Blue 는 로드 발랜서와 연결된다.&lt;/li&gt;
&lt;li&gt;사용자가 Cli 로 앱 업그레이드를 Blue-Green 전략으로 요청한다.&lt;/li&gt;
&lt;li&gt;Argo Workflow 에서는 Rollout 으로 Green 으로 배포한다.&lt;/li&gt;
&lt;/ol&gt;</description>
      <category>Kubernetes</category>
      <category>Application 배포</category>
      <category>kubernetes</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/312</guid>
      <comments>https://ahnseungkyu.com/312#entry312comment</comments>
      <pubDate>Tue, 23 May 2023 18:12:18 +0900</pubDate>
    </item>
    <item>
      <title>Kubernetes Custom Controller 개발에 필요한 Go 언어 기초 문법</title>
      <link>https://ahnseungkyu.com/311</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Kubernetes custom controller 개발에 가장 잘 맞는 프로그래밍 언어는 Go 이다. Kubernetes 가 Go 로 개발된 S/W 이다 보니 Custom controller 도 Go 로 만드는 것이 좋을 것 같다는 생각이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 겸사겸사 Custom Controller 개발에 필요한 Go 문법만 정리해 보기로 했다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;변수 선언 : var, Short Variable Declaration Operator(:=)&lt;/li&gt;
&lt;li&gt;Package 선언 및 활용&lt;/li&gt;
&lt;li&gt;Struct (json 으로 변환)&lt;/li&gt;
&lt;li&gt;Receiver function&lt;/li&gt;
&lt;li&gt;Interface 선언, 활용&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;변수 선언&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변수는 var 키워드로 쉽게 선언할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;delphi&quot;&gt;&lt;code&gt;// var 변수명 변수타입
var message string
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변수를 선언하면서 값을 대입하면 마지막의 변수 타입은 생략 가능하다.&lt;/p&gt;
&lt;pre class=&quot;actionscript&quot;&gt;&lt;code&gt;var message = &quot;Hi, Welcome!&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;:= operator 를 사용하면 shortcut 으로 선언하여 var 도 생략할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;makefile&quot;&gt;&lt;code&gt;message := &quot;Hi, Welcome!&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Package 선언 및 활용&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모듈로 만들어서 import 하여 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같이 디렉토리를 만들어보자. greetings 는 모듈로 선언하고 basic 에서 greetings 모듈을 import 하여 사용할 예정이다.&lt;/p&gt;
&lt;pre class=&quot;shell&quot;&gt;&lt;code&gt;$ mkdir -p go-sample
$ cd go-sample

$ mkdir -p {basic,greetings}
$ cd greetings
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;go-sample 이라는 프로젝트 아래에 greetings 라는 모듈을 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모듈을 만들기 위해서 go.mod 파일을 만든다.&lt;/p&gt;
&lt;pre class=&quot;vim&quot;&gt;&lt;code&gt;$ go mod init github.com/seungkyua/go-sample/greetings
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;go.mod 파일이 생성되며 파일 내용은 아래와 같다.&lt;/p&gt;
&lt;pre class=&quot;vim&quot;&gt;&lt;code&gt;module github.com/seungkyua/go-sample/greetings

go 1.19
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;greetings.go 파일을 만들어서 아래와 같이 입력한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기도 error 핸들링과 string format 을 위해서 모듈을 import 하고 있는데 이를 이해할려고 하지 말고 그냥 Hello function 이 있다는 것만 이해하자.&lt;/p&gt;
&lt;pre class=&quot;go&quot;&gt;&lt;code&gt;package greetings

import (
	&quot;errors&quot;
	&quot;fmt&quot;
)

func Hello(name string) (string, error) {
	if name == &quot;&quot; {
		return &quot;&quot;, errors.New(&quot;empty name&quot;)
	}

	message := fmt.Sprintf(&quot;Hi, %v. Welcome!&quot;, name)
	return message, nil
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;go-sample 홈디렉토리에서 보는 greetings 디렉토리 구조는 아래와 같다.&lt;/p&gt;
&lt;pre class=&quot;maxima&quot;&gt;&lt;code&gt;greetings
├── go.mod
└── greetings.go
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;golang 1.19 버전 부터는 로컬 하위 디렉토리를 인식하기 위해서 [go.work](&amp;lt;&lt;a href=&quot;http://go.work&quot;&gt;http://go.work&lt;/a&gt;&amp;gt;) 를 사용한다. 그리니 아래와 같이 하여 파일을 만들어 보자.&lt;/p&gt;
&lt;pre class=&quot;elixir&quot;&gt;&lt;code&gt;$ go work use ./basic
$ go work use ./greetins
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;go-sample 홈디렉토리 아래에 [go.work](&amp;lt;&lt;a href=&quot;http://go.work&quot;&gt;http://go.work&lt;/a&gt;&amp;gt;) 파일이 아래와 같이 만들어 진다.&lt;/p&gt;
&lt;pre class=&quot;gauss&quot;&gt;&lt;code&gt;go 1.19

use (
	./greetings
	./basic
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 basic 디렉토리로 가서 똑같이 go.mod 파일을 만들고 main.go 파일도 만들어 본다.&lt;/p&gt;
&lt;pre class=&quot;vim&quot;&gt;&lt;code&gt;$ cd basic

$ go mod init github.com/seungkyua/go-sample/basic
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;go.mod 파일이 아래와 같이 생성되었음을 알 수 있다.&lt;/p&gt;
&lt;pre class=&quot;vim&quot;&gt;&lt;code&gt;module github.com/seungkyua/go-sample/basic

go 1.19
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;greetings 모듈을 로컬로 인식하게 변경한다.&lt;/p&gt;
&lt;pre class=&quot;vim&quot;&gt;&lt;code&gt;$ go mod edit -replace github.com/seungkyua/go-sample/greetings=../greetings
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 로컬 버전을 사용하기 위해서 pseudo 버전을 사용하게 tidy 명령을 활용한다.&lt;/p&gt;
&lt;pre class=&quot;gams&quot;&gt;&lt;code&gt;$ go mod tidy
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 최종 go.mod 는 다음과 같다.&lt;/p&gt;
&lt;pre class=&quot;vim&quot;&gt;&lt;code&gt;module github.com/seungkyua/go-sample/basic

go 1.19

// go mod edit 으로 로컬 경로를 보도록 수정
replace github.com/seungkyua/go-sample/greetings =&amp;gt; ../greetings

// 로컬이므로 pseudo 버전을 만든다 
require github.com/seungkyua/go-sample/greetings v0.0.0-00010101000000-000000000000
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;main.go 파일을 만들어서 greetings 모듈을 import 하여 활용해 본다.&lt;/p&gt;
&lt;pre class=&quot;go&quot;&gt;&lt;code&gt;package main

import (
	&quot;fmt&quot;
	&quot;log&quot;

	&quot;github.com/seungkyua/go-sample/greetings&quot;
)

func main() {
	message, err := greetings.Hello(&quot;Seungkyu&quot;)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(message)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;go-sample 디렉토리 구조는 아래와 같다.&lt;/p&gt;
&lt;pre class=&quot;maxima&quot;&gt;&lt;code&gt;basic
├── go.mod
└── main.go
greetings
├── go.mod
└── greetings.go
go.work
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Struct 활용 (json 변환)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;struct 를 json data 로 변환하는 것을 marshal (encoding) 이라고 하고 json data를 struct 로 변환하는 것을 unmarshal (decoding) 이라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;json 패키지의 Marshal function 은 다음과 같다.&lt;/p&gt;
&lt;pre class=&quot;go&quot;&gt;&lt;code&gt;func Marshal(v interface{}) ([]byte, error)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Struct 를 만들어서 json data (byte slice) 로 변환해 보자.&lt;/p&gt;
&lt;pre class=&quot;groovy&quot;&gt;&lt;code&gt;type album struct {
	ID     string  `json:&quot;id&quot;`
	Title  string  `json:&quot;title&quot;`
	Artist string  `json:&quot;artist&quot;`
	Price  float64 `json:&quot;price&quot;`
}

a := album{ID: &quot;1&quot;, Title: &quot;Blue Train&quot;, Artist: &quot;John Coltrane&quot;, Price: 56.99}
b, err := json.Marshal(a)
if err != nil {
	log.Fatal(err)
}

b2 := []byte(`{&quot;id&quot;:&quot;1&quot;,&quot;title&quot;:&quot;Blue Train&quot;,&quot;artist&quot;:&quot;John Coltrane&quot;,&quot;price&quot;:56.99}`)
fmt.Println(bytes.Equal(b, b2))
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Unmarshal function 은 다음과 같다.&lt;/p&gt;
&lt;pre class=&quot;go&quot;&gt;&lt;code&gt;func Unmarshal(data []byte, v interface{}) error
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;json data (byte slice) 를 struct 로 다시 변환한다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;var a2 album
err = json.Unmarshal(b, &amp;amp;a2)
if err != nil {
	log.Fatal(err)
}
fmt.Println(a2)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Receiver Function&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Receiver function 은 struct 의 멤버 변수를 활용할 수 있는 function 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Vertex struct 를 만들고 그에 속한 멤버 변수를 활용하는 function 을 만들면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;func 와 함수명 사이에 Struct 를 변수와 함께 넣으면 Receiver function 이 된다.&lt;/p&gt;
&lt;pre class=&quot;go&quot;&gt;&lt;code&gt;type Vertex struct {
	X, Y float64
}

func (v Vertex) Abs() float64 {
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

func (v *Vertex) Scale(f float64) {
	v.X = v.X * f
	v.Y = v.Y * f
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같이 main 함수를 실행하면 값은 50 이 나온다.&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;func main() {
	v := Vertex{3, 4}
	v.Scale(10)
	fmt.Println(v.Abs())
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 만약 위의 func (v *Vertex) Scale(f float64) **에서 Vertex 를 포인터가 아닌 value 로 만들면 어떤 결과가 나올까? 위의 함수에서 * 를 지우고 다시 실행해 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과는 5 가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, Struct 의 멤버 변수의 값을 바꾸고 싶으면 Pointer Receiver 를 사용해야 한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Interface 선언, 활용&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Interface 는 method 를 모아둔 것이라 할 수 있다. interface 역시 type 키워드로 선언하기 때문에 interface 타입이라고도 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같이 Abs() 메소드를 선언하고 나서 Abs 를 Receiver function 으로 구현했다면 Abs 를 구현한 타입은 Abser 타입이라고 할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;type Abser interface {
	Abs() float64
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 MyFloat 타입도 Abser 타입이라고 할 수 있다. 하지만 Abs 의 Receiver 는 value Receiver 이다.&lt;/p&gt;
&lt;pre class=&quot;go&quot;&gt;&lt;code&gt;type MyFloat float64

func (f MyFloat) Abs() float64 {
	if f &amp;lt; 0 {
		return float64(-f)
	}
	return float64(f)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Vertex 타입도 역시 Abser 타입이며 pointer Receiver 이다.&lt;/p&gt;
&lt;pre class=&quot;go&quot;&gt;&lt;code&gt;type Vertex struct {
	X, Y float64
}

func (v *Vertex) Abs() float64 {
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;main 함수에서 interface 를 활용해 본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;a = v 에서 에러가 발생한다.&lt;/p&gt;
&lt;pre id=&quot;code_1684833265481&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;func main() {
	var a Abser
	f := MyFloat(-math.Sqrt2)
	v := Vertex{3, 4}

	a = f  // MyFloat 은 Abser 인터페이스를 구현했으니 가능함
	a = &amp;amp;v // *Vertex 는 Abser 인터페이스를 구현했으니 가능함

	a = v  // v 는 Vertext 타입임 (*Vertex 타입이 아님), value receiver 는 구현안했으니 에러 

	fmt.Println(a.Abs())
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Interface 선언, 활용 (2)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;interface 는 interface 를 포함할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같이 Client interface 가 Reader interface 를 가지면 Reader interface 에 선언된 함수가 그 대로 Client 에도 속하게 된다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;package interfaces

import (
	&quot;fmt&quot;
)

type Reader interface {
	Get(obj string) error
	List(list []string) error
}

type Client interface {
	Reader
}

var ReconcileClient Client = &amp;amp;client{}

type client struct {
	name string
}

func (c *client) Get(obj string) error {
	fmt.Println(obj)
	return nil
}

func (c *client) List(list []string) error {
	fmt.Println(list)
	return nil
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런 다음 struct 에서 interface 를 또 다시 포함할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같이 GuestbookReconciler struct 에 Client interface 를 포함하면 GuestbookReconciler 는 마치 Client interface 가 가지는 함수를 자신의 메소드 처럼 사용할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;package main

import &quot;github.com/seungkyua/go-sample/interfaces&quot;

type GuestbookReconciler struct {
	interfaces.Client
}

func main() {
	g := GuestbookReconciler{interfaces.ReconcileClient}
	g.Get(&quot;Seungkyu&quot;)
	g.Client.Get(&quot;Seungkyu&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 메소드 활용은 g.Get 혹은 g.Client.Get 둘 다 가능하다.&lt;/p&gt;</description>
      <category>프로그래밍/Go</category>
      <category>golang</category>
      <category>Interface</category>
      <category>receiver function</category>
      <category>struct</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/311</guid>
      <comments>https://ahnseungkyu.com/311#entry311comment</comments>
      <pubDate>Tue, 23 May 2023 18:04:57 +0900</pubDate>
    </item>
    <item>
      <title>(tmux) 터미널을 효율적으로 사용하기 (2/2)</title>
      <link>https://ahnseungkyu.com/310</link>
      <description>&lt;p&gt;지난 설명에 이어서 이번에는 tmux 의 설정에 대해서 자세히 살펴보자.&lt;/p&gt;
&lt;p&gt;tmux 는 conf 파일로 단축키와 기능을 설정할 수 있다.&lt;/p&gt;
&lt;h1&gt;tmux.conf 설정 파일&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;tmux.conf&lt;/code&gt; 파일을 홈디렉토리 아래에 다음과 같이 생성한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ vi ~/.tmux.conf

bind r source-file ~/.tmux.conf \; display &amp;quot;Reloaded!&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위의 설정은 현재의 session 에서 설정 파일인 &lt;code&gt;tmux.conf&lt;/code&gt; 을 동적으로 바로 리로딩하는 기능을 가진다.&lt;/p&gt;
&lt;p&gt;새로운 session 을 만들고 설정 파일을 리로딩해보자.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ tmux new -s sample&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rDEob/btr1dd5gZ0i/y7X7ri4IZes4jOvHcSMRu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rDEob/btr1dd5gZ0i/y7X7ri4IZes4jOvHcSMRu1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rDEob/btr1dd5gZ0i/y7X7ri4IZes4jOvHcSMRu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrDEob%2Fbtr1dd5gZ0i%2Fy7X7ri4IZes4jOvHcSMRu1%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;이제 &lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;r&lt;/code&gt; 을 해보면 설정 파일이 리로딩된 것을 볼 수 있다. (&lt;code&gt;prefix&lt;/code&gt; 는 &lt;code&gt;ctrl + b&lt;/code&gt; 를 나타내며 &lt;code&gt;Reloaded!&lt;/code&gt; 문구가 나타난 후 바로 삭제돼서 화면 캡쳐가 어렵다. ㅠㅠ)&lt;/p&gt;
&lt;p&gt;설정 파일에 적용할 수 있는 내용을 더 알아보자.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;set -s escape-time 1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;prefix&lt;/code&gt; 와 &lt;code&gt;command&lt;/code&gt; 사이에 인식할 수 있는 간격이 1초라는 의미이다. 리로딩의 경우 &lt;code&gt;prefix&lt;/code&gt; 를 누르고 &lt;code&gt;r&lt;/code&gt; 을 1초 이내에 눌러야 한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;set -g base-index 1
setw -g pane-base-index 1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;윈도우와 패인의 번호가 &lt;code&gt;0&lt;/code&gt; 번이 아닌 &lt;code&gt;1&lt;/code&gt; 번 부터 시작한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bind -r H resize-pane -L 5
bind -r J resize-pane -D 5
bind -r K resize-pane -U 5
bind -r L resize-pane -R 5&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;패인의 사이즈를 조절할 수 있다. &lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;H&lt;/code&gt; 는 왼쪽으로 5 만큼 늘린다는 의미이며, 수평(좌우)으로 2개의 패인으로 나눠진 경우에서 우측 패인에서 사용할 수 있다. 패인이 수직(위아래)으로 나눠진 경우에는 &lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;H&lt;/code&gt; 가 아니라 &lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;J&lt;/code&gt; 혹은 &lt;code&gt;K&lt;/code&gt; 를 사용할 수 있다.&lt;/p&gt;
&lt;p&gt;아래 이미지를 보면 오른쪽 패인이 조금 더 넓은 것을 볼 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dfJeLW/btr1dcSRmAg/SAu0x44hdpcsrwNk24l99K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dfJeLW/btr1dcSRmAg/SAu0x44hdpcsrwNk24l99K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dfJeLW/btr1dcSRmAg/SAu0x44hdpcsrwNk24l99K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdfJeLW%2Fbtr1dcSRmAg%2FSAu0x44hdpcsrwNk24l99K%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;set -g mouse on&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;마우스 클릭으로 패인의 포커스를 이동할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;setw -g pane-border-style fg=green,bg=black
setw -g pane-active-border-style fg=white,bg=yellow&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;현재 선택된 패인을 컬러바로 보여준다. 바로 위의 그림에서 노란색바가 아래에 있는데 이는 우측 패인이 선택되었다는 의미이다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;set -g status-left-length 40
set -g status-left &amp;quot;#[fg=green][#S] &amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;맨 아래 status 라인 왼쪽 사이드에 세션의 이름을 녹색으로 보여준다. 여기서는 &lt;code&gt;[sample]&lt;/code&gt; 로 보여진다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bind _ split-window -v -c &amp;quot;#{pane_current_path}&amp;quot;
bind / split-window -h -c &amp;quot;#{pane_current_path}&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;패인을 나누면서 현재 패인의 디렉토리를 그대로 적용해 준다. &lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;%&lt;/code&gt; 는 수평(좌우)로 나누지만 세션을 만들 때의 디렉토리를 적용해준다. 하지만 &lt;code&gt;prefix&lt;/code&gt; +  &lt;code&gt;/&lt;/code&gt; 는 수평(좌우)로 나누면서도 좌측 패인의 디렉토리를 우측패인에 그대로 적용해 준다.&lt;/p&gt;
&lt;p&gt;아래 seungkyua 라는 디렉토리 위치가 그대로 적용된 것을 볼 수 있&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MlOej/btr1fNL0FEz/H5sPraoY0CpYf7C8GkLr7K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MlOej/btr1fNL0FEz/H5sPraoY0CpYf7C8GkLr7K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MlOej/btr1fNL0FEz/H5sPraoY0CpYf7C8GkLr7K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMlOej%2Fbtr1fNL0FEz%2FH5sPraoY0CpYf7C8GkLr7K%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h1&gt;Window / Pane 추가 기능&lt;/h1&gt;
&lt;h2&gt;window 옮기기&lt;/h2&gt;
&lt;p&gt;세션에 있는 윈도우를 또 다른 세션으로 옮길 수 있으며, 서로 다른 윈도우를 하나의 윈도우에 패인으로 나눠서 통합할 수 있으며, 윈도우에 있는 패인을 또 다른 윈도우로 옮길 수 있다.&lt;/p&gt;
&lt;p&gt;추가로 &lt;code&gt;panes&lt;/code&gt; 세션을 만들고 거기에 &lt;code&gt;first&lt;/code&gt; 윈도우를 만든다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ tmux new -s panes -n first -d&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;panes&lt;/code&gt; 세션에 &lt;code&gt;second&lt;/code&gt; 윈도우를 만든다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ tmux new-window -t panes -n second&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;panes&lt;/code&gt; 세션에 들어간다. 윈도우는 &lt;code&gt;second&lt;/code&gt; 윈도우에 접속된다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ tmux attach -t panes&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qcwi7/btr0KHABgPb/xK4wtvtiT43eUdcrla7q2k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qcwi7/btr0KHABgPb/xK4wtvtiT43eUdcrla7q2k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qcwi7/btr0KHABgPb/xK4wtvtiT43eUdcrla7q2k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fqcwi7%2Fbtr0KHABgPb%2FxK4wtvtiT43eUdcrla7q2k%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt; &lt;code&gt;first&lt;/code&gt; 윈도우를 &lt;code&gt;second&lt;/code&gt; 윈도우에 패인으로 붙힌다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;prefix + :               ---&amp;gt; 명령 모드로 변경됨

join-pane -s panes:1     ---&amp;gt; 명령 모드에서 명령어를 실행&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DRUpN/btr02zafaYY/VgkkcLjWvbUOHzMkWMmAbk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DRUpN/btr02zafaYY/VgkkcLjWvbUOHzMkWMmAbk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DRUpN/btr02zafaYY/VgkkcLjWvbUOHzMkWMmAbk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDRUpN%2Fbtr02zafaYY%2FVgkkcLjWvbUOHzMkWMmAbk%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;결과로는 &lt;code&gt;first&lt;/code&gt; 윈도우가 &lt;code&gt;second&lt;/code&gt; 윈도우로 합쳐지면서 &lt;code&gt;second&lt;/code&gt; 윈도우는 2개의 패인으로 남는다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HAGAH/btr1blvHcf0/hkYwYal48tkkkY9uoEYAWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HAGAH/btr1blvHcf0/hkYwYal48tkkkY9uoEYAWK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HAGAH/btr1blvHcf0/hkYwYal48tkkkY9uoEYAWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHAGAH%2Fbtr1blvHcf0%2FhkYwYal48tkkkY9uoEYAWK%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2&gt;패인 layout 바꾸기&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;space&lt;/code&gt; 는 수직(위아래) 패인 레이아웃을 수평(좌우) 패인 레이아웃으로 바꿀 수 있다. 이 때 토글로 작동한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1JHyy/btr0VKXyUZ6/l94ONDR33SkzbKaa3KCQa1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1JHyy/btr0VKXyUZ6/l94ONDR33SkzbKaa3KCQa1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1JHyy/btr0VKXyUZ6/l94ONDR33SkzbKaa3KCQa1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1JHyy%2Fbtr0VKXyUZ6%2Fl94ONDR33SkzbKaa3KCQa1%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2&gt;여러 패인에 동시에 명령어 실행하기&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;ctrl + s&lt;/code&gt; 로 여러 패인에 동시에 명령어를 실행할 수 있다. 이 명령어도 토글로 작동된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tdZhI/btr0OaWM7RA/d3lXSm6JMvKmWDk11wGPxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tdZhI/btr0OaWM7RA/d3lXSm6JMvKmWDk11wGPxk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tdZhI/btr0OaWM7RA/d3lXSm6JMvKmWDk11wGPxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtdZhI%2Fbtr0OaWM7RA%2Fd3lXSm6JMvKmWDk11wGPxk%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2&gt;현재 패인을 새로운 윈도우로 옮기기&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;!&lt;/code&gt; 는 현재 패인을 새로운 윈도우로 만들면서 옮길 수 있다. 위에 &lt;code&gt;2:second&lt;/code&gt; 윈도우가 있고 우측 패인이 있는데, 우측 패인에서 해당 키를 수행하면 &lt;code&gt;1:zsh&lt;/code&gt; 윈도우가 만들어지면서 해당 패인이 윈도우가 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ca874E/btr1lBRZdbM/OxPwwqC9yOpSxqFk309cQK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ca874E/btr1lBRZdbM/OxPwwqC9yOpSxqFk309cQK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ca874E/btr1lBRZdbM/OxPwwqC9yOpSxqFk309cQK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fca874E%2Fbtr1lBRZdbM%2FOxPwwqC9yOpSxqFk309cQK%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2&gt;패인 최대화하기&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;z&lt;/code&gt; 는 현재 패인을 최대화해서 보여준다. 보통 패인은 창을 나눠서 쓰기 때문에 화면이 좁을 수 있는데 일시적으로 현재 패인을 전체화면 윈도우로 만들어 준다고 생각하면 쉽다.&lt;/p&gt;
&lt;p&gt;토글 기능이라 전체화면 윈도우에서 &lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;z&lt;/code&gt; 를 수행하면 원래 패인 크기도 돌아온다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yieCl/btr07Amp9ty/kCVj8lQZjsm4xNQXNqFORK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yieCl/btr07Amp9ty/kCVj8lQZjsm4xNQXNqFORK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yieCl/btr07Amp9ty/kCVj8lQZjsm4xNQXNqFORK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyieCl%2Fbtr07Amp9ty%2FkCVj8lQZjsm4xNQXNqFORK%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;최대화가 되면 화면 아래에 status 에서 패인이름 끝에  &lt;code&gt;Z&lt;/code&gt; 표시가 붙어 있어 현재 상태를 알기 쉽게 되어 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lXwJn/btr1dcL011f/NtpcyukVa12TjWw08kQnR1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lXwJn/btr1dcL011f/NtpcyukVa12TjWw08kQnR1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lXwJn/btr1dcL011f/NtpcyukVa12TjWw08kQnR1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlXwJn%2Fbtr1dcL011f%2FNtpcyukVa12TjWw08kQnR1%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Linux</category>
      <category>tmux</category>
      <category>tmux.conf</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/310</guid>
      <comments>https://ahnseungkyu.com/310#entry310comment</comments>
      <pubDate>Tue, 28 Feb 2023 13:28:54 +0900</pubDate>
    </item>
    <item>
      <title>Kubernetes Cluster 에서 Blue/Green 배포하기 (Argo Rollout 버전)</title>
      <link>https://ahnseungkyu.com/309</link>
      <description>&lt;p&gt;이전 글에서는 Kubernetes Cluster 상에서 App 을 Scratch 방식으로 Blue/Green 배포를 하였다. 이번에는 Argo Rollout 을 사용한 Blue/Green 배포하는 방식을 살표보자.&lt;/p&gt;
&lt;p&gt;Nginx 혹은 AWS ALB 를 직접 연결하여 사용할 수 있지만, Blue/Green 배포는 Traffic Shifting 이 필요하지 않으므로 AWS LB → Ingress Controller 를 연결한 상태를 만들어 놓고 배포하는 방식을 설명한다.&lt;/p&gt;
&lt;h2&gt;1. Argo Rollout 설치&lt;/h2&gt;
&lt;p&gt;helm chart 를 이용하여 argo rollout 을 설치한다.&lt;/p&gt;
&lt;p&gt;argo rollout dashboard 를 포햄하여 설치하고 싶으면 &lt;code&gt;dashboard.enabled=true&lt;/code&gt; 를 추가하면 된다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ helm repo add argo https://argoproj.github.io/argo-helm
$ helm repo update

$ helm search repo argo/argo-rollouts -l
NAME                    CHART VERSION   APP VERSION     DESCRIPTION
argo/argo-rollouts      2.22.2          v1.4.0          A Helm chart for Argo Rollouts
argo/argo-rollouts      2.22.1          v1.4.0          A Helm chart for Argo Rollouts

$ helm upgrade -i argo-rollout argo/argo-rollouts --version 2.22.2 -n argo --set dashboard.enabled=true --create-namespace&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;argo rollout dashboard 는 인증 체계가 없다. 그러므로 포트 포워딩으로 dashboard 에 접속 하는 것을 추천한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ kubectl port-forward service/argo-rollouts-dashboard 31000:3100&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;2. Argo Rollout kubectl plugin 설치&lt;/h2&gt;
&lt;p&gt;kubectl 로 cli 호출이 가능하도록 plugin 을 설치한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ curl -LO https://github.com/argoproj/argo-rollouts/releases/download/v1.4.0/kubectl-argo-rollouts-linux-amd64
$ chmod +x kubectl-argo-rollouts-linux-amd64
$ sudo mv kubectl-argo-rollouts-linux-amd64 /usr/local/bin/kubectl-argo-rollouts

$ kubectl argo rollouts version
--- output ---
kubectl-argo-rollouts: v1.4.0+e40c9fe
  BuildDate: 2023-01-09T20:20:38Z
  GitCommit: e40c9fe8a2f7fee9d8ee1c56b4c6c7b983fce135
  GitTreeState: clean
  GoVersion: go1.19.4
  Compiler: gc
  Platform: linux/amd64&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;argo rollout bash complete 도 설치한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ kubectl argo rollouts completion bash | tee /home/ubuntu/.kube/kubectl-argo-rollouts &amp;gt; /dev/null

$ vi ~/.bash_profile
source &amp;#39;/home/ubuntu/.kube/completion.bash.inc&amp;#39;
source &amp;#39;/home/ubuntu/.kube/kubectl-argo-rollouts&amp;#39;

PATH=/home/ubuntu/bin:$PATH

if [ -f ~/.bashrc ]; then
    . ~/.bashrc
fi&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3. 최초 App 배포 (Blue Deployment)&lt;/h2&gt;
&lt;p&gt;초기 app (blue)을 배포한다. 이전 글에서 사용된 &lt;code&gt;seungkyua/nginx:blue&lt;/code&gt; 이미지를 배포한다. 단 &lt;code&gt;replicas 를 0&lt;/code&gt; 으로 배포한다. 이렇게 배포하면 실제 pod 는 실행되지 않지만 pod template 은 배포된 상태가 된다. pod template 은 나중에 rollout 에서 참조하여 사용한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ cat nginx-blue-deploy.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx-blue-green
  name: nginx-blue-green
spec:
  replicas: 0
  selector:
    matchLabels:
      app: nginx-blue-green
      version: blue-green
  template:
    metadata:
      labels:
        app: nginx-blue-green
        version: blue-green
    spec:
      containers:
      - image: seungkyua/nginx:blue
        name: nginx

$ kubectl apply -f nginx-blue-deploy.yaml

$ kubectl get deploy,pod
NAME                               READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx-blue-green   0/0     0            0           11s&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Service 를 배포한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ cat nginx-blue-green-svc.yaml
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: nginx-blue-green
  name: nginx-blue-green-svc
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx-blue-green
    version: blue-green
  type: ClusterIP

$ kubectl apply -f nginx-blue-green-svc.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;그리고 blue deployment app 에 웹접속이 가능하게 ingress 를 배포한다. ingress 를 배포하더라도 아직 웹 접속은 불가능하다. 앞에서 deployment 의 replicas 를 0 으로 생성했기 때문에 실행되고 있는 pod 가 없기 때문이다. (나중에 접속을 위해서 &lt;code&gt;/etc/hosts&lt;/code&gt; 에 &lt;code&gt;nginx-blue-green.taco-cat.xyz&lt;/code&gt; 를 등록해 놓자)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ cat nginx-blue-green-ingress.yaml

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-blue-green-ingress
spec:
  ingressClassName: nginx
  rules:
  - host: nginx-blue-green.taco-cat.xyz
    http:
      paths:
      - pathType: ImplementationSpecific
        backend:
          service:
            name: nginx-blue-green-svc
            port:
              number: 80

$ kubectl apply -f nginx-blue-green-ingress.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Rollout 커스텀 리소스 배포&lt;/h3&gt;
&lt;p&gt;이제 초기 환경으로 Rollout 을 배포한다. Rollout 을 배포하면 pod 가 생성된다. &lt;code&gt;workloadRef&lt;/code&gt; 영역은 Deployment 에서 &lt;code&gt;Pod Template&lt;/code&gt; 영역과 일치한다. 그래서 이미 배포된 Deployment 를 참조하게 정의했다.&lt;/p&gt;
&lt;p&gt;마지막 라인의 &lt;code&gt;autoPromotionEnabled&lt;/code&gt; 는 &lt;code&gt;false&lt;/code&gt; 로 하여 수동으로 Blue/Green 을 확인하면서 배포를 할 수 있게 한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ cat nginx-rollout.yaml

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: nginx-rollout
spec:
  replicas: 2
  revisionHistoryLimit: 5
  selector:
    matchLabels:
      app: nginx-blue-green
  workloadRef:
    apiVersion: apps/v1
    kind: Deployment
    name: nginx-blue-green
  strategy:
    blueGreen:
      activeService: nginx-blue-green-svc
      autoPromotionEnabled: false

$ kubectl apply -f nginx-rollout.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이제 배포가 완료되면 아래와 같이 리소스가 생성되었음을 확인할 수 있다. rollout pod 와 rollout 에서 사용하는 ReplicaSet 이 생성되어 있음을 알 수 있다. &lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ kubectl argo rollouts list rollout
NAME           STRATEGY   STATUS        STEP  SET-WEIGHT  READY  DESIRED  UP-TO-DATE  AVAILABLE
nginx-rollout  BlueGreen  Healthy       -     -           2/2    2        2           2

$ kubectl get pods,deploy,rs
NAME                                 READY   STATUS    RESTARTS   AGE
pod/nginx-rollout-85c4bfb654-jmts7   1/1     Running   0          2m29s
pod/nginx-rollout-85c4bfb654-s46sm   1/1     Running   0          2m29s

NAME                               READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx-blue-green   0/0     0            0           4m50s

NAME                                         DESIRED   CURRENT   READY   AGE
replicaset.apps/nginx-blue-green-8b4f9cddb   0         0         0       4m50s
replicaset.apps/nginx-rollout-85c4bfb654     2         2         2       2m29s&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;웹으로 접속하면 아래와 같은 화면을 볼 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brkl54/btrYKu9wehc/anBmTcVseo1SIetE7yv8U0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brkl54/btrYKu9wehc/anBmTcVseo1SIetE7yv8U0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brkl54/btrYKu9wehc/anBmTcVseo1SIetE7yv8U0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbrkl54%2FbtrYKu9wehc%2FanBmTcVseo1SIetE7yv8U0%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;혹은 curl 로도 확인할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ curl nginx-blue-green.taco-cat.xyz

--- output ---
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;body style=&amp;quot;background-color:blue;&amp;quot;&amp;gt;
&amp;lt;h1&amp;gt;This is a blue webserver&amp;lt;/h1&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Rollout dashboard 에는 아래와 같이 나온다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWZejt/btrYLtCxETL/F0cOnJW8aokUXP7ZXhiaNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWZejt/btrYLtCxETL/F0cOnJW8aokUXP7ZXhiaNK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWZejt/btrYLtCxETL/F0cOnJW8aokUXP7ZXhiaNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWZejt%2FbtrYLtCxETL%2FF0cOnJW8aokUXP7ZXhiaNK%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2&gt;4. App 업그레이드 배포 (Green Deployment)&lt;/h2&gt;
&lt;p&gt;app 을 수정하여 배포해 보자. app 은 Deployment 를 수정해서 배포하면 된다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ cat nginx-green-deploy.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx-blue-green
  name: nginx-blue-green
spec:
  replicas: 0
  selector:
    matchLabels:
      app: nginx-blue-green
      version: blue-green
  template:
    metadata:
      labels:
        app: nginx-blue-green
        version: blue-green
    spec:
      containers:
      - image: seungkyua/nginx:green
        name: nginx

$ kubectl apply -f nginx-green-deploy.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Deployment 가 업그레이드 되어 배포했기 때문에 Rollout 이 이를 인식하고 Green 에 해당하는 추가 Pod 와 ReplicaSet 을 생성한다. 그리고 Rollout 리소스의 상태는 &lt;code&gt;Paused&lt;/code&gt; 가 된. (앞에서 Rollout 리소스 배포 시에 &lt;code&gt;autoPromotionEnabled&lt;/code&gt; 는 &lt;code&gt;false&lt;/code&gt; 로 하였기 때문이다)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ kubectl argo rollouts list rollout
NAME           STRATEGY   STATUS        STEP  SET-WEIGHT  READY  DESIRED  UP-TO-DATE  AVAILABLE
nginx-rollout  BlueGreen  Paused        -     -           2/4    2        2           2&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pod 와 ReplicaSet 을 조회해 보면 아래와 같다. Blue 해당하는 ReplicaSet 1 개, Pod 2개, Green 에 해당하는 ReplicaSet 1개 Pod 2 개가 떠 있는 것을 알 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HnpO7/btrYPA2clNT/74oS3PSXYbDRzQynKMyZs1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HnpO7/btrYPA2clNT/74oS3PSXYbDRzQynKMyZs1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HnpO7/btrYPA2clNT/74oS3PSXYbDRzQynKMyZs1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHnpO7%2FbtrYPA2clNT%2F74oS3PSXYbDRzQynKMyZs1%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Rollout Dashboar 는 아래와 같은 Pause 상태이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c5v0pd/btrYI5PUKOs/MjvMZIOICVd55R5HMWbUD1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c5v0pd/btrYI5PUKOs/MjvMZIOICVd55R5HMWbUD1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c5v0pd/btrYI5PUKOs/MjvMZIOICVd55R5HMWbUD1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc5v0pd%2FbtrYI5PUKOs%2FMjvMZIOICVd55R5HMWbUD1%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2&gt;5. Rollout 진행 완료 (promote)&lt;/h2&gt;
&lt;p&gt;완전히 Green 으로 변경하려면 Rollout 을 &lt;code&gt;promote&lt;/code&gt; 하여 최종 적용을 하던지 &lt;code&gt;abort&lt;/code&gt; 하여 중단, 혹은 &lt;code&gt;undo&lt;/code&gt; 하여 Pause 보다 이전 단계이 최초 Blue app 배포 단계로 돌아가는 방법이 있다.&lt;/p&gt;
&lt;p&gt;Green 으로 진행하는 promote 를 해보자.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ kubectl argo rollouts promote nginx-rollout

--- output ---
rollout &amp;#39;nginx-rollout&amp;#39; promoted&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ReplicaSet 은 남아 있지만 Pod 는 Green 으로 배포된 것만 남아있는 것을 확인할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ kubectl get pods,rs -l rollouts-pod-template-hash --show-labels
NAME                                 READY   STATUS    RESTARTS   AGE   LABELS
pod/nginx-rollout-569b8595bf-8s94v   1/1     Running   0          10m   app=nginx-blue-green,rollouts-pod-template-hash=569b8595bf,version=blue-green
pod/nginx-rollout-569b8595bf-c7fgg   1/1     Running   0          10m   app=nginx-blue-green,rollouts-pod-template-hash=569b8595bf,version=blue-green

NAME                                       DESIRED   CURRENT   READY   AGE   LABELS
replicaset.apps/nginx-rollout-569b8595bf   2         2         2       10m   app=nginx-blue-green,rollouts-pod-template-hash=569b8595bf,version=blue-green
replicaset.apps/nginx-rollout-85c4bfb654   0         0         0       19m   app=nginx-blue-green,rollouts-pod-template-hash=85c4bfb654,version=blue-green&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Rollout Dashboard 에서도 완료된 것을 알 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Wd3th/btrYLzpfpKo/l9xZlPVkc1sJRfOO0uRdU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Wd3th/btrYLzpfpKo/l9xZlPVkc1sJRfOO0uRdU1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Wd3th/btrYLzpfpKo/l9xZlPVkc1sJRfOO0uRdU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWd3th%2FbtrYLzpfpKo%2Fl9xZlPVkc1sJRfOO0uRdU1%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;마지막으로 웹 화면으로 확인한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lTF8g/btrYI4XPa5u/PipKaBuZcPEociHFRt7w7k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lTF8g/btrYI4XPa5u/PipKaBuZcPEociHFRt7w7k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lTF8g/btrYI4XPa5u/PipKaBuZcPEociHFRt7w7k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlTF8g%2FbtrYI4XPa5u%2FPipKaBuZcPEociHFRt7w7k%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2&gt;마치며…&lt;/h2&gt;
&lt;p&gt;Argo Rollout 은 Deployment 변경에서만 인식을 한다. ConfigMap 이나 Secret 과 같은 다른 리소스는 지원하지 않으니 Rollout 에서 이를 지원하는 방법은 추가로 고민해야 한다.&lt;/p&gt;</description>
      <category>Kubernetes</category>
      <category>argo rollout</category>
      <category>BlueGreen 배포</category>
      <category>DevOps</category>
      <category>kubernetes</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/309</guid>
      <comments>https://ahnseungkyu.com/309#entry309comment</comments>
      <pubDate>Fri, 10 Feb 2023 09:04:10 +0900</pubDate>
    </item>
    <item>
      <title>Kustomize 활용법 (feat. GitOps 로 가는 길)</title>
      <link>https://ahnseungkyu.com/308</link>
      <description>&lt;p&gt;TACO 에서는 Kubernetes 에 워크로드를 배포하기 위해서 Decapod 라는 자체 빌드 및 배포 체계를 갖고 있다. Decapod 는 Helm Chart 의 value override 기능과 Kustomize 의 plugin 기능을 개발하여 적용한 또 다른 value override 를 모두 사용하고 있다.&lt;/p&gt;
&lt;p&gt;Helm Chart 와 Kustomize 모두 value oeverride 기능을 모두 제공하는데 왜 2가지를 모두 사용할까? 그 이유는 Helm Chart 는 이미 다양하게 제공되고 있는 것들이 많아 가져다 쓰면 되고, value 값들을 하나의 yaml 파일로 합쳐서 관리하기 위해서 Kustomize 의 plugin 을 개발하여 사용하고 있다.&lt;/p&gt;
&lt;p&gt;즉, Decapod 체계는 다음과 같은 장점이 있다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Helm Chart 기반으로 default custom value 값을 지정할 수 있다. (decapod-base-yaml)&lt;/li&gt;
&lt;li&gt;Kustomize plugin 을 개발하여 각 사이트마다 갖는 여러 helm chart 의 고유 value 값들을 &lt;code&gt;1개의 yaml 파일&lt;/code&gt;에 합쳐서 관리할 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;하지만 Helm Chart 를 제공하지 않는 app 들은 어떻게 지원할까? 예를 들어 Kubeflow 의 경우 Helm Chart 를 제공하지 않지만 Kustomize 를 제공하고 있으니 이를 지원하는 방법도 필요해 보인다.&lt;/p&gt;
&lt;h2&gt;Kustomize 활용을 위한 기본 디렉토리 (base repo)&lt;/h2&gt;
&lt;p&gt;kustomize 는 설치되어 있다고 가정하고 바로 활용을 위한 기본 디렉토리를 살펴보자.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ tree
.
├── LICENSE
├── README.md
└── service-mesh
    └── nginx
        ├── aws-msa-reference
        │   ├── kustomization.yaml
        │   └── site-values.yaml
        └── base
            ├── kustomization.yaml
            ├── nginx-deployment.yaml
            ├── nginx-service.yaml
            └── site-values.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;소스 홈 디렉토리 아래에는 &lt;code&gt;service-mesh&lt;/code&gt; 라는 서비스 디렉토리가 있다. 여기에는 nginx, istio, jaeger, kaili 등 다양한 application 이 동시에 설치되어야 하는데 각 app 을 나타내는 디렉토리 (여기서는 편의상 nginx 만 설명한다)가 존재한다.&lt;/p&gt;
&lt;p&gt;nginx 설치를 위해서는 보통 nginx-deployment.yaml 과 nginx-service.yaml 이 필요하며 이를 base 디렉토리에 위치시킨다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ cat nginx-deployment.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx-blue
  name: nginx-blue
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-blue
      version: blue
  template:
    metadata:
      labels:
        app: nginx-blue
        version: blue
    spec:
      containers:
      - image: seungkyua/nginx:blue
        name: nginx &lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ cat nginx-service.yaml
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-blue-svc
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx-blue
    version: blue
  type: LoadBalancer&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;여기까지는 Helm chart 와 동일하다. 다만 chart 는 template 을 활용하여 value 값을 override 할 수 있는데 반하여 kustomize 는 kustomize.yaml 을 통해서 value 값을 override 할 수 있다.&lt;/p&gt;
&lt;p&gt;kustomize.yaml 을 지정하고 기본적으로 업데이트할 디폴트 값을 site-values.yaml 이라는 파일에 지정한다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;resources&lt;/code&gt; 는 kubernetes 에 설치할 리소스들에 대한 yaml 리스트이고 &lt;code&gt;patchesStrategicMerge&lt;/code&gt; 는 kustomize 에서 제공하는 yaml 합성 기능 중에 하나의 방법이다.&lt;/p&gt;
&lt;p&gt;아래의 경우에는 site-values.yaml 값과 nginx-deployment.yaml, nginx-service.yaml 값을 합쳐서 만든다.&lt;/p&gt;
&lt;p&gt;중복되는 경우에는 site-values.yaml 값을 우선시 한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ cat kustomization.yaml
---
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- nginx-deployment.yaml
- nginx-service.yaml

patchesStrategicMerge:
- site-values.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;site-values.yaml 에는 override 할 default value 값을 가진다.&lt;/p&gt;
&lt;p&gt;deployment 는 replicas 값을, service 는 NodePort 타입과 nodePort 값을 가진다. (이것을 base 값이라 생각하면 이해하기 쉽다. nginx helm chart 는 기본값이 replicas 1 인데 우리는 기본 값을 replicas 2 로 의도한 것이다.)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ cat site-values.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-blue
spec:
  replicas: 2

---
apiVersion: v1
kind: Service
metadata:
  name: nginx-blue-svc
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
    nodePort: 32080
  type: NodePort&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;여기서 잠깐. nginx-deployment.yaml 과 nginx-service.yaml 값을 처음부터 바꿔서 넣으면 site-values.yaml 이 필요하지 않을 텐데 왜 굳이 이걸 만들지?&lt;/p&gt;
&lt;p&gt;그건 kustomize 혹은 helm chart 를 제공하기 때문에 가져다 쓰는 경우도 많은데 원래의 작성 값들을 바꿔서 관리하지 않으려고 하는 의도이다. 업스트림에서 만들어 진 것이 있으면 원본은 그대로 가져다 쓰는 것이 추후 유지 보수 관점에서 편리하기 때문이다.&lt;/p&gt;
&lt;p&gt;이제 여기까지 만든 내용을 kustomize 로 build 해 보자.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ cd service-mesh/nginx

$ kustomize build base

--- output ---
apiVersion: v1
kind: Service
metadata:
  name: nginx-blue-svc
spec:
  ports:
  - nodePort: 32080
    port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx-blue
    version: blue
  type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx-blue
  name: nginx-blue
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-blue
      version: blue
  template:
    metadata:
      labels:
        app: nginx-blue
        version: blue
    spec:
      containers:
      - image: seungkyua/nginx:blue
        name: nginx&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Site 별 디렉토리 (Site repo)&lt;/h2&gt;
&lt;p&gt;이제 특정한 사이트에 다른 값으로 설치해야 한다고 가정해 보자. &lt;/p&gt;
&lt;p&gt;aws-msa-reference 라는 신규 사이트 디렉토리를 만들고 kustomize.yaml 과 value 값을 모아둔 site-values.yaml 을 만든다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ tree
.
├── LICENSE
├── README.md
└── service-mesh
    └── nginx
        ├── aws-msa-reference
        │   ├── kustomization.yaml
        │   └── site-values.yaml
        └── base
            ├── kustomization.yaml
            ├── nginx-deployment.yaml
            ├── nginx-service.yaml
            └── site-values.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;지금은 service-mesh/nginx 디렉토리 아리에 aws-msa-reference 가 있지만 이 디렉토리는 다른 repo 에서 관리하다가 kustomize build 를 하려할 때 해당 디렉토리로 복사해 오는 방법을 쓸 수 있다. (decapod 에서는 실제로 decapod-site 라는 repo 에 따로 사이트 값들을 관리하고 build 할 때 복사하는 방식을 사용하고 있다)&lt;/p&gt;
&lt;p&gt;kustomize.yaml 과 site-values.yaml 을 보자.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ cat kustomization.yaml
---
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
bases:
- ../base

patchesStrategicMerge:
- site-values.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ cat site-values.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-blue
spec:
  replicas: 3

---
apiVersion: v1
kind: Service
metadata:
  name: nginx-blue-svc
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  type: LoadBalancer&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;새로운 신규 사이트에는 replicas 를 3으로 Service Type 을 LoadBalancer 로 설치하고자 한다.&lt;/p&gt;
&lt;p&gt;이를 build 하면 다음과 같다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ kustomize build aws-msa-reference

--- output ---
apiVersion: v1
kind: Service
metadata:
  name: nginx-blue-svc
spec:
  ports:
  - nodePort: 32080
    port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx-blue
    version: blue
  type: LoadBalancer
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx-blue
  name: nginx-blue
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx-blue
      version: blue
  template:
    metadata:
      labels:
        app: nginx-blue
        version: blue
    spec:
      containers:
      - image: seungkyua/nginx:blue
        name: nginx&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;결과가 site 별로 지정한 값으로 잘 변경되었다.&lt;/p&gt;
&lt;h2&gt;어디에 적용할까?&lt;/h2&gt;
&lt;p&gt;kustomize 로 빌드된 결과 yaml 들을 특정 repo 에 저장하고 &lt;code&gt;Argo CD&lt;/code&gt; 와 같은 tool 을 적용하면 효과적인 &lt;code&gt;GitOps&lt;/code&gt; 체계를 만들 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Tekton pipeline&lt;/code&gt; 이나 &lt;code&gt;Argo workflow&lt;/code&gt;, &lt;code&gt;Jenkins pipeline&lt;/code&gt; 으로 CI 를 구축하고 &lt;code&gt;Argo CD&lt;/code&gt; 로 CD 를 연결하면 &lt;code&gt;GitOps CICD&lt;/code&gt; 를 구축할 수 있다. (이것까지 글로 써볼까? ㅎ)&lt;/p&gt;</description>
      <category>Kubernetes</category>
      <category>decapod</category>
      <category>DevOps</category>
      <category>gitops</category>
      <category>kustomize</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/308</guid>
      <comments>https://ahnseungkyu.com/308#entry308comment</comments>
      <pubDate>Mon, 6 Feb 2023 15:26:00 +0900</pubDate>
    </item>
    <item>
      <title>Kubernetes Cluster 에서 Blue/Green 배포하기 (scratch 버전)</title>
      <link>https://ahnseungkyu.com/307</link>
      <description>&lt;p&gt;Kubernetes 에서 Blue/Green 배포하는 방법을 알아보자.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Blue 와 Green 버전의 Container 이미지 만들기&lt;/li&gt;
&lt;li&gt;Blue 버전의 Deployment 와 LoadBalancer 타입의 Service 배포&lt;/li&gt;
&lt;li&gt;Green 버전의 Deployment 와 NodePort 타입의 Service 배포&lt;/li&gt;
&lt;li&gt;Patch 로 Service EndPoint 변경&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;1. Blue 와 Green 버전의 Container 이미지 만들기&lt;/h2&gt;
&lt;p&gt;Container 이미지는 nginx 를 상속받아 쉽게 만들 수 있다. nginx 가 바라보는 web root 는 &lt;code&gt;/usr/share/nginx/html&lt;/code&gt; 이므로 여기에 blue 버전을 표시할 수 있는 html 을 넣어준다.&lt;/p&gt;
&lt;h3&gt;index-blue.html&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;body style=&amp;quot;background-color:blue;&amp;quot;&amp;gt;
&amp;lt;h1&amp;gt;This is a blue webserver&amp;lt;/h1&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;index-blue.html&lt;/code&gt; 을 &lt;code&gt;index.html&lt;/code&gt; 로 변경하여 복사한다.&lt;/p&gt;
&lt;h3&gt;Dockerfile-blue&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;FROM nginx
COPY index-blue.html /usr/share/nginx/html/index.html&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;seungkyua/nginx:blue&lt;/code&gt; 이름과 태그를 갖는 Container 이미지를 만든다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ docker build -t seungkyua/nginx:blue -f Dockerfile-blue . &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이미지가 정확한지 test 해본다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ docker run --rm -d -p 8080:80 --name nginx-blue seungkyua/nginx:blue

$ curl localhost:8080
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;body style=&amp;quot;background-color:blue;&amp;quot;&amp;gt;
&amp;lt;h1&amp;gt;This is a blue webserver&amp;lt;/h1&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이미지가 잘 확인되었으니 docker hub 에 push 한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ docker login -u seungkyua
password: 

$ docker push seungkyua/nginx:blue&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;같은 방식으로 Green 이미지를 만들어서 docker hub 에 push 한다.&lt;/p&gt;
&lt;h3&gt;index-green.html&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;body style=&amp;quot;background-color:green;&amp;quot;&amp;gt;
&amp;lt;h1&amp;gt;This is a green webserver&amp;lt;/h1&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Dockerfile-green&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ cat Dockerfile-green
FROM nginx
COPY index-green.html /usr/share/nginx/html/index.html&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ docker build -t seungkyua/nginx:green -f Dockerfile-green .
$ docker push seungkyua/nginx:green&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;2. Blue 버전의 Deployment 와 LoadBalancer 타입의 Service 배포&lt;/h2&gt;
&lt;p&gt;이미지가 준비되었으니 Blue 버전의 deployment 와 service yaml 을 만들어 배포한다.&lt;/p&gt;
&lt;h3&gt;nginx-blue-deploy.yaml&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx-blue
  name: nginx-blue
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-blue
      version: blue
  template:
    metadata:
      labels:
        app: nginx-blue
        version: blue
    spec:
      containers:
      - image: seungkyua/nginx:blue
        name: nginx&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ kubectl apply -f nginx-blue-deploy.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Service 를 배포할 때는 Blue pod 의 label 을 selector 로 지정해 줘야 한다.&lt;/p&gt;
&lt;h3&gt;nginx-blue-green-svc.yaml&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;apiVersion: v1
kind: Service
metadata:
  labels:
    app: nginx-blue-green
  name: nginx-blue-green-svc
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx-blue
    version: blue
  type: LoadBalancer&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ kubectl apply -f nginx-blue-green-svc.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;blue version 은 웹 브라우저에서 접속하기 위해서 Service 를 LoadBalancer 타입으로 생성하였다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ kubectl get svc
NAME                   TYPE           CLUSTER-IP      EXTERNAL-IP                                                                  PORT(S)        AGE
kubernetes             ClusterIP      10.233.0.1      &amp;lt;none&amp;gt;                                                                       443/TCP        12d
nginx-blue-green-svc   LoadBalancer   10.233.30.78    aa1d4e1994e454eb5aea607cfdfd3dcf-23761053.ap-northeast-2.elb.amazonaws.com   80:32234/TCP   5m18s&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;웹브라우저에 접속하면 아래와 같이 blue 버전으로 접속이 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/v1OLm/btrXLrfmAro/DRJjktLXAIdi6JQdBI6bmk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/v1OLm/btrXLrfmAro/DRJjktLXAIdi6JQdBI6bmk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/v1OLm/btrXLrfmAro/DRJjktLXAIdi6JQdBI6bmk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fv1OLm%2FbtrXLrfmAro%2FDRJjktLXAIdi6JQdBI6bmk%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2&gt;3. Green 버전의 Deployment 와 NodePort 타입의 Service 배포&lt;/h2&gt;
&lt;p&gt;이제 새로운 버전인 Green 버전을 배포해 보자. image 와 label 을 잘 확인해야 한다.&lt;/p&gt;
&lt;h3&gt;nginx-green-deploy.yaml&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx-green
  name: nginx-green
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-green
      version: green
  template:
    metadata:
      labels:
        app: nginx-green
        version: green
    spec:
      containers:
      - image: seungkyua/nginx:green
        name: nginx&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ kubectl apply -f nginx-green-deploy.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Service 는 Green 배포가 잘 되었는지 확인하기 위해서 Service 를 NodeType 으로 적용하였다.&lt;/p&gt;
&lt;h3&gt;nginx-green-svc.yaml&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;apiVersion: v1
kind: Service
metadata:
  labels:
    app: nginx-green
  name: nginx-green-svc
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
    nodePort: 32080
  selector:
    app: nginx-green
    version: green
  type: NodePort&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ kubectl apply -f nginx-green-svc.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;green pod 가 떠 있는 노드를 확인한다.&lt;/p&gt;
&lt;p&gt;여기서는 &lt;code&gt;172.31.49.87&lt;/code&gt; 노드와 &lt;code&gt;172.31.46.179&lt;/code&gt; 노드에 pod 가 생성되어 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ kubectl get pods -o wide
NAME                           READY   STATUS    RESTARTS   AGE    IP               NODE                                               NOMINATED NODE   READINESS GATES
nginx-blue-69dd468cf4-nts5h    1/1     Running   0          6m7s   10.233.114.152   ip-172-31-49-87.ap-northeast-2.compute.internal    &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
nginx-blue-69dd468cf4-xvxqz    1/1     Running   0          6m7s   10.233.110.80    ip-172-31-46-179.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
nginx-green-7df845c6cf-mpj6b   1/1     Running   0          8s     10.233.114.153   ip-172-31-49-87.ap-northeast-2.compute.internal    &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
nginx-green-7df845c6cf-pvmrc   1/1     Running   0          8s     10.233.110.81    ip-172-31-46-179.ap-northeast-2.compute.internal   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;curl 명령어로 Green 이 정상적으로 배포되었는지 확인한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ kubectl get svc
NAME                   TYPE           CLUSTER-IP      EXTERNAL-IP                                                                  PORT(S)        AGE
kubernetes             ClusterIP      10.233.0.1      &amp;lt;none&amp;gt;                                                                       443/TCP        12d
nginx-blue-green-svc   LoadBalancer   10.233.30.78    aa1d4e1994e454eb5aea607cfdfd3dcf-23761053.ap-northeast-2.elb.amazonaws.com   80:32234/TCP   5m18s
nginx-green-svc        NodePort       10.233.33.157   &amp;lt;none&amp;gt;                                                                       80:32080/TCP   12s&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ curl 172.31.49.87:32080
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;body style=&amp;quot;background-color:green;&amp;quot;&amp;gt;
&amp;lt;h1&amp;gt;This is a green webserver&amp;lt;/h1&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;4. Patch 로 Service EndPoint 변경&lt;/h2&gt;
&lt;p&gt;이제 LoadBalancer 타입으로 생성된 &lt;code&gt;nginx-blue-green-svc&lt;/code&gt; 가 Green Pod 로 연결되게 selector 를 Green pod 가 선택되게 변경한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ kubectl patch svc nginx-blue-green-svc -p &amp;#39;{&amp;quot;spec&amp;quot;: {&amp;quot;selector&amp;quot;: {&amp;quot;app&amp;quot;: &amp;quot;nginx-green&amp;quot;, &amp;quot;version&amp;quot;: &amp;quot;green&amp;quot;}}}&amp;#39;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;웹브라우저로 접속하면 Green 으로 변경된 것을 확인할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPyFMJ/btrXJWfzMyp/53ysTWxtzhMqzKdHgNK7Fk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPyFMJ/btrXJWfzMyp/53ysTWxtzhMqzKdHgNK7Fk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPyFMJ/btrXJWfzMyp/53ysTWxtzhMqzKdHgNK7Fk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbPyFMJ%2FbtrXJWfzMyp%2F53ysTWxtzhMqzKdHgNK7Fk%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Kubernetes</category>
      <category>Blue Green Deployment</category>
      <category>Blue Green 배포</category>
      <category>kubernetes</category>
      <category>배포전략</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/307</guid>
      <comments>https://ahnseungkyu.com/307#entry307comment</comments>
      <pubDate>Wed, 1 Feb 2023 14:25:38 +0900</pubDate>
    </item>
    <item>
      <title>Kubernetes 에서 CSI Driver 를 활용한 ebs storage 사용하기</title>
      <link>https://ahnseungkyu.com/306</link>
      <description>&lt;p&gt;이전에는 aws 에 Kubernetes Cluster 를 설치한 후 Load Balancer 를 연결한는 방법을 설명하였다. Kubernetes Cluster 를 사용하려면 Load Balancer 외에도 필요한 기능이 있는데 그것이 바로 Storage 이다.&lt;/p&gt;
&lt;p&gt;Pod 에서 영구적으로 데이터를 저장하기 위해서는 ebs 와 같은 Block Storage 를 생성해서 연결해야 하는데 Kubernetes 에서는 CSI 로 이를 지원하고 있다.&lt;/p&gt;
&lt;p&gt;aws 에서 ebs 를 사용하려면 아래의 순서대로 적용한다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;IAM Policy 생성&lt;/li&gt;
&lt;li&gt;CSI Driver (Provisioner) 설치&lt;/li&gt;
&lt;li&gt;Storage Class 생성&lt;/li&gt;
&lt;li&gt;PVC, POD 로 테스트&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;1. IAM Policy 생성&lt;/h2&gt;
&lt;p&gt;CSI 를 위한 IAM Policy 는 생성하기 전에 이미 만들어서 제공되고 있는 Managed Policy 를 사용해도 된다. &lt;code&gt;arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;하지만 새로 만든다고 하면 아래와 같이 만들수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;{
  &amp;quot;Version&amp;quot;: &amp;quot;2012-10-17&amp;quot;,
  &amp;quot;Statement&amp;quot;: [
    {
      &amp;quot;Effect&amp;quot;: &amp;quot;Allow&amp;quot;,
      &amp;quot;Action&amp;quot;: [
        &amp;quot;ec2:CreateSnapshot&amp;quot;,
        &amp;quot;ec2:AttachVolume&amp;quot;,
        &amp;quot;ec2:DetachVolume&amp;quot;,
        &amp;quot;ec2:ModifyVolume&amp;quot;,
        &amp;quot;ec2:DescribeAvailabilityZones&amp;quot;,
        &amp;quot;ec2:DescribeInstances&amp;quot;,
        &amp;quot;ec2:DescribeSnapshots&amp;quot;,
        &amp;quot;ec2:DescribeTags&amp;quot;,
        &amp;quot;ec2:DescribeVolumes&amp;quot;,
        &amp;quot;ec2:DescribeVolumesModifications&amp;quot;
      ],
      &amp;quot;Resource&amp;quot;: &amp;quot;*&amp;quot;
    },
    {
      &amp;quot;Effect&amp;quot;: &amp;quot;Allow&amp;quot;,
      &amp;quot;Action&amp;quot;: [
        &amp;quot;ec2:CreateTags&amp;quot;
      ],
      &amp;quot;Resource&amp;quot;: [
        &amp;quot;arn:aws:ec2:*:*:volume/*&amp;quot;,
        &amp;quot;arn:aws:ec2:*:*:snapshot/*&amp;quot;
      ],
      &amp;quot;Condition&amp;quot;: {
        &amp;quot;StringEquals&amp;quot;: {
          &amp;quot;ec2:CreateAction&amp;quot;: [
            &amp;quot;CreateVolume&amp;quot;,
            &amp;quot;CreateSnapshot&amp;quot;
          ]
        }
      }
    },
    {
      &amp;quot;Effect&amp;quot;: &amp;quot;Allow&amp;quot;,
      &amp;quot;Action&amp;quot;: [
        &amp;quot;ec2:DeleteTags&amp;quot;
      ],
      &amp;quot;Resource&amp;quot;: [
        &amp;quot;arn:aws:ec2:*:*:volume/*&amp;quot;,
        &amp;quot;arn:aws:ec2:*:*:snapshot/*&amp;quot;
      ]
    },
    {
      &amp;quot;Effect&amp;quot;: &amp;quot;Allow&amp;quot;,
      &amp;quot;Action&amp;quot;: [
        &amp;quot;ec2:CreateVolume&amp;quot;
      ],
      &amp;quot;Resource&amp;quot;: &amp;quot;*&amp;quot;,
      &amp;quot;Condition&amp;quot;: {
        &amp;quot;StringLike&amp;quot;: {
          &amp;quot;aws:RequestTag/ebs.csi.aws.com/cluster&amp;quot;: &amp;quot;true&amp;quot;
        }
      }
    },
    {
      &amp;quot;Effect&amp;quot;: &amp;quot;Allow&amp;quot;,
      &amp;quot;Action&amp;quot;: [
        &amp;quot;ec2:CreateVolume&amp;quot;
      ],
      &amp;quot;Resource&amp;quot;: &amp;quot;*&amp;quot;,
      &amp;quot;Condition&amp;quot;: {
        &amp;quot;StringLike&amp;quot;: {
          &amp;quot;aws:RequestTag/CSIVolumeName&amp;quot;: &amp;quot;*&amp;quot;
        }
      }
    },
    {
      &amp;quot;Effect&amp;quot;: &amp;quot;Allow&amp;quot;,
      &amp;quot;Action&amp;quot;: [
        &amp;quot;ec2:DeleteVolume&amp;quot;
      ],
      &amp;quot;Resource&amp;quot;: &amp;quot;*&amp;quot;,
      &amp;quot;Condition&amp;quot;: {
        &amp;quot;StringLike&amp;quot;: {
          &amp;quot;ec2:ResourceTag/ebs.csi.aws.com/cluster&amp;quot;: &amp;quot;true&amp;quot;
        }
      }
    },
    {
      &amp;quot;Effect&amp;quot;: &amp;quot;Allow&amp;quot;,
      &amp;quot;Action&amp;quot;: [
        &amp;quot;ec2:DeleteVolume&amp;quot;
      ],
      &amp;quot;Resource&amp;quot;: &amp;quot;*&amp;quot;,
      &amp;quot;Condition&amp;quot;: {
        &amp;quot;StringLike&amp;quot;: {
          &amp;quot;ec2:ResourceTag/CSIVolumeName&amp;quot;: &amp;quot;*&amp;quot;
        }
      }
    },
    {
      &amp;quot;Effect&amp;quot;: &amp;quot;Allow&amp;quot;,
      &amp;quot;Action&amp;quot;: [
        &amp;quot;ec2:DeleteVolume&amp;quot;
      ],
      &amp;quot;Resource&amp;quot;: &amp;quot;*&amp;quot;,
      &amp;quot;Condition&amp;quot;: {
        &amp;quot;StringLike&amp;quot;: {
          &amp;quot;ec2:ResourceTag/kubernetes.io/created-for/pvc/name&amp;quot;: &amp;quot;*&amp;quot;
        }
      }
    },
    {
      &amp;quot;Effect&amp;quot;: &amp;quot;Allow&amp;quot;,
      &amp;quot;Action&amp;quot;: [
        &amp;quot;ec2:DeleteSnapshot&amp;quot;
      ],
      &amp;quot;Resource&amp;quot;: &amp;quot;*&amp;quot;,
      &amp;quot;Condition&amp;quot;: {
        &amp;quot;StringLike&amp;quot;: {
          &amp;quot;ec2:ResourceTag/CSIVolumeSnapshotName&amp;quot;: &amp;quot;*&amp;quot;
        }
      }
    },
    {
      &amp;quot;Effect&amp;quot;: &amp;quot;Allow&amp;quot;,
      &amp;quot;Action&amp;quot;: [
        &amp;quot;ec2:DeleteSnapshot&amp;quot;
      ],
      &amp;quot;Resource&amp;quot;: &amp;quot;*&amp;quot;,
      &amp;quot;Condition&amp;quot;: {
        &amp;quot;StringLike&amp;quot;: {
          &amp;quot;ec2:ResourceTag/ebs.csi.aws.com/cluster&amp;quot;: &amp;quot;true&amp;quot;
        }
      }
    }
  ]
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Role 에 Policy 연결&lt;/h3&gt;
&lt;p&gt;이전 글에서 설명한 &lt;code&gt;control-plane.cluster-api-provider-aws.sigs.k8s.io&lt;/code&gt;  와 &lt;code&gt;nodes.cluster-api-provider-aws.sigs.k8s.io&lt;/code&gt; role 에 위의 Policy 를 연결한다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Role :&lt;/strong&gt; &lt;code&gt;control-plane.cluster-api-provider-aws.sigs.k8s.io&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m1o7e/btrXHOV8ayn/vXKITNoAxytpyptebkII6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m1o7e/btrXHOV8ayn/vXKITNoAxytpyptebkII6k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m1o7e/btrXHOV8ayn/vXKITNoAxytpyptebkII6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm1o7e%2FbtrXHOV8ayn%2FvXKITNoAxytpyptebkII6k%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Role :&lt;/strong&gt; &lt;code&gt;nodes.cluster-api-provider-aws.sigs.k8s.io&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbPbw4/btrXJgc2zJI/7iwa6e61QZfGMj8wGAE3Z1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbPbw4/btrXJgc2zJI/7iwa6e61QZfGMj8wGAE3Z1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbPbw4/btrXJgc2zJI/7iwa6e61QZfGMj8wGAE3Z1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbPbw4%2FbtrXJgc2zJI%2F7iwa6e61QZfGMj8wGAE3Z1%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2&gt;2. CSI Driver (Provisioner) 설치&lt;/h2&gt;
&lt;p&gt;EBS 용 CSI Driver 를 helm chart repo 를 등록한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ helm repo add aws-ebs-csi-driver https://kubernetes-sigs.github.io/aws-ebs-csi-driver
$ helm repo update

$ helm search repo aws-ebs-csi-driver -l
NAME                                    CHART VERSION   APP VERSION     DESCRIPTION
aws-ebs-csi-driver/aws-ebs-csi-driver   2.16.0          1.15.0          A Helm chart for AWS EBS CSI Driver
aws-ebs-csi-driver/aws-ebs-csi-driver   2.15.1          1.14.1          A Helm chart for AWS EBS CSI Driver
...&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;지금 최신 버전 차트는 2.16.0 이다. 해당 차트는 Kubernetes 1.17+ 이상만 호환되는데 현재의 웬만한 Kubernetes 버전은 지원된다고 보면 된다.&lt;/p&gt;
&lt;p&gt;Helm chart 로 설치한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ helm upgrade -i aws-ebs-csi-driver -n kube-system aws-ebs-csi-driver/aws-ebs-csi-driver --version 2.16.0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;설치가 제대로 되었는지는 아래의 명령어로 확인할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/R3XMi/btrXECoAzuw/YLe5buNsLU7fap976Kgfp0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/R3XMi/btrXECoAzuw/YLe5buNsLU7fap976Kgfp0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/R3XMi/btrXECoAzuw/YLe5buNsLU7fap976Kgfp0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FR3XMi%2FbtrXECoAzuw%2FYLe5buNsLU7fap976Kgfp0%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2&gt;3. Storage Class 설치&lt;/h2&gt;
&lt;p&gt;ebs volume 이 생성될 때 CSI Driver 에게 필요한 설정 값을 전달해야 하는데 이것이 바로 Storage Class 라고 보면 된다.&lt;/p&gt;
&lt;p&gt;아래와 같이 생성한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ vi standard-ebs-sc.yaml
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  annotations: 
    storageclass.kubernetes.io/is-default-class: &amp;quot;true&amp;quot;
  name: standard
provisioner: ebs.csi.aws.com
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Delete

$ kubectl apply -f standard-ebs-sc.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;storage class 에 storage type (gp2, gp3, io1 등),  iops, 데이터 암호화 여부, 토폴로지 등을 넣을 수 있는데 이를 적용하면 현재 csi driver 에서 에러가 나므로 추가 확인이 필요하다. (볼륨 생성이 안된다던지, 볼륨 attach 가 안된다든지 하는 문제가 발생했는데 자세히 소스까지 찾아보지는 않았음 ㅠㅠ)&lt;/p&gt;
&lt;p&gt;storage class 가 잘 생성되었는지 확인한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ kubectl get sc
NAME                 PROVISIONER             RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
local-path           rancher.io/local-path   Delete          WaitForFirstConsumer   false                  12d
standard (default)   ebs.csi.aws.com         Delete          WaitForFirstConsumer   false                  138m&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;4. PVC, POD 로 테스트&lt;/h2&gt;
&lt;p&gt;pvc 를 생성하고 pod 에서 이를 mount 하여 활용해본다.&lt;/p&gt;
&lt;h3&gt;pvc 생성&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ vi pvc-example.yaml
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: ebs-claim
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: standard
  resources:
    requests:
      storage: 4Gi

$ kubectl apply -f pvc-example.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;sc 설정에서 &lt;code&gt;volumeBindingMode: WaitForFirstConsumer&lt;/code&gt; 이기 때문에 pod 가 생성되기 전까지는 pv 는 만들어지지 않는다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b47Hgq/btrXH805yG7/2IneXxzde0ZQmfkp2fJba1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b47Hgq/btrXH805yG7/2IneXxzde0ZQmfkp2fJba1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b47Hgq/btrXH805yG7/2IneXxzde0ZQmfkp2fJba1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb47Hgq%2FbtrXH805yG7%2F2IneXxzde0ZQmfkp2fJba1%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3&gt;POD 생성&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ vi pod-example.yaml
---
apiVersion: v1
kind: Pod
metadata:
  name: app
spec:
  containers:
  - name: app
    image: centos
    command: [&amp;quot;/bin/sh&amp;quot;]
    args: [&amp;quot;-c&amp;quot;, &amp;quot;while true; do echo $(date -u) &amp;gt;&amp;gt; /data/out.txt; sleep 5; done&amp;quot;]
    volumeMounts:
    - name: persistent-storage
      mountPath: /data
  volumes:
  - name: persistent-storage
    persistentVolumeClaim:
      claimName: ebs-claim

$ kubectl apply -f pod-example.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;out.txt 에 date 값이 설정된 것을 확인할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ kubectl exec -it app -- cat /data/out.txt&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Kubernetes</category>
      <category>aws csi driver</category>
      <category>AWS EBS</category>
      <category>CSI</category>
      <category>kubernetes</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/306</guid>
      <comments>https://ahnseungkyu.com/306#entry306comment</comments>
      <pubDate>Tue, 31 Jan 2023 19:45:16 +0900</pubDate>
    </item>
    <item>
      <title>Kubernetes Cluster 에서 Cloud Provider 로 aws LoadBalancer 연결하기</title>
      <link>https://ahnseungkyu.com/305</link>
      <description>&lt;p&gt;kubernetes 에 서비스를 올릴 때 Service 의 Type 으로 LoadBalancer 를 선택하면 cloud 에서 자동으로 LB (external-ip ) 가 생성되어 서비스 pod 에 연결된다. 어떻게 Kubernetes 에서 설정한 값이 cloud 에 연결될까? 이는 Cloud Provider 가 있어 가능하다.&lt;/p&gt;
&lt;p&gt;Cloud Provider 는 초기에 Kubernetes Controller 에 포함되어 있다. 하지만 지금은 External Kubernete Cloud Provider 로 Kubernetes 에서 제외되었으며, 이전 Kubernetes Controller 에 포함된 Cloud Provider 는 Legacy Cloud Provider 로 불리고 있다.&lt;/p&gt;
&lt;p&gt;AWS Cloud Provider 의 경우에는 아직 1.23 (Kubernetes 와 같이 버전을 맞춰가고 있음) alpha 버전이라  아직은 Legacy Cloud Provider 를 사용하는 것이 안정적이다.&lt;/p&gt;
&lt;p&gt;aws 에서는 아래의 순서대로 적용한다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;IAM Policy, Role 생성&lt;/li&gt;
&lt;li&gt;VPC, Subnet, Routing Table, Internet Gateway, Nat Gateway 생성&lt;/li&gt;
&lt;li&gt;VM 생성&lt;/li&gt;
&lt;li&gt;aws resource 에 Tag 적용&lt;/li&gt;
&lt;li&gt;Kubernetes Cluster 생성&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;1. IAM Policy, Role 생성&lt;/h2&gt;
&lt;p&gt;Control plane 과 Node 2개의 Policy 를 생성한다.&lt;/p&gt;
&lt;h3&gt;Control Plane Policy&lt;/h3&gt;
&lt;p&gt;control node 에서 사용할 policy 이다.&lt;/p&gt;
&lt;p&gt;정책명: &lt;strong&gt;&lt;code&gt;control-plane.cluster-api-provider-aws.sigs.k8s.io&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;{
  &amp;quot;Version&amp;quot;: &amp;quot;2012-10-17&amp;quot;,
  &amp;quot;Statement&amp;quot;: [
    {
      &amp;quot;Effect&amp;quot;: &amp;quot;Allow&amp;quot;,
      &amp;quot;Action&amp;quot;: [
        &amp;quot;autoscaling:DescribeAutoScalingGroups&amp;quot;,
        &amp;quot;autoscaling:DescribeLaunchConfigurations&amp;quot;,
        &amp;quot;autoscaling:DescribeTags&amp;quot;,
        &amp;quot;ec2:DescribeInstances&amp;quot;,
        &amp;quot;ec2:DescribeRegions&amp;quot;,
        &amp;quot;ec2:DescribeRouteTables&amp;quot;,
        &amp;quot;ec2:DescribeSecurityGroups&amp;quot;,
        &amp;quot;ec2:DescribeSubnets&amp;quot;,
        &amp;quot;ec2:DescribeVolumes&amp;quot;,
        &amp;quot;ec2:DescribeAvailabilityZones&amp;quot;,
        &amp;quot;ec2:CreateSecurityGroup&amp;quot;,
        &amp;quot;ec2:CreateTags&amp;quot;,
        &amp;quot;ec2:CreateVolume&amp;quot;,
        &amp;quot;ec2:ModifyInstanceAttribute&amp;quot;,
        &amp;quot;ec2:ModifyVolume&amp;quot;,
        &amp;quot;ec2:AttachVolume&amp;quot;,
        &amp;quot;ec2:AuthorizeSecurityGroupIngress&amp;quot;,
        &amp;quot;ec2:CreateRoute&amp;quot;,
        &amp;quot;ec2:DeleteRoute&amp;quot;,
        &amp;quot;ec2:DeleteSecurityGroup&amp;quot;,
        &amp;quot;ec2:DeleteVolume&amp;quot;,
        &amp;quot;ec2:DetachVolume&amp;quot;,
        &amp;quot;ec2:RevokeSecurityGroupIngress&amp;quot;,
        &amp;quot;ec2:DescribeVpcs&amp;quot;,
        &amp;quot;elasticloadbalancing:AddTags&amp;quot;,
        &amp;quot;elasticloadbalancing:AttachLoadBalancerToSubnets&amp;quot;,
        &amp;quot;elasticloadbalancing:ApplySecurityGroupsToLoadBalancer&amp;quot;,
        &amp;quot;elasticloadbalancing:CreateLoadBalancer&amp;quot;,
        &amp;quot;elasticloadbalancing:CreateLoadBalancerPolicy&amp;quot;,
        &amp;quot;elasticloadbalancing:CreateLoadBalancerListeners&amp;quot;,
        &amp;quot;elasticloadbalancing:ConfigureHealthCheck&amp;quot;,
        &amp;quot;elasticloadbalancing:DeleteLoadBalancer&amp;quot;,
        &amp;quot;elasticloadbalancing:DeleteLoadBalancerListeners&amp;quot;,
        &amp;quot;elasticloadbalancing:DescribeLoadBalancers&amp;quot;,
        &amp;quot;elasticloadbalancing:DescribeLoadBalancerAttributes&amp;quot;,
        &amp;quot;elasticloadbalancing:DetachLoadBalancerFromSubnets&amp;quot;,
        &amp;quot;elasticloadbalancing:DeregisterInstancesFromLoadBalancer&amp;quot;,
        &amp;quot;elasticloadbalancing:ModifyLoadBalancerAttributes&amp;quot;,
        &amp;quot;elasticloadbalancing:RegisterInstancesWithLoadBalancer&amp;quot;,
        &amp;quot;elasticloadbalancing:SetLoadBalancerPoliciesForBackendServer&amp;quot;,
        &amp;quot;elasticloadbalancing:AddTags&amp;quot;,
        &amp;quot;elasticloadbalancing:CreateListener&amp;quot;,
        &amp;quot;elasticloadbalancing:CreateTargetGroup&amp;quot;,
        &amp;quot;elasticloadbalancing:DeleteListener&amp;quot;,
        &amp;quot;elasticloadbalancing:DeleteTargetGroup&amp;quot;,
        &amp;quot;elasticloadbalancing:DescribeListeners&amp;quot;,
        &amp;quot;elasticloadbalancing:DescribeLoadBalancerPolicies&amp;quot;,
        &amp;quot;elasticloadbalancing:DescribeTargetGroups&amp;quot;,
        &amp;quot;elasticloadbalancing:DescribeTargetHealth&amp;quot;,
        &amp;quot;elasticloadbalancing:ModifyListener&amp;quot;,
        &amp;quot;elasticloadbalancing:ModifyTargetGroup&amp;quot;,
        &amp;quot;elasticloadbalancing:RegisterTargets&amp;quot;,
        &amp;quot;elasticloadbalancing:DeregisterTargets&amp;quot;,
        &amp;quot;elasticloadbalancing:SetLoadBalancerPoliciesOfListener&amp;quot;,
        &amp;quot;iam:CreateServiceLinkedRole&amp;quot;,
        &amp;quot;kms:DescribeKey&amp;quot;
      ],
      &amp;quot;Resource&amp;quot;: [
        &amp;quot;*&amp;quot;
      ]
    }
  ]
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Node Policy&lt;/h3&gt;
&lt;p&gt;일반 Node 에 대한 policy 이다.&lt;/p&gt;
&lt;p&gt;정책명: &lt;strong&gt;&lt;strong&gt;&lt;code&gt;nodes.cluster-api-provider-aws.sigs.k8s.io&lt;/code&gt;&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;{
  &amp;quot;Version&amp;quot;: &amp;quot;2012-10-17&amp;quot;,
  &amp;quot;Statement&amp;quot;: [
    {
      &amp;quot;Effect&amp;quot;: &amp;quot;Allow&amp;quot;,
      &amp;quot;Action&amp;quot;: [
        &amp;quot;ec2:DescribeInstances&amp;quot;,
        &amp;quot;ec2:DescribeRegions&amp;quot;,
        &amp;quot;ecr:GetAuthorizationToken&amp;quot;,
        &amp;quot;ecr:BatchCheckLayerAvailability&amp;quot;,
        &amp;quot;ecr:GetDownloadUrlForLayer&amp;quot;,
        &amp;quot;ecr:GetRepositoryPolicy&amp;quot;,
        &amp;quot;ecr:DescribeRepositories&amp;quot;,
        &amp;quot;ecr:ListImages&amp;quot;,
        &amp;quot;ecr:BatchGetImage&amp;quot;
      ],
      &amp;quot;Resource&amp;quot;: &amp;quot;*&amp;quot;
    }
  ]
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;policy 를 생성했으면 이제 Role 을 생성한다.&lt;/p&gt;
&lt;h3&gt;Control plane Role&lt;/h3&gt;
&lt;p&gt;Policy 를 활용할 수 있는 Role 을 만들어서 Policy 와 연결한다.&lt;/p&gt;
&lt;p&gt;Role 명: &lt;strong&gt;&lt;code&gt;control-plane.cluster-api-provider-aws.sigs.k8s.io&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;연결할 Policy 리스트
- control-plane.cluster-api-provider-aws.sigs.k8s.io
- nodes.cluster-api-provider-aws.sigs.k8s.io&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Node Role&lt;/h3&gt;
&lt;p&gt;Role 명: &lt;strong&gt;&lt;code&gt;nodes.cluster-api-provider-aws.sigs.k8s.io&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;연결할 Policy 리스트
- nodes.cluster-api-provider-aws.sigs.k8s.io&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;2. VPC, Subnet, Routing Table, Internet Gateway, Nat Gateway 생성&lt;/h2&gt;
&lt;p&gt;서울 리전의 경우 VPC 를 1개 만들고, public 용도의 subnet 4개, private 용도의 subnet 4개를 만든다.&lt;/p&gt;
&lt;p&gt;Internet Gateway 1개를 만들어서 public subnet 에 연결하고, Nat Gateway 4개를 만들어서 각각 private subnet 에 연결한다.&lt;/p&gt;
&lt;p&gt;Routing Table 은 subnet 갯수에 맞는 8개를 만들어서 각각 연결한다. private 용 4개의 Routing table 은 0.0.0.0/0 → nat gateway 를 대상으로 설정하고, public 용 4개의 Routing table 은 0.0.0.0/0 → internet gateway 대상으로 설정한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;1. vpc : 1개
   - vpc

2. subent : 8개
   - public-subnet-a
   - public-subnet-b
   - public-subnet-c
   - public-subnet-d
   - private-subnet-a
   - private-subnet-b
   - private-subnet-c
   - private-subnet-d

3. internat gateway : 1개
   - igw

4. Nat Gateway : 4개
   - nat-private-a
   - nat-private-b
   - nat-private-c
   - nat-private-d

5. Routing Table : 4개
   - rt-public-a (0.0.0.0/0 -&amp;gt; igw)
   - rt-public-b (0.0.0.0/0 -&amp;gt; igw)
   - rt-public-c (0.0.0.0/0 -&amp;gt; igw)
   - rt-public-d (0.0.0.0/0 -&amp;gt; igw)
   - rt-priabe-a (0.0.0.0/0 -&amp;gt; nat-private-a)
   - rt-priabe-b (0.0.0.0/0 -&amp;gt; nat-private-b)
   - rt-priabe-c (0.0.0.0/0 -&amp;gt; nat-private-c)
   - rt-priabe-d (0.0.0.0/0 -&amp;gt; nat-private-d)&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3. VM 생성&lt;/h2&gt;
&lt;p&gt;VM 은 Controler Plane 3대는 각 private subnet 에 1대씩 생성하고(subnet 1개는 남는다), Node 용 4대는 각 private subnet 1대씩 생성하다.&lt;/p&gt;
&lt;p&gt;bastion 노드로 public subnet 에 1대 생성한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;1. bastion VM 1대
   - public-subnet-a

2. Control Plane VM 3대
   - private-subnet-a
   - private-subnet-b
   - private-subnet-c

3. Node VM 4대
   - private-subnet-a
   - private-subnet-b
   - private-subnet-c
   - private-subnet-d&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;4. Aws Resource 에 Tag 설정&lt;/h2&gt;
&lt;p&gt;aws cloud provider 가 리소스를 파악하기 위해서는 aws 에 적절한 값을 설정해야 한다.&lt;/p&gt;
&lt;h3&gt;4-1. VM 에 IAM Role 을 할당&lt;/h3&gt;
&lt;p&gt;VM 에서 권한을 얻기 위해서는 반드시 IAM Role 을 할당해야 한다.&lt;/p&gt;
&lt;p&gt;Control node 에는 &lt;strong&gt;&lt;code&gt;control-plane.cluster-api-provider-aws.sigs.k8s.io&lt;/code&gt;&lt;/strong&gt; role 을 할당한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcjsiw/btrXbrMHYHq/v43F5DvNtH6GGb41y6MaQK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcjsiw/btrXbrMHYHq/v43F5DvNtH6GGb41y6MaQK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcjsiw/btrXbrMHYHq/v43F5DvNtH6GGb41y6MaQK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbcjsiw%2FbtrXbrMHYHq%2Fv43F5DvNtH6GGb41y6MaQK%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;일반 Node 에는 &lt;strong&gt;&lt;code&gt;nodes.cluster-api-provider-aws.sigs.k8s.io&lt;/code&gt;&lt;/strong&gt; role 을 할당한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nyWVa/btrXa09DJNu/Sez2rV7qWdchQ70y8Tp3X1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nyWVa/btrXa09DJNu/Sez2rV7qWdchQ70y8Tp3X1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nyWVa/btrXa09DJNu/Sez2rV7qWdchQ70y8Tp3X1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnyWVa%2FbtrXa09DJNu%2FSez2rV7qWdchQ70y8Tp3X1%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3&gt;4-2 VM 에 Tag 설정&lt;/h3&gt;
&lt;p&gt;VM 에는 Kubernetes Cluster Name 을 Tag 로 지정한다. &lt;code&gt;kubernetes.io/cluster/&amp;lt;cluster name&amp;gt;&lt;/code&gt; 과 같이 지정하는데 Cluster Name 은 Kubernetes 를 설치할 때 지정할 수 있다. 기본 값은 &lt;code&gt;cluster.local&lt;/code&gt; 인데 여기서는 &lt;code&gt;ahnsk&lt;/code&gt; 로 이름을 지정하였다.&lt;/p&gt;
&lt;p&gt;그리고 vm 의 역할을 지정해야 하는데 Controler Node 는 &lt;code&gt;control-plane&lt;/code&gt; 으로, Node 는 &lt;code&gt;node&lt;/code&gt; 로 지정한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bziu9v/btrW4EUAisf/tHIdUmYO2j1WNNmNjKdt61/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bziu9v/btrW4EUAisf/tHIdUmYO2j1WNNmNjKdt61/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bziu9v/btrW4EUAisf/tHIdUmYO2j1WNNmNjKdt61/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbziu9v%2FbtrW4EUAisf%2FtHIdUmYO2j1WNNmNjKdt61%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2t0iw/btrWZXtwj02/UIHkFlHCi50LsoI0RrGlxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2t0iw/btrWZXtwj02/UIHkFlHCi50LsoI0RrGlxk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2t0iw/btrWZXtwj02/UIHkFlHCi50LsoI0RrGlxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2t0iw%2FbtrWZXtwj02%2FUIHkFlHCi50LsoI0RrGlxk%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3&gt;4-3. Subnet 에 Tag 설정&lt;/h3&gt;
&lt;p&gt;Load Balancer 를 핸들링 하기 위해서 Kubernetes Cluster 가 어느 Subnet 과 Routing Table 을 사용해야 하는지 알아야 한다.&lt;/p&gt;
&lt;p&gt;주의해야 할 점은 public subnet 의 경우 &lt;code&gt;[kubernetes.io/role/elb](http://kubernetes.io/role/elb)&lt;/code&gt; 이지만, private subnet 의 경우에는 &lt;code&gt;[kubernetes.io/role/internal-elb](http://kubernetes.io/role/internal-elb)&lt;/code&gt; 로 해야 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhbJNQ/btrW0PoMiii/IGdhiMAhwdpJ064Hx9lMgK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhbJNQ/btrW0PoMiii/IGdhiMAhwdpJ064Hx9lMgK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhbJNQ/btrW0PoMiii/IGdhiMAhwdpJ064Hx9lMgK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhbJNQ%2FbtrW0PoMiii%2FIGdhiMAhwdpJ064Hx9lMgK%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3&gt;4-4. Routing Table 에 Tag 설정&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IoDc1/btrW77WeKyp/tmRrHXszKhsuwvR9sMAjj1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IoDc1/btrW77WeKyp/tmRrHXszKhsuwvR9sMAjj1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IoDc1/btrW77WeKyp/tmRrHXszKhsuwvR9sMAjj1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIoDc1%2FbtrW77WeKyp%2FtmRrHXszKhsuwvR9sMAjj1%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2&gt;5. Kubernetes Cluster 생성&lt;/h2&gt;
&lt;p&gt;Kubernetes cluster 이름은 앞에서 설명했듯이 &lt;code&gt;ahnsk&lt;/code&gt; 로 설정한다.&lt;/p&gt;
&lt;p&gt;kubeadm 혹은 kubespray 를 사용할 수 있으며 여기서 생성 방법을 생략한다.&lt;/p&gt;
&lt;p&gt;aws cloud provider 를 활성화 하기 위해서는 API Server, Controller, Kubelet 에 &lt;code&gt;--cloud-provider=aws&lt;/code&gt; 옵션을 추가해야 한다.&lt;/p&gt;
&lt;h3&gt;kube-apiserver.yaml&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;apiVersion: v1
kind: Pod
metadata:
  annotations:
    kubeadm.kubernetes.io/kube-apiserver.advertise-address.endpoint: 172.31.22.52:6443
  creationTimestamp: null
  labels:
    component: kube-apiserver
    tier: control-plane
  name: kube-apiserver
  namespace: kube-system
spec:
  containers:
  - command:
    - kube-apiserver
    - --advertise-address=172.31.22.52
...
    **- --cloud-provider=aws**
...
    image: registry.k8s.io/kube-apiserver:v1.24.6
...&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;kube-controller-manager.yaml&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    component: kube-controller-manager
    tier: control-plane
  name: kube-controller-manager
  namespace: kube-system
spec:
  containers:
  - command:
    - kube-controller-manager
    - --allocate-node-cidrs=true
...
    **- --cloud-provider=aws
...**
    image: registry.k8s.io/kube-controller-manager:v1.24.6
...&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;kubelet.env&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;...
KUBELET_CLOUDPROVIDER=&amp;quot;**--cloud-provider=aws --cloud-config=/etc/kubernetes/cloud_config**&amp;quot;
...&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;kubelet 은 aws 의 리소스를 위해 추가해야 할 값들이 있는데 &lt;code&gt;cloud_config&lt;/code&gt; 을 만들어서 옵션을 전달하였다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;[Global]
zone=
vpc=vpc-b342d5d8
subnetId=
routeTableId=
roleArn=
kubernetesClusterTag=ahnsk
kubernetesClusterId=ahnsk
disableSecurityGroupIngress=false
disableStrictZoneCheck=false
elbSecurityGroup=&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;값을 다 채워 넣으면 apiserver 가 &lt;code&gt;kube-apiserver-master-dummy&lt;/code&gt; 라는 이름으로 잘못 실행되므로 조심해야 한다. master-dummy 로 띄우는 방법은 aws account 가 다를 경우에만 사용하는 방법이다. 이는 아래 소스를 보면 알 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;https://github.com/kubernetes/legacy-cloud-providers/blob/707ecda639b086132369678680a1b34d4d2b5c7c/aws/aws.go#L1251

...
  tagged := cfg.Global.KubernetesClusterTag != &amp;quot;&amp;quot; || cfg.Global.KubernetesClusterID != &amp;quot;&amp;quot;
    if cfg.Global.VPC != &amp;quot;&amp;quot; &amp;amp;&amp;amp; (cfg.Global.SubnetID != &amp;quot;&amp;quot; || cfg.Global.RoleARN != &amp;quot;&amp;quot;) &amp;amp;&amp;amp; tagged {
        // When the master is running on a different AWS account, cloud provider or on-premise
        // build up a dummy instance and use the VPC from the nodes account
        klog.Info(&amp;quot;Master is configured to run on a different AWS account, different cloud provider or on-premises&amp;quot;)
        awsCloud.selfAWSInstance = &amp;amp;awsInstance{
            nodeName: &amp;quot;master-dummy&amp;quot;,
            vpcID:    cfg.Global.VPC,
            subnetID: cfg.Global.SubnetID,
        }
        awsCloud.vpcID = cfg.Global.VPC
    } else {
        selfAWSInstance, err := awsCloud.buildSelfAWSInstance()
        if err != nil {
            return nil, err
        }
        awsCloud.selfAWSInstance = selfAWSInstance
        awsCloud.vpcID = selfAWSInstance.vpcID
    }
...&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;RoleARN 의 값을 넣으면 안되는데 값이 없으면서도 어떻게 kubelet 이 해당 Role 로 인증을 받을 수 있을까? 이는 앞에서 설명한 VM 에 IAM Role 인 &lt;code&gt;control-plane.cluster-api-provider-aws.sigs.k8s.io&lt;/code&gt; 이나 &lt;code&gt;nodes.cluster-api-provider-aws.sigs.k8s.io&lt;/code&gt; 이 설정되어 있기 때문에 가능하다.&lt;/p&gt;
&lt;h3&gt;kubelet-config.yaml&lt;/h3&gt;
&lt;p&gt;kubernetes node 정보에 providerID 값이 들어가 있어야 한다. 만약 이 정보가 없다면 LoadBalancer 가 생성된다고 하더라도 인스턴스가 LoadBalancer 에 할당되지 않아 제대로 사용할 수 가 없다.&lt;/p&gt;
&lt;p&gt;providerID 는 kubelet-config.yaml 에 추가한다. &lt;code&gt;aws:///&amp;lt;zone-id&amp;gt;/&amp;lt;instance-id&amp;gt;&lt;/code&gt; 값으로 추가한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ sudo vi /etc/kubernetes/kubelet-config.yaml
...
providerID: &amp;quot;aws:///ap-northeast-2d/i-0f59f059e2d64213f&amp;quot;
...&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이미 노드가 생성된 경우에는 해당 값을 변경하고 kubelet 서비스를 다시 restart 한다고 값이 추가되지는 않는다. 그래서 patch 명령으로 동적으로 추가하는 것이 좋다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ kubectl patch node ip-172-31-46-179.ap-northeast-2.compute.internal -p &amp;#39;{&amp;quot;spec&amp;quot;: {&amp;quot;providerID&amp;quot;: &amp;quot;aws:///ap-northeast-2d/i-08cb6f884239f894c&amp;quot;}}&amp;#39;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;5. Nginx 로 테스트&lt;/h3&gt;
&lt;p&gt;nginx 를 생성하고 service 를 LoadBalancer type 으로 생성하여 잘 접속이 되는지 확인해 보자.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ kubectl create deploy nginx --image=nginx
deployment.apps/nginx created&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ kubectl get pods
NAME                    READY   STATUS    RESTARTS   AGE
nginx-8f458dc5b-nhkfd   1/1     Running   0          55s&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ kubectl expose deployment nginx --name nginx-svc --target-port=80 --port=80 --type=LoadBalancer&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ kubectl get svc
NAME         TYPE           CLUSTER-IP     EXTERNAL-IP                                                                   PORT(S)        AGE
kubernetes   ClusterIP      10.233.0.1     &amp;lt;none&amp;gt;                                                                        443/TCP        5h28m
nginx-svc    LoadBalancer   10.233.7.131   a76a315f5d7c14652a4db83cc3b25125-113127685.ap-northeast-2.elb.amazonaws.com   80:30796/TCP   27s&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Kubernetes</category>
      <category>AWS Cloud Provider</category>
      <category>kubernetes</category>
      <category>LoadBalancer</category>
      <category>VM Instance 할당 에러</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/305</guid>
      <comments>https://ahnseungkyu.com/305#entry305comment</comments>
      <pubDate>Wed, 25 Jan 2023 16:44:24 +0900</pubDate>
    </item>
    <item>
      <title>(tmux) 터미널을 효율적으로 사용하기 (1/2)</title>
      <link>https://ahnseungkyu.com/304</link>
      <description>&lt;p&gt;command line 명령을 사용할 때 터미널에서 여러 기능들을 사용해야 할 때가 있다. 예를 들어 여러 윈도우(창)을 띄워놓고 필요에 따라 옮긴다던가 하나의 윈도우을 상하, 혹은 좌우로 구분하여 나눠서 사용하는 경우가 있다.&lt;/p&gt;
&lt;p&gt;보통은 명령어를 여러 디렉토리를 옮겨가며 작업하기 때문에 디렉토리 마다 윈도우를 만들어 사용한다. 혹은 포그라운드로 프로세스를 띄워 출력되는 로그를 확인하고, 다른 윈도에서 작업하는 경우도 있다.&lt;/p&gt;
&lt;p&gt;위와 같은 기능을 제공하는 툴에는 tmux 라는 sw가 있다. 일반적으로 linux 에는 기본으로 설치되어 있고 mac 에서는 쉽게 설치할 수 있으므로 쉽게 활용할 수 가 있다.&lt;/p&gt;
&lt;h2&gt;1. 세션 관리&lt;/h2&gt;
&lt;h3&gt;세션 만들기&lt;/h3&gt;
&lt;p&gt;tmux 는 세션 단위로 구분하여 관리한다. 자신만의 새로운 세션을 만들어 독립으로 사용할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ tmux new -s ahnsk&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cHUR5Z/btrWde9Ggnm/UL66ScqDTOoZKRxjsHMkDk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cHUR5Z/btrWde9Ggnm/UL66ScqDTOoZKRxjsHMkDk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cHUR5Z/btrWde9Ggnm/UL66ScqDTOoZKRxjsHMkDk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcHUR5Z%2FbtrWde9Ggnm%2FUL66ScqDTOoZKRxjsHMkDk%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ahnsk&lt;/code&gt; 이라는 새로운 세션(session)이 생성되면서 &lt;code&gt;1:zsh&lt;/code&gt; 라는 윈도우(window) 1개가 기본적으로 생성되었다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ exit&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;exit&lt;/code&gt; 는 현재의 윈도우를 삭제한다. 지금은 세션에 1개의 윈도우 밖에 없기 때문에 윈도우가 삭제되면 해당 세션도 삭제된다.&lt;/p&gt;
&lt;h3&gt;command prefix&lt;/h3&gt;
&lt;p&gt;tmux 에서는 &lt;code&gt;vi&lt;/code&gt; 처럼 명령모드를 사용할 수 있다. &lt;code&gt;Ctrl&lt;/code&gt; &lt;code&gt;+&lt;/code&gt; &lt;code&gt;b&lt;/code&gt; (control 키와 b 키를 동시에 누름)를 입력한 이후에 명령어를 입력하면 되는데 명령 모드를 알려주는 이 키 조합을 command prefix 라고 한다. 줄여서 앞으로는 &lt;code&gt;prefix&lt;/code&gt; 라고 한다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;t&lt;/code&gt; 를 누르면 화면에 시간에 표시된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXOoZE/btrWeffY17e/xwAWxItCkqsjB23AKcEsk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXOoZE/btrWeffY17e/xwAWxItCkqsjB23AKcEsk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXOoZE/btrWeffY17e/xwAWxItCkqsjB23AKcEsk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXOoZE%2FbtrWeffY17e%2FxwAWxItCkqsjB23AKcEsk1%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3&gt;Detaching 과 Attaching&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;exit&lt;/code&gt; 는 윈도우를 삭제(경우에 따라서는 세션까지도 삭제) 하기 때문에 이전의 세션과 윈도우를 계속 유지 시키면서 tmux 에서 빠져나오고 싶을 때도 있다. 이 때 사용해야할 기능이 detaching 기능이다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ top&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/esdLk3/btrWbViKVJ2/5rWOgOXbwFUlWKTWLWRFR0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/esdLk3/btrWbViKVJ2/5rWOgOXbwFUlWKTWLWRFR0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/esdLk3/btrWbViKVJ2/5rWOgOXbwFUlWKTWLWRFR0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FesdLk3%2FbtrWbViKVJ2%2F5rWOgOXbwFUlWKTWLWRFR0%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;d&lt;/code&gt; 를 입력하여 detaching 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TYplI/btrWc3tEMJ2/tzxAhL75XIBGnFQAPTcYEK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TYplI/btrWc3tEMJ2/tzxAhL75XIBGnFQAPTcYEK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TYplI/btrWc3tEMJ2/tzxAhL75XIBGnFQAPTcYEK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTYplI%2FbtrWc3tEMJ2%2FtzxAhL75XIBGnFQAPTcYEK%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;[detached (from session ahnsk)] 가 출력되고 원래의 터미널 창으로 빠져나온 것이 확인 된다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;-d&lt;/code&gt;  옵션으로 새로운 세션을 만들고 바로 detaching 할 수 도 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ tmux new -s dummy -d&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;세션을 조회하여 기존에 만든 세션의 리스트를 확인할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ tmux ls

--- output ---
ahnsk: 1 windows (created Sat Jan 14 14:51:09 2023)
dummy: 1 windows (created Sat Jan 14 15:25:39 2023)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;기존의 만든 ahnsk 세션으로 들어가고 싶으면 &lt;code&gt;attach&lt;/code&gt; 명령을 쓰면 된다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ tmux attach -t ahnsk&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cR8mJc/btrWdfHDBk0/cCKKzIkmFzpogesO5JeAK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cR8mJc/btrWdfHDBk0/cCKKzIkmFzpogesO5JeAK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cR8mJc/btrWdfHDBk0/cCKKzIkmFzpogesO5JeAK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcR8mJc%2FbtrWdfHDBk0%2FcCKKzIkmFzpogesO5JeAK1%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3&gt;세션 삭제&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;kill-session&lt;/code&gt; 옵션으로 세션을 삭제할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ tmux kill-session -t ahnsk
$ tmux kill-session -t dummy&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;2. 윈도우 관리&lt;/h2&gt;
&lt;h3&gt;윈도우 만들기&lt;/h3&gt;
&lt;p&gt;session 을 만들면 새로운 윈도우도 기본으로 생성된다고 했다. 이 때 &lt;code&gt;-n&lt;/code&gt; 옵션을 사용하여 생성되는 윈도우에 이름을 넣을 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ tmux new -s ahnsk -n shell&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cSv9u4/btrWeYd1chh/Uttcftj3BQ6HW8Bk60zXO1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cSv9u4/btrWeYd1chh/Uttcftj3BQ6HW8Bk60zXO1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cSv9u4/btrWeYd1chh/Uttcftj3BQ6HW8Bk60zXO1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcSv9u4%2FbtrWeYd1chh%2FUttcftj3BQ6HW8Bk60zXO1%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;c&lt;/code&gt; 명령으로 새로운 윈도우를 만들 수 있다. 이렇게 새로 만든 윈도우에 top 명령을 실행해 보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/777pN/btrWd0wtLE7/nWQ7V8oCkBJvx3wkJlCLi0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/777pN/btrWd0wtLE7/nWQ7V8oCkBJvx3wkJlCLi0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/777pN/btrWd0wtLE7/nWQ7V8oCkBJvx3wkJlCLi0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F777pN%2FbtrWd0wtLE7%2FnWQ7V8oCkBJvx3wkJlCLi0%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3&gt;윈도우 이름 변경&lt;/h3&gt;
&lt;p&gt;첫번째 윈도우의 이름은 shell 이고 두번째 top 이 실행되고 있는 윈도우의 이름은 top 이다. (top 이 실행되고 있으므로) 두번째 윈도우 이름을 process 로 변경해 보자.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;,&lt;/code&gt; 로 윈도우 이름을 변경할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVOAbE/btrWc2hiA0S/KL67IFgaOqaak75a1pzgfk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVOAbE/btrWc2hiA0S/KL67IFgaOqaak75a1pzgfk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVOAbE/btrWc2hiA0S/KL67IFgaOqaak75a1pzgfk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVOAbE%2FbtrWc2hiA0S%2FKL67IFgaOqaak75a1pzgfk%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;이름을 넣은 뒤에 &lt;code&gt;enter&lt;/code&gt; 를 치면 된다.&lt;/p&gt;
&lt;h3&gt;윈도우 이동&lt;/h3&gt;
&lt;p&gt;작업 윈도우를 아래 명령으로 옮겨 다닐 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;n&lt;/code&gt; : 현재 윈도우 다음(next) 윈도우로 이동하기&lt;/p&gt;
&lt;p&gt;&lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;p&lt;/code&gt; : 현재 윈도우 이전(previous) 윈도우로 이동하기&lt;/p&gt;
&lt;p&gt;&lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;1&lt;/code&gt; : 첫번째(1) 윈도우로 이동하기&lt;/p&gt;
&lt;p&gt;&lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;5&lt;/code&gt; : 다섯번째(5) 윈도우로 이동하기&lt;/p&gt;
&lt;p&gt;&lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;w&lt;/code&gt; : 윈도우 리스트를 보여주고 선택하여 이동하기&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgKd3Y/btrWd1a4s6R/ZX0ubbXdj1kDOePrpTPDy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgKd3Y/btrWd1a4s6R/ZX0ubbXdj1kDOePrpTPDy0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgKd3Y/btrWd1a4s6R/ZX0ubbXdj1kDOePrpTPDy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcgKd3Y%2FbtrWd1a4s6R%2FZX0ubbXdj1kDOePrpTPDy0%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3&gt;윈도우 닫기&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;&amp;amp;&lt;/code&gt; 로 명령으로 확인 입력(y)을 받으면 윈도우를 닫을 수(삭제할 수) 있다. &lt;code&gt;exit&lt;/code&gt; 를 입력하여 확인없이 바로 윈도우가 삭제된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kAwvi/btrWdeIC3YU/KKeFa5QRruJ1GcUKkxTY10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kAwvi/btrWdeIC3YU/KKeFa5QRruJ1GcUKkxTY10/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kAwvi/btrWdeIC3YU/KKeFa5QRruJ1GcUKkxTY10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkAwvi%2FbtrWdeIC3YU%2FKKeFa5QRruJ1GcUKkxTY10%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3&gt;윈도우 이름으로 생성하기&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;:&lt;/code&gt; 으로 명령어 입력창을 띄울 수 있다. 여기에 &lt;code&gt;new-window -n monitor&lt;/code&gt; 라고 입력하고 &lt;code&gt;enter&lt;/code&gt; 를 치면 새로운 윈도우에 이름을 지정하여 생성할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dQIwVT/btrWbLtLH0Q/cEnzgyHpRmppawbcHHPtMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dQIwVT/btrWbLtLH0Q/cEnzgyHpRmppawbcHHPtMk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dQIwVT/btrWbLtLH0Q/cEnzgyHpRmppawbcHHPtMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdQIwVT%2FbtrWbLtLH0Q%2FcEnzgyHpRmppawbcHHPtMk%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2&gt;3. 패인 관리&lt;/h2&gt;
&lt;h3&gt;패인(pane) 만들기&lt;/h3&gt;
&lt;p&gt;윈도우 안의 구분되는 영역을 패인이라 한다. 윈도우를 수평으로 2개의 패인으로 나누거나 수직으로 2개의 패인으로 나눌 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;%&lt;/code&gt; : 윈도우를 수평(좌우)으로 2개의 패인으로 나눈다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cij4Bv/btrWbT6kT2h/sfsV4GSKHBRjvwb1QP6Bpk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cij4Bv/btrWbT6kT2h/sfsV4GSKHBRjvwb1QP6Bpk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cij4Bv/btrWbT6kT2h/sfsV4GSKHBRjvwb1QP6Bpk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcij4Bv%2FbtrWbT6kT2h%2FsfsV4GSKHBRjvwb1QP6Bpk%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;&amp;quot;&lt;/code&gt; (double quote) : 윈도우를 수직(위아래)으로 2개의 패인으로 나눈다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MoFe7/btrWcKgLSpv/v3xvi4kkEGuW4io1JUooZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MoFe7/btrWcKgLSpv/v3xvi4kkEGuW4io1JUooZK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MoFe7/btrWcKgLSpv/v3xvi4kkEGuW4io1JUooZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMoFe7%2FbtrWcKgLSpv%2Fv3xvi4kkEGuW4io1JUooZK%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3&gt;패인 이동하기&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;Left 화살표&lt;/code&gt; : 좌측 패인으로 이동하기&lt;/p&gt;
&lt;p&gt;&lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;Right 화살표&lt;/code&gt; : 우측 패인으로 이동하기&lt;/p&gt;
&lt;p&gt;&lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;Up 화살표&lt;/code&gt; : 위 패인으로 이동하기&lt;/p&gt;
&lt;p&gt;&lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;Downe 화살표&lt;/code&gt; : 아래 패인으로 이동하기&lt;/p&gt;
&lt;p&gt;&lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;o&lt;/code&gt; : 시계 방향으로 패인 이동하기&lt;/p&gt;
&lt;h3&gt;패인 삭제하기&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;x&lt;/code&gt; 명령으로 현재 선택된 패인을 삭제할 수 있다. &lt;code&gt;exit&lt;/code&gt; 로도 삭제가 가능하다. 가끔 화면에 키보드 입력이 안돼서 &lt;code&gt;exit&lt;/code&gt; 를 화면에 입력할 수 없는 경우가 있다. 이 경우에는 명령모드인 &lt;code&gt;prefix&lt;/code&gt; + &lt;code&gt;x&lt;/code&gt; 로 삭제해야 하므로 명령모드도 알아 두는 것이 좋다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JRzuX/btrWdHqiP9h/7aGhX3QA9394AihL4jSGTK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JRzuX/btrWdHqiP9h/7aGhX3QA9394AihL4jSGTK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JRzuX/btrWdHqiP9h/7aGhX3QA9394AihL4jSGTK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJRzuX%2FbtrWdHqiP9h%2F7aGhX3QA9394AihL4jSGTK%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Linux</category>
      <category>split pane</category>
      <category>split window</category>
      <category>tmux</category>
      <category>창나누기</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/304</guid>
      <comments>https://ahnseungkyu.com/304#entry304comment</comments>
      <pubDate>Sat, 14 Jan 2023 16:53:46 +0900</pubDate>
    </item>
    <item>
      <title>(go-06) Go If, For, Switch, Function</title>
      <link>https://ahnseungkyu.com/303</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;언어를 배울 때 가장 기본적인 것 중에 하나가 비교문(if), 반복문(for), 함수(function) 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;If 문&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;if 는 비교 구문에서 사용되는 키워드 이다. 변수 선언과 동시에 비교를 할 수 있는데 이 때 선언된 변수는 해당 if 문 block 안에서만 유효하다. 그렇기 때문에 마지막 라인은 num 변수는 인식하지 못해 에러가 난다.&lt;/p&gt;
&lt;div data-language=&quot;bash&quot;&gt;
&lt;pre class=&quot;maxima&quot;&gt;&lt;code&gt;func main() {
	if num := 5; num == 0 {
		fmt.Println(&quot;False&quot;)
	} else if num &amp;lt; 10 {
		fmt.Println(&quot;True&quot;)
	} else {
		fmt.Println(&quot;Big number&quot;)
	}
	fmt.Println(num)
}

--- output ---
./main_05_for_function.go:17:14: undefined: num&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&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 문 밖에서 선언한 변수는 if 문 안과 밖 모두에서 사용할 수 있다. 하지만 if 문 안에서 같은 변수명을 재정의 하면 해당 변수 값은 오버라이드 된다.&lt;/p&gt;
&lt;div data-language=&quot;bash&quot;&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;func main() {
	num := 10
	if num &amp;gt; 0 {
		fmt.Println(&quot;outer num =&quot;, num)
		num := 0
		fmt.Println(&quot;inner num =&quot;, num)
	}
	fmt.Println(&quot;outer num =&quot;, num)
}

--- output ---
outer num = 10
inner num = 0
outer num = 10&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;For 문&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;for lloop 는 반복문이며 slice 나 map 타입에 대해서 range 를 사용하여 item 을 하나씩 가져온다. slice 를 range 로 가져오면 index, value 2개의 값으로 넘어온다. value 만을 사용하고 싶으면 index 부분은&lt;span&gt;&amp;nbsp;&lt;/span&gt;_&lt;span&gt;&amp;nbsp;&lt;/span&gt;로 처리하여 버릴 수 있다. 또한 index 1개의 값만 가져올 수 있다.&lt;/p&gt;
&lt;div data-language=&quot;bash&quot;&gt;
&lt;pre class=&quot;makefile&quot;&gt;&lt;code&gt;func main() {
	nums := []int{10, 20, 30, 40, 50}
	for i, v := range nums {
		fmt.Println(&quot;index =&quot;, i, &quot;,&quot;, &quot;value =&quot;, v)
	}
	for _, v := range nums {
		fmt.Println(&quot;value =&quot;, v)
	}
	for i := range nums {
		fmt.Println(&quot;index =&quot;, i)
	}
}

--- output ---
index = 0 , value = 10
index = 1 , value = 20
index = 2 , value = 30
index = 3 , value = 40
index = 4 , value = 50
value = 10
value = 20
value = 30
value = 40
value = 50
index = 0
index = 1
index = 2
index = 3
index = 4&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;map 도 slice 와 마찬가지로 range 로 가져올 수 있다. 이 때 return 되는 값은 key, value 이다.&lt;/p&gt;
&lt;div data-language=&quot;bash&quot;&gt;
&lt;pre class=&quot;makefile&quot;&gt;&lt;code&gt;func main() {
  m := map[string]int{
		&quot;a&quot;: 1,
		&quot;b&quot;: 2,
		&quot;c&quot;: 3,
	}
	for k, v := range m {
		fmt.Println(&quot;key =&quot;, k, &quot;,&quot;, &quot;value =&quot;, v)
	}
	for _, v := range m {
		fmt.Println(&quot;value =&quot;, v)
	}
	for k := range m {
		fmt.Println(&quot;key =&quot;, k)
	}
}

--- output ---
key = c , value = 3
key = a , value = 1
key = b , value = 2
value = 2
value = 3
value = 1
key = a
key = b
key = c&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;Switch&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;선택문은 switch 로 가능하다. 각 case 마다 break 문이 없어도 되며, case 에는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;,&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;로 여러 개의 값을 지정할 수 있다.&lt;/p&gt;
&lt;div data-language=&quot;bash&quot;&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;func main() {
  alpha := []string{&quot;a&quot;, &quot;ab&quot;, &quot;abc&quot;, &quot;abcd&quot;, &quot;abcde&quot;, &quot;abcdef&quot;, &quot;abedefg&quot;}
	for _, a := range alpha {
		switch l := len(a); l {
		case 1, 2:
			fmt.Println(a, &quot;length = 2 or 3&quot;)
		case 3:
			fmt.Println(a, &quot;length = 3&quot;)
		case 4, 5, 6:
			fmt.Println(a, &quot;length = 4, 5 or 6&quot;)
		default:
			fmt.Println(a, &quot;length &amp;gt; 6&quot;)
		}
	}
}

--- output ---
a length = 2 or 3
ab length = 2 or 3
abc length = 3
abcd length = 4, 5 or 6
abcde length = 4, 5 or 6
abcdef length = 4, 5 or 6
abedefg length &amp;gt; 6&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;Function&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수는&lt;span&gt;&amp;nbsp;&lt;/span&gt;func,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #66d9ef;&quot;&gt;function&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;name,&lt;span&gt;&amp;nbsp;&lt;/span&gt;parameter,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #66d9ef;&quot;&gt;return&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;value&lt;span&gt;&amp;nbsp;&lt;/span&gt;로 만들 수 있다. 아래 2개의 숫자를 받아서 나누는 div 함수는 아래와 같이 정의 할 수 있다. parameter 가 같은 타입이면 앞의 타입은 생략할 수 있다.&lt;/p&gt;
&lt;div data-language=&quot;bash&quot;&gt;
&lt;pre class=&quot;nimrod&quot;&gt;&lt;code&gt;func main() {
  result := div(4, 2)
	fmt.Println(result)
}

// func div(n int, d int) int { 는 n, d 파라미터의 타입이 같아 아래와 같이 바꿀 수 있음
func div(n, d int) int {
	if d == 0 {
		return 0
	}
	return n / d
}

--- output ---
2&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&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: #f8f8f2;&quot;&gt;,&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;로 구분하여 여러 개의 아규먼트를 넘길 수 있으며 이 때 받는 함수에서는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;...&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;를 활용하여 가변 파라미터로 받을 수 있다. 또한&lt;span&gt;&amp;nbsp;&lt;/span&gt;slice&lt;span style=&quot;color: #f8f8f2;&quot;&gt;...&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;와 같이 slice 를 가변인자로 보낼 수 있다.&lt;/p&gt;
&lt;div data-language=&quot;bash&quot;&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;func main() {
  fmt.Println(addTo(1))
	fmt.Println(addTo(1, 2))
	fmt.Println(addTo(1, 2, 3))
	i := []int{4, 5}
	fmt.Println(addTo(3, i...))   // slice를 가변인자로 보내기
	fmt.Println(addTo(6, []int{7, 8, 9}...))
}

// 가변인자 (variadic parameter)
func addTo(base int, vals ...int) []int {
	result := make([]int, 0, len(vals))
	for _, v := range vals {
		result = append(result, base+v)
	}
	return result
}

--- output ---
[]
[3]
[3 4]
[7 8]
[13 14 15]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Function 의 리턴 값을 여러 개로 할 수 있다. (multi return values)&lt;/p&gt;
&lt;div data-language=&quot;bash&quot;&gt;
&lt;pre class=&quot;go&quot;&gt;&lt;code&gt;func main() {
  result, remainder, err := multiReturnValues(10, 5)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(result, remainder)
}

// multiple retrun values
func multiReturnValues(n, d int) (int, int, error) {
	if d == 0 {
		return 0, 0, errors.New(&quot;cannot divid by zero&quot;)
	}
	return (n / d), (n % d), nil
}

--- output ---
2 0&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Function 은 변수에 담을 수 있다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;cal&lt;span&gt;&amp;nbsp;&lt;/span&gt;함수 내부에 보면 map 의 value 로 Function 타입을 선언하여 할당한 것을 볼 수 있다. Function 을 변수로 선언할 수 있고, 파라미터로 받을 수 있고 return value 로도 사용할 수 있다.&lt;/p&gt;
&lt;div data-language=&quot;bash&quot;&gt;
&lt;pre class=&quot;go&quot;&gt;&lt;code&gt;func main() {
  exp := []string{&quot;3&quot;, &quot;+&quot;, &quot;4&quot;}
	result, err := cal(exp)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(result)
}

func cal(exp []string) (int, error) {
	// Function Type
	type opFuncType func(int, int) int
	var opMap = map[string]opFuncType{
		&quot;+&quot;: add,
		&quot;-&quot;: sub,
	}

	a, err := strconv.Atoi(exp[0])
	if err != nil {
		fmt.Println(err)
		return 0, err
	}

	b, err := strconv.Atoi(exp[2])
	if err != nil {
		fmt.Println(err)
		return 0, err
	}

	op := exp[1]
	opFunc, ok := opMap[op]
	if !ok {
		fmt.Println(&quot;unsupported operator: &quot;, op)
		return 0, err
	}
	return opFunc(a, b), nil
}

func add(a, b int) int {
	return a + b
}

func sub(a, b int) int {
	return a - b
}

--- output ---
7&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;struct 와 마찬가지로 Function 도 anonymous 로 만들 수 있다.&lt;/p&gt;
&lt;div data-language=&quot;bash&quot;&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;func main() {
  for i := 0; i &amp;lt; 5; i++ {
		func(j int) {
			fmt.Println(j)
		}(i)
	}
}

--- output ---
0
1
2
3
4&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Function 안에는 Function 을 중첩해서 선언할 수 있는데 이 것을&lt;span&gt;&amp;nbsp;&lt;/span&gt;clousure&lt;span&gt;&amp;nbsp;&lt;/span&gt;(클로저)라 한다. 클로저는 앞에서 설명한 Function 을 파라미터와 리턴 값으로 사용할 수 있는 성질을 많이 이용한다.&lt;/p&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&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #e6db74;&quot;&gt;multiple&lt;/span&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ae81ff;&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;)&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;을 호출&lt;span&gt;&amp;nbsp;&lt;/span&gt;할 때 생성된 파라미터&lt;span&gt;&amp;nbsp;&lt;/span&gt;base 변수&lt;span&gt;&amp;nbsp;&lt;/span&gt;에는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ae81ff;&quot;&gt;2&lt;/span&gt;가 할당&lt;span&gt;&amp;nbsp;&lt;/span&gt;되고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #e6db74;&quot;&gt;funcA&lt;/span&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ae81ff;&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;)&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;을 호출&lt;span&gt;&amp;nbsp;&lt;/span&gt;할 때도 계속 값이 남아 있어&lt;span&gt;&amp;nbsp;&lt;/span&gt;base&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;*&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;factor&lt;span&gt;&amp;nbsp;&lt;/span&gt;의 값은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ae81ff;&quot;&gt;2&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;*&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ae81ff;&quot;&gt;3&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이 되어 6 이 출려된다.&lt;/p&gt;
&lt;div data-language=&quot;bash&quot;&gt;
&lt;pre class=&quot;go&quot;&gt;&lt;code&gt;func main() {
  funcA := multiple(2)
	fmt.Println(funcA(3))

	funcA = multiple(4)
	fmt.Println(funcA(5))
}

// high-ooder fuctnion
func multiple(base int) func(int) int {
	return func(factor int) int {
		return base * factor
	}
}

--- output ---
6
20&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&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&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;Call&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;by&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;Value&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이다. 아래과 같이 기본 타입이나 Struct 타입은 함수를 통해 넘겨받은 변수의 값을 변경하더라도 원래의 값은 변경되지 않는다. 즉, 아래와 같이 person 을 modify 함수를 통해 넘긴 다음, modify 함수에서 값을 수정해도 원래의 person 의 값은 수정되지 않는다.&lt;/p&gt;
&lt;div data-language=&quot;bash&quot;&gt;
&lt;pre class=&quot;go&quot;&gt;&lt;code&gt;func main() {
  i := 1
	s := &quot;Hello&quot;
	p := person{}
	modify(i, s, p)
	fmt.Println(i, s, p)
}

type person struct {
	name string
	age  int
}

// Call by Value (여기서 수정해도 원래 변수 값은 수정되지 않는다)
func modify(i int, s string, p person) {
	i = i + 1
	s = &quot;modified&quot;
	p.name = &quot;ask&quot;
	p.age = 100
}

--- output ---
1 Hello { 0}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 포인터로 넘기면 원래의 값도 수정할 수 있다. 포인터는 다음에 설명하기로 하고 여기서는 slice 와 map 이 포인터와 같이 작동한다고 이해하면 된다.&lt;/p&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&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #e6db74;&quot;&gt;modSlice&lt;/span&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;(&lt;/span&gt;s&lt;span style=&quot;color: #f8f8f2;&quot;&gt;)&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;에서의&lt;span&gt;&amp;nbsp;&lt;/span&gt;s 변수&lt;span&gt;&amp;nbsp;&lt;/span&gt;가 가리키는 주소와&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #e6db74;&quot;&gt;modSlice&lt;/span&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;(&lt;/span&gt;s&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;]&lt;/span&gt;int&lt;span style=&quot;color: #f8f8f2;&quot;&gt;)&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;함수에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;s 변수&lt;span&gt;&amp;nbsp;&lt;/span&gt;가 가리키는 주소는 동일하다. (마치 포인터 처럼 동작한다) 하지만&lt;span&gt;&amp;nbsp;&lt;/span&gt;s 변수&lt;span&gt;&amp;nbsp;&lt;/span&gt;의 경우 modSlice 함수 통해 넘기는데 처음 생성할 때&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #f92672;&quot;&gt;길이&lt;/span&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #ae81ff;&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;,&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #f92672;&quot;&gt;크기&lt;/span&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #ae81ff;&quot;&gt;2&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;로 생성했다. 즉, 길이와 크기가 같아 modSlice 함수에서 append 로 item 을 추가할 경우 크기를 늘린 새로운 slice 를 만들어서 리턴 된다.&lt;/p&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&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;=&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #e6db74;&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;(&lt;/span&gt;s&lt;span style=&quot;color: #f8f8f2;&quot;&gt;,&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ae81ff;&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;)&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;에서 s 가 가리키는 주소는 처음&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #e6db74;&quot;&gt;modSlice&lt;/span&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;(&lt;/span&gt;s&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;]&lt;/span&gt;int&lt;span style=&quot;color: #f8f8f2;&quot;&gt;)&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;일 때 가리키는 주소가 아니라 크기가 늘어나 새롭게 생성된 slice 를 가리키게 된다. 그래서 그 이전에 수정된 s 의 값은 변화가 있고, 그 이후에 수정된 s 의 값은 변화가 없다.&lt;/p&gt;
&lt;div data-language=&quot;bash&quot;&gt;
&lt;pre class=&quot;go&quot;&gt;&lt;code&gt;func main() {
  m := map[string]int{
		&quot;one&quot;: 1,
		&quot;two&quot;: 2,
	}
	modMap(m)
	fmt.Println(m)

	s := []int{1, 2}
	modSlice(s)
	fmt.Println(s)
}

// Call by Value but slice and map like pointer
func modMap(m map[string]int) {
	m[&quot;two&quot;] = 20
	m[&quot;three&quot;] = 3
	delete(m, &quot;one&quot;)
}

func modSlice(s []int) {
	s[0] = s[0] * 10
	s = append(s, 3)  // 길이 == 크기 이므로 새로운 크기의 slice 가 만들어져서 리턴된다
	s[1] = s[1] * 10
}

--- output ---
map[three:3 two:20]
[10 2]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>프로그래밍/Go</category>
      <category>Closure</category>
      <category>for</category>
      <category>function</category>
      <category>golang</category>
      <category>high-order function</category>
      <category>If</category>
      <category>Switch</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/303</guid>
      <comments>https://ahnseungkyu.com/303#entry303comment</comments>
      <pubDate>Tue, 2 Aug 2022 16:16:11 +0900</pubDate>
    </item>
    <item>
      <title>KServe 이 보다 더 쉬운 ML Model Serving 은 없다</title>
      <link>https://ahnseungkyu.com/302</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;MLOps 라고 불리는 s/w 가 여러개 있는데 그 중에서 Kubeflow 는 Kubernetes 기반의 MLOps 를 쉽게 구축할 수 있는 오픈 소스이다. 초창기 개발은 Google 이 주축이 되어 Arrikto 가 같이 참여하여 개발하는 형식이었는데 이제는 많은 글로벌 회사에서 같이 참여하여 점차 확대되고 있는 추세이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Kubeflow 는 Kubernetes 위에서만 돌아가기 때문에 Kubernetes 를 알아야 한다는 단점이 있지만, 일단 Kubernets 를 알고 있다면 설치가 아주 쉽다. 물론 그 안에 들어가는 컴포넌트들이 많고, MLOps 의 특성상 자동화는 workflow 를 잘 작성해서 pipeline 을 어떻게 구성하느냐가 중요하기 때문에 어려운 사용법을 익혀야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;KServe 는 Kubeflow 의 여러 기능 중에서 ML Model Serving 에 해당하는 컴포넌트이며, 얼마전 kubeflow 내의 KFServe 컴포넌트 이었다가 독립적인 Add-Ons 으로 빠져 나오면서 KServe 로 이름을 바꾸고 자체 github repository 를 만들었다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;KServe Architecture&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;KServe 아키텍처는 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;data:image/png;base64,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QIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQJDF1iW7HPy1D2ecNWXff2pP/p/3vJ/zeof989lwk+Uy2c0b35/XbE8lpWPXB/LynK5jTIBAgQIECBAgAABAgQOCWyU6PPgR3/LQaLPFfe+vPnvv+srm2/4qodL9jlEaYYAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIEahJYmuxz+vKve+DDn3jqM//2//zdWVsi0adM8CnL2dR1STzlurKcrzUlQIAAAQIECBAgQIDAIYF1iT75R8WJWaLP/fIXfSLR53uf+rgmppJ9DlmaIUCAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAIHKBJYm+1x2z6994HVfN0v2+e1M9lmW8BMtzfvsFsulwibblNsrEyBAgAABAgQIECAwYYGdE33CTLLPhM8cTSdAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgMBIBJYn+3zJ1zzg2q859Zl/d8f/PWtmJvrkNFseSTz5zGXLppJ9lqlYRoAAAQIECBAgQIDAJQKrEn0O/VHxoEd845UnT97jufHq/EWf3JNkn5QwJUCAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAIFaBZYl+5y6x72++v7XfNXpP/53b41kn0zoWZxu2uRD9+Vt+iLbESBAgAABAgQIECAwLYGjEn3mf1g86JHfvDLRJ7gk+0zrpNFaAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIjFFgebLPvb/q/td85alZss+dszaXST67EEj22UXNawgQIECAAAECBAhMSKCVRJ/wkuwzobNGUwkQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIDBSgRXJPl95/786S/b52EGyT7Q+k3YWp0fJ5PblPo56jfUECBAgQIAAAQIECExEoLVEn/CS7DORs0YzCRAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgMGKBpck+l997luxz4yzZ5235yz4hUCbtrBJZtk25rCyv2oflBAgQIECAAAECBAhMRGBZok/5R0OUTzzokd98v5Mn7/HcMIlknu996uNW8kj2WUljBQECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAhUIrA82ec+N175sMcvJvts0qLyvrzcvlxWlnO9KQECBAgQIECAAAECExRoPdEnDCX7TPBM0mQCBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAiMTGBZss/pyyX7jKybNYcAAQIECBAgQIDAoAQ6SfSJFkr2GVQ/qwwBAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQI7CCwOtnnK2a/7PP2Oy/ssvxFnrK8eMRl68plZXnxteYJECBAgAABAgQIEJiAwLpEn/yD4cRV//U3XHny1D2fGx6RwPO9T33cRjSSfTZishEBAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIDFhgebLPFY+/8mGXJPvEfXfnZs+8/25Zq5atK5eV5WWvt4wAAQIECBAgQIAAgRELbJTo86BHfNNOiT7hJtlnxGePphEgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQGAiAhsk+2SCTk7XySzbplxWltftxzoCBAgQIECAAAECBEYm0HmiT3hJ9hnZWaM5BAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQmKDAFsk+m+gsS+Ypl5XlTfZnGwIECBAgQIAAAQIERiCwSaLPydkv+tzv5Kl7PjfaG0k73/vUx23ddMk+W5N5AQECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgMTECyz8A6RHUIECBAgAABAgQIjExgk0SfE20k+oSbZJ+RnT2aQ4AAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgQkKSPaZYKdrMgECBAgQIECAAIGeBHpN9Ik2SfbpqWcdhgABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQ6E5Ds0xmtHRMgQIAAAQIECBCYtEDviT6hLdln0uecxhMgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQGAUApJ9RtGNGkGAAAECBAgQIEBgUAJ7SfQJAck+gzoPVIYAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIEdhCQ7LMDmpcQIECAAAECBAgQILBSYG+JPlEjyT4r+8UKAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIEKhEQLJPJR2lmgQIECBAgAABAgQqENhrok/4SPap4CxRRQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBBYKyDZZy2PlQQIECBAgAABAgQIbCiw90SfqKdknw17y2YECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgMFgByT6D7RoVI0CAAAECBAgQIFCNwCASfUJLsk8154yKEiBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgMAKAck+K2AsJkCAAAECBAgQIEBgI4HBJPpEbSX7bNRnNiJAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgACBAQtI9hlw56gaAQIECBAgQIAAgYELDCrRJ6wk+wz8jFE9AgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIEDhSQLLPkUQ2IECAAAECBAgQIEBgicDgEn2ijpJ9lvSURQQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBQlYBkn6q6S2UJECBAgAABAgQIDEJgkIk+ISPZZxDnh0oQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAwDEEJPscA89LCRAgQIAAAQIECExQYLCJPtEXkn0meEZqMgECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBEYmINlnZB2qOQQIECBAgAABAgQ6FBh0ok+0W7JPh71v1wQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECDQi4Bkn16YHYQAAQIECBAgQIBA9QKDT/QJYck+1Z9nGkCAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAIHJC0j2mfwpAIAAAQIECBAgQIDAkQJVJPpEKyT7HNmXNiBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgACBgQtI9hl4B6keAQIECBAgQIAAgT0LVJPoE06SffZ8tjg8AQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBxbQLLPsQntgAABAgQIECBAgMBoBapK9IlekOwz2nNRwwgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIDAZAck+k+lqDSVAgAABAgQIECCwlUB1iT7ROsk+W/WxjQkQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIEBggAKSfQbYKapEgAABAgQIECBAYM8CVSb6hJlknz2fOQ5PgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAscWkOxzbEI7IECAAAECBAgQIDAqgWoTfaIXJPuM6lzUGAIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECExSQLLPJLtdowkQIECAAAECBAgsFag60SdaJNlnab9aSIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIVCUj2qaizVJUAAQIECBAgQIBAhwLVJ/qEjWSfDs8QuyZAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgACBXgQk+/TC7CAECBAgQIAAAQIEBi0wikSfEJbsM+jzTOUIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAYAMByT4bINmEAAECBAgQIECAwIgFRpPoE30k2WfEZ6qmESBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAYCICkn0m0tGaSYAAAQIECBAgQGCJwKgSfaJ9kn2W9LJFBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIFCVgGSfqrpLZQkQIECAAAECBAi0JjC6RJ+QkezT2vlhRwQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECCwJwHJPnuCd1gCBAgQIECAAAECexQYZaJPeEr22eNZ5dAECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAg0IqAZJ9WGO2EAAECBAgQIECAQDUC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bHQA+uyZVKVYPSJeNtc6rNZff33fV8Ngagyj5ERABERABJoTMD2BGJOlMzTnlCakkOHOgQce2GjoQ794krOJJcyPp9lll138/0z+I999992OiTgff/zxJsn4fsCqNxgGFfo/XKjOVvBqq63m/vSnP2WySp61zXw7Ri6fyVwZ88HknfS/vP76637yMiYaM8c1Sz/CSSed5FfzsfC4b8c0Px6ftG+rDzIBLcx33nnnpGQKEwEREAEREAEREAEREAERqFECMvSp0ROvZrddAtbBRQ1NVmdX8ecri1nkFl98ccfsN7ncypERC0s5d+nSxXf6MBscnV758uQqKymcmfToSEpyNkNrPK61283gJAbhUG8G8zJzULHODHrihj4MFLIZaospkw+SzNBPxxydji3hmL1v+PDh7uijj/Yz+p1//vlu0qRJfjlvPoymcVmUkeY4SiMCItC+CJhuQK1NzlJPkLFP27seGIi97777+kGkDBTG0IUVaxioWozDKOb666/3M+6R/84770w09CmmzGLT8rGOlXYwONptt9384BoGQGNgk8Zh9MT7FSMfjIT46IWRcZKDG0bbrBC4xx57+Fn50NXILycCIiACtULAdAXaa7L0hvxnH+MKW9kX41BmdcXx/z/fKnS5St166619FP9l+V9qK8OxQg+GPhgAbbnllm7UqFHeqCPtSsC5jtcWwuMMS6kTfQpmdIuBjjkMYHADBgywoNQ+1z6TozDI18ox32YoTl3YDwnTroKYtlyuBa4RjI8YXIXegj5TzOzIWZSRtr5KJwIiIAKmX0DC5Cx1DRn7VP4aY/b8W265xR+IiT+Y+ALH++i8887zE1vdeOONbqeddvLvJB/ZRn6oLw6jafo78jkmTmGFXwYro2PQF1GuQzdk4hb6bJjp/+yzz3b0e8iJgAiIgAg0J2B6AjEmS2dozqlQiL2zc6Xj+wFbPsckJoUmMuFbP6vHsroOK/t9/PHHfqILDHx4n/LtvdCEJWn7/MO6/upXv3JscWfXTDw81/6zzz6bKypnOMfguz4bE3qyehGTp3Xs2NHrR3yPSWMojCEwWzGObx25xn4UU47SioAIiIAIiIAIiIAIiIAIVCeBbNYSrU42apUItBqBsGPLZHzbGLiIjM9GR4ptdDYgd+rUyXc8mH/kkUf6jzIMLOED2dVXX91q7au2A59xxhmeObPz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jRlIs8MOO7htttkmb9GsbMRHUByDxnBZlOEL0o8IiEDNEzDdABAmZ6knaGWftnOJMdO/DYxlNt1S3Ouvv944GOZnP/tZKUVkmmeVVVbx5X3wwQcFV6p86623fFr0CWapL9a19ioIxdZX6UVABESgEgRMV6Bsk2tFb+A/WK6JGlg5Z+VoQoe11lrL+yF7BoPizNg0jEsj898VwwzcGmuskTMLhqhm9EMiDE/4L8kKOH/729/8qkMYdGA4Eg4izVlggYjLLrvMGw4lJeP9fNdddzWLKpVhWBD/508//fQwqFFmZQEm97jtttvc+PHj3YgRI9zbb7/tmCUfx2oDrLYEU84H56xYZ6si2rkw38KLLS9f+mOPPbaZ8U2+9LniuAbZ6OPAwYTz8+c//9mv8sg1gkE0BmGdOnVKLCaLMhILVqAIiIAIxAiYfkGwyVnqGjL2iQH/YRejFVaqSeuYqMtWiTv++OPdgAED8malf59V5Ojjp58InaWU/+X5DlJMG5h8jBWGMAIeNmxYvmKbxR188MGONt96660uy285fCfgXW0rDTU7sAJEQAREQASaEDA9gUCTpTM0QaQdERABERABERABERABERABERABEfAEZOijC0EE2gEB6+Ciqiars6ttnTibOXXKlCltq2IVrk2udmP8wuy1GNjw0WzgwIF+EAoGO+HAE2YtZvASs/l/+umnfpb9q6++2vXo0aNZzceMGeNn23vuuef8h0UGK/PxLD7z7auvvuqNgF588UVfBrMer7TSSs3KKzWA2Q4feughP1iLj5ysGnTggQc2mWmYshmYxWyIDO6ZPXu2W2qppfzKBcRlUQblyImACIgABEw3COUs9QQZ+7T+dcbs7QcccICvyCabbNK4ykDamjEg9sYbb3SshMO7l1UKGNyS5DBkTTv7PIN1l1tuuaRiUoXZ+5n3JKsV2X5SZjP0WTka1Bte30lpFSYCIiACIpCbQK3qDRtssIE75phjcoPJEWOGIO+8806OFPmD33vvPW/MSiorK3+O+bEYtjJglI3BqKxS+8knn7hDDjnEr+aSpox8aRgcy3/qJJdrBvpSGYbHYCKOfO973vNDhw51Xbp08QY+DPpFfyEPg3lZkZB6cz4KTboRHtdkM+ixc2E+egj6EoZExbgNN9zQYbCMMdLee+9dTNaS0zK4efjw4e7oo492v/3tb935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7777bp+EMljZR04EREAERKA5AdMViDFZesMCTmuttZb797//7Q444AB3xx13OFbpYevTp483ImUAMu/XL774wmeC3e9//3u/JfXJYPzz/PPPu3/84x8OIx42joFh6zLLLOMwOHnllVf8Ma0WBx10kBs5cqTtVr2P8QoOTqx+BGNzGEptvvnm/nxg5IPMqj6bbrqpXyXwvffecxhJkQ8HW4yCchn8skLvxIkT3dFHH+2uvPJKb4jFMQjHUIhjP/fcc+7dd9/15XXp0sX3mR144IF+P+ln5WhFxaRzn5SWMIyIVlhhBX9NsAIRutLw4cO90RHtoy5du3Z1GD499thjzlY6wiCKa5I4HPoO11U5ZfiC9CMCIiACGRMw/YJiTc5S19C3jIxPmIoTAREQAREQgVYiYHoChzdZOkMrnQwdVgREQAREQAREQAREQAREQAREoNUJyNCn1U+BKiAC5RGwDi5KMVmdXeUxVW4REAEREAERqBYCphvQHpOz1BNk7NP+rpTVV1/dD0Rm8GhrutNOO81NmzbNLbroou6UU05JVZWzzjrL3X///X7g88033+x23333gvkYcH3qqaf6dEOGDPH3QcFMSiACIiACNUrAdAWab3J71xs6d+7sz6b55ZxaDCluu+02d9FFF7lLLrnEvf766+7999/3m5ULr6222sqddNJJ3kDVwuM+6W644QZ31FFHOVbc4/32xhtv+C2etl+/fn61lv333z8e1Wzf2ml+swQlBFhZ5pdQhLO85qcpA+MW3PTp0x1GuzvvvHOTbKyE9Oyzz/rVk4hnlZvHH3+8SRqMYPbee29vuMOKPvkcxjtXXHGFXyGIFZsw7Jk6dao3ELJ81H/w4MHuggsucOhUcRe27+uvv45H591nRSwc55vVCLnOqAe6zMMPP9wsLwbce+65p2//iiuu2CQ+izKaFKgdERABEciIgOkXFGcyvjlNXGYk5IuACIiACIhAbRMwPQEKJktnqO1rQq0XAREQAREQAREQAREQAREQgVolIEOfWj3zandVEbAOLhplsjq7quoUqzEiIAIiIAIiUDIB0w0owOQs9QQZ+5R8alolY+/evf1xbRb4lq7ErFmz/IDmCy+80B+aFQ2YoT6N22ijjdxee+3l/v73vzsGO3///fdu3333zZmV1RAOO+wwP0B28cUXdxgKyYmACIiACOQnYLoCqUxuz3rDVVdd5diycrBg1Re2t99+27FyzKeffuow0mAlHlaOWXrppVMfrn///n61OoxCMO7AcOizzz5zPXv2dMsvv7xf4YUVWtI6DF+ydlkwLKWMddZZp3EV61xtWnXVVd1NN93k4PfSSy+5jz/+2H355ZcOAx/0C1byC1cCylVOGL7ffvs5tsmTJ/tz/Mknn3hDpfXWW88b9+QrD4MbW3k7LLNYeYkllnAnnniiGzVqlG8T1wXXB2Uvt9xyfltppZVcp06dchadRRk5C1eECIiACJRBwPQLijA5S11DK/uUcXKUVQREQAREQATaEAHTE6iSydIZ2tAJUlVEQAREQAREQAREQAREQAREQARahIAMfVoEsw4iApUnYB1cHMlkdXZVnruOIAIiIAIiIALtgYDpBtTV5Cz1BBn7tIerYH4dGfiKmzJlyvyACv8yu74NXH755ZfdmDFj/ABmDvvjH//YjRw5sqgakP/NN9/0s+wzCJfVFDDmic9k/+qrr3ojoBdffNGXP27cOMeAWDkREAEREIHCBExXIKXJ0huac2NFl6RVXZqnLBzCCncYtrDJFU8AfltuuWXxGfPkQLeI6xd5klckivsOgyU2VukpxWVRRinHVR4REAERyEfA9AvSmIxvTiv7GAn5IiACIiACIlDbBExPgILJ0hlq+5pQ60VABERABERABERABERABESg1gjI0KfWzrjaW9UErIOLRpqszq6qPuVqnAiIgAiIgAikJmC6ARlMzlJPkLFP6lPRqgmXWmopf/znn3/ezZ07t9ks9yuvvLJjUFVah0FN6ML8zDr/1VdfhdFe7tq1qzf4OeSQQ5rFFQpgoOvEiRP9SgpXXnmlGz16tN8I79u3r2/Pc8895959911fVJcuXRwzOh944IGFila8CIiACIhAQMB0BYJMlt4QAJIoAiIgAiIgAiJQFgHTLyjE5Cx1Da3sU9bpUWYREAEREAERaDMETE+gQiZLZ2gzp0cVEQEREAEREAEREAEREAEREAERqDABGfpUGLCKF4GWJmAdXBzXZHV2tfRZ0PFEQAREQAREoG0SMN2A2pmcpZ4gY5/0571z584+sfnpcy5IaXnNXxCTW9p888195PTp093dd9/tdt55Zxfm//rrr3NnTojp2LFjwfw9evRw6623nlt//fW9v8suu7hlllkmobR0QRjvXHHFFW7gwIFu7NixfnWfqVOnultvvbWxANo0ePBgd8EFF6RebcE4mN9YmAQREAERqFECpivQfJOlN9ToxaBmi4AIiIAIiEAFCJh+QdEmZ6lryNinAidNRYqACIiACIhAKxAwPYFDmyydoRVOhA4pAiIgAiIgAiIgAiIgAiIgAiLQ4gRk6NPiyHVAEag8Aevg4kgmq7Or8tx1BBEQAREQARFoDwRMN6CuJmepJ8jYJ91VcNVVVzm2clwpZayzzjqOlXZCt+KKKzYLC+PTyPEy0+RJSmPXZFJcPGy//fZzbJMnT3Zvv/22++STT7zREUZFq6++erPViuL54/tDhw4tm0O8TO2LgAiIQHsnED6XTZbe0N7PquovAiIgAiIgAm2HgOkX1MjkLHUNGfu0nXOtmoiACIiACIhAOQRMT6AMk6UzlENUeUVABERABERABERABERABERABNoDARn6tIezpDqKQAkErIOLrCars6sEkMoiAiIgAiIgAlVIwHQDmmZylnqCjH2q8KJpw03CUIlNTgREQAREoDIETFegdJOlN1SGtUoVAREQAREQgVokYPoFbTc5S11Dxj61eFWpzSIgAiIgAtVIwPQE2maydIZqPNNqkwiIgAiIgAiIgAiIgAiIgAiIgBGQoY+RkC8CVUjAOrhomsnq7KrCE60miYAIiIAIiEAJBEw3IKvJWeoJMvYp4aQoiwiIgAiIgAi0UQKmK1A9k6U3tNGTpWqJgAiIgAiIQDskYPoFVTc5S11Dxj7t8KJQlUVABERABEQggYDpCUSZLJ0hAZSCREAEREAEREAEREAEREAEREAEqoKADH2q4jSqESKQm4B1cJHCZHV25ealGBEQAREQARGoJQKmG9Bmk7PUE2TsU0tXk9oqAiIgAiJQ7QRMV6CdJktvqPazrvaJgAiIgAiIQMsRMP2CI5qcpa4hY5+WO5c6kgiIgAiIgAhUkoDpCRzDZOkMlSSuskVABERABERABERABERABERABFqLgAx9Wou8jisCLUjAOrg4pMnq7GrBE6BDiYAIiIAIiEAbJmC6AVU0OUs9QcY+bfjkq2oiIAIiIAIiUCQB0xXIZrL0hiIhKrkIiIAIiIAIiEBOAqZfkMDkLHUNGfvkRK8IERABERABEWhXBExPoNImS2doV6dQlRUBERABERABERABERABERABEUhBQIY+KSApiQhUAwHr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8XtO9IgAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIERloghnLSrD3lslewJ7YtP8owwj1lDesECBAgQIAAgRER2FXQZ0TGbBgVAWGfCohNAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBwsAIp1NOrjOGfcr1Az8E+F85OgAABAgQIEDhWAgcS9Mnz3Ow+x+pp3rkzwj47G2lBgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgT2SSCFeVKZgj3l2XtSwKdal7b3qStOQ4AAAQIECBAgcJwEDiToc5wGqC+DCwj7DG6lJQECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQeACBFOwplzHAk7ZTmCeWaSmvx7rqdmqnJECAAAECBAgQGGKBAwn6FEXhzeOQviiEfYb0idNtAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIEBgOga17LON9lvEezlSmgE+5Lu7r9xiOseolAQIECBAgQIDArgV2FfQpOp34htEy4gLCPiP+BBseAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBy1QDXAE/uzXd1R99f1CRAgQIAAAQIEDklgV0Gf7fpUFEJA2/kM2z5hn2F7xvSXAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBIZIIH3xer9wTxxKmt0nrqf2cb289Ksvt7FOgAABAgQIECAwRALVoE96w5iG0H0D2Om0tn0jWGxNI5mO2XVZFH3fgO76XA7YPwFhn/2zdCYCBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIFARqAZ5yvdwVtcrh9okQIAAAQIECBAYVYFq0Gfgce423FNkxbZhoYEvrOGhCgj7HCq3ixEgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIDAyRAo31NZDfVU9yWRcn2sq26ndkoCBAgQIECAAIEhFthz0CeNuRr4qW6ndsrhFRD2Gd7nTs8JECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBA4FgLpJBPLNMMP6kudby8HdctBAgQIECAAAECIyywp6BPUXS6bxQ7nf6z9MTAT3qMsN+JGZqwz4l5qg2UAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBA5eIAV2Ulm9Yqwv7ytvl9erx9kmQIAAAQIECBAYcoE9BX36jbnYJvjT7xj1wyMg7DM8z5WeEiBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgMCxF0hBnlTGDldDPL22j/3AdJAAAQIECBAgQGDvAgMHfb7z63/z2XiZL/7aL35lp8vFmXx2amP/cAoI+wzn86bXBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIHDsBNK9linMk7ZTR1N93K7uS22UBAgQIECAAAECIyYwUNDnhS99/vU47mceuzg3YuM3nD0ICPvsAc0hBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECgt0BRqi6He0rVfVcFgPrS2EGAAAECBAgQGE6Bxjbd3tWbP7P4bCM5grti2KcoOveMLM/DS6ZWK7JOJ6/Va1mnHfbn9axWz+KHkPh6ulM2i1bYDi++btncqs9+9iMT81m2ln339dZ0PPE3fvB29xHXLQQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAYIQF4j126RGHWV1P9+HF+rikcmtr67+prhwcKu+3ToAAAQIECBAgMAQC2wV9hqD7uniUAocR9jnK8bk2AQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBA4YIEUzul3mbQ/lbGdIE8/LfUECBAgQIAAgREQ2C7ok9LfAw0zzObijeNAUqPV6DDDPv/i//h69ifff3u0AI2GAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBEZe4O0PFrcbYwrxxPswq/dupn3V492zWRWxTYAAAQIECBAYEYHtgj4jMkTDOGiBwwz7fOMHgj4H/Xw6PwECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgcnEBj/PRU6ewp3BOrUqgnhXjidnk9tknb1fW4bSFAgAABAgQIEBgBgQMJ+pjd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gAABAgQIECBAgAABAgQIECBA4KgEKvexpeDOdmX1xrfqdr+hxHbxvBYCBAgQIECAAIERENjNjD493wTGIE/Zobpd3medAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIEBgXwXuuY9zX8/sZAQIECBAgAABAocusFPQ5+6bv0/90j/5+7F3X/yNrz8Vy90GevLs3kBQPIeFAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIHBCBNI9malMw07bqazWp20lAQIECBAgQIDACRCoBn3im8TqG8Xs45/7wvWi1vjLL71+c+Zr337z4arLbkM/9x9//zWrbWwTmJ1ba0aF2YWtkggBAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIEDjuAjt8Ufp992yG8ZTryuvHfaj6R4AAAQIECBAgsA8C1aDPtqfMa7W+bxjzvP++bU9qJ4EBBWYX1rtBn7nFrXLAwzQjQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQLHTSDej1m+JzNtp7q0nfqd6tO2kgABAgQIECBAYEQFdhX0GVEDwxoSgdtLG43Y1VQOSbd1kwABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQI7BTUqe5P27FM6xQJECBAgAABAgROgEA3OLHf48zz3JvK/UY94ef7zHNXFuJjeWVt87PPXV0+4RyGT4AAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQLDJ1C9tzKFeFJ9dbs8wrSvXGedAAECBAgQIEBgBAXM6DOCT6ohESBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAsdSIAV2eoV7ynWx89W2gwwonWOQttoQIECAAAECBAgcQ4EDCfoURZEfw7HqEgECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIEDg0AT+xW++8Gi82Ef/k1/766WL9grwpIBOuSyvx8PL2+X10qmtEiBAgAABAgQIDLtAY9gHoP8ECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgeMmcGturTm/tNnIs6kzjbGpc9v0L4V2YpO4nh69Dim3re7fbl+1rW0CBAgQIECAAIFjKrCrGX2KTqfvTD1F0X/fMR27bhEgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIEDlMghXFSmKdalvuS9pXrrBMgQIAAAQIECIy4QDXoE4M894V5Op3WfXVll6Iott1fbttrvSjuv2avduoIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAkMukMI+1WGk+l4Bn7SveoxtAgQIECBAgACBEROoBn2qw+sb4NltuKfIHiwMVO2YbQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIDAkAsI8Az5E6j7BAgQIECAAIH9Ftgp6LPj9aqBn+r2jifQgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBwMgX6fiH7yeQwagIECBAgQIAAgT0FfYqi031j2elsP0tPDP0I/niRESBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgR2FNgu9LPdvh1PrAEBAgQIECBAgMDwCOwp6NNveEUp+CPg009JPQECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIHCCBWJopxzcKa9HlvL+6r4TzGboBAgQIECAAIGTITBw0Gd96e2/GEn+wd/6ha/vRCPks5OQ/QQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgMAJFCgHd6qBnvK+SFPdPoFchkyAAAECBAgQOHkCjUGG/MKXPv96aFd75p//7blGo7na6bQHDggNcn5tCBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIjLFAO7cT19IhD7rVerSu3S/uKO8fGMi6xPi5pe2vLfwkQIECAAAECBIZKYLvATnrDN9CAzOIzEJNGexS4ObfWjIfOzq93yz2exmEECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQOAoBar3ZqbtWKZH7F+qP8q+ujYBAgQIECBAgMARCGwX9DmC7rgkgd4CtxbWu7NP3VrcGOvdQi0BAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIEBgKgXKgJ3Y4hXp6lalt2jcUA9RJAgQIECBAgACBvQtsF/TZ1dSNeZ7vqv3eu+xIAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgMDQCVTDOuUQT9pXrosDTPXV9aEbvA4TIECAAAECBAgMJrBd0GewM2hFgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECCwW4FyiCcdW65L66lMbZQECBAgQIAAAQIjLHAgQR+z+4zwK+aIhjY7t9aMl769sNEtj6gbLkuAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAYSuDAzsfmrv/Lcq+PZ0tL3fuvv/KPKQSm8Uy7Temya1qtl5TQ2CRAgQIAAAQIERk1gX4M+eS0vEpCwT5JQ7pfAzTthn1vzW6Gf/Tqv8xAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgUMQ6BfaSfWpC9XtVK8kQIAAAQIECBA4AQJ7Cvrkea0b6KmVgj29rGLYR+Cnl4y6vQjcWlhvxONmFza75V7O4RgCBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIHBMBaoBn+p2v24P2q7f8eoJECBAgAABAgSOkcBugj53Z+sp978a5Klul9taJ0CAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECgt8BOQZ8U7ik+9Uv/5O/HU3zxN77+VCx3G+jJszydKx5uIUCAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAicRIF+91NW66vb/awGbdfvePUECBAgQIAAAQLHSKAa9Ilv9u57w/fxz33hsaLW+MsvvX5z5mvffvPhav93G/q5//j7r1ltY5vA7NxaMyrMLmyVRAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAwBAJ3Hd/Zuh7r/s2e7UbomHqKgECBAgQIECAwIMIVIM+254rr9X6vnnM8/77tj2pnQQGFJhdWO8GfeYWt8oBD9OMAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgcmUCe5b3uvawGfNJ2attr+8jG4MIECBAgQIAAAQKHJ7CroM/hdcuVCNwvcHtpoxFrU3l/CzUECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQOBYCqQAT7/OVfen7RT46XecegIECBAgQIAAgRET6AYn9ntMed4zfb7fl3G+EyTwmeeuLMTH8sra5mefu7p8goZuqAQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECAwGgIpvJNGk0I8qb66ndrFMu0r11knQIAAAQIECBAYQQEz+ozgk2pIBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAwLEUSIGdXuGecl3sfLXtsRyQThEgQIAAAQIECOyvwIEEfYqiyPe3m85GgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIEBgugX/1+z++Gnv89C/8vb80YM+rYZ/qYWl/qq9up3olAQIECBAgQIDAkAocSNBnSC10mwABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECCwLwK35taab7y7fGotmzozcebKk6WTVmfqSduxSVpPZaqrlnF/dSkfU91nmwABAgQIECBAYEgEdhX0KTqdvjP1FEX/fUNioZsECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgYMUSAGdFMqpbpevndqU66wTIECAAAECBAiMuECjMr6+QZ5KO5sECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQK7F0jhnnRkr+1qXWqrJECAAAECBAgQGHGBnWb06QZ/Op3WfQGgoiju1pXX+3kV2Yftq22KIrt7ruo+2wQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgACBEyCwXbhnu30ngMYQCRAgQIAAAQInR2CnoM+OEtWQT3V7xxNoQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIBAtqegT1F07sz003+Wnmgr9OMVRoAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAYSKB7b2afltvt63OIagIECBAgQIAAgWEU2FPQp99Ai86HwZ8U8kllv2PUEyBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgROkEAM7ZSDO+X1yFDeX913gpgMlQABAgQIECBwMgUGDvqsL739FyPRP/hbv/D1naiEe3YSsp8AAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBA4gQLl4E410NNv3wlkMmQCBAgQIECAwMkVaAwy9Be+9PnXQ7vaM//8b881Gs3VTqc9cEBokPNrQ4AAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAYYYFeIZ5UF8t+65Gkui+1L+7si2VcUru0vVXrvwQIECBAgAABAkMlsF1gJ73hG2hAZvEZiEmjPQrcnFtrxkNn59e75R5P4zACBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIHCUAtV7M9N2LNMj9i/VH2VfXZsAAQIECBAgQOAIBLYL+hxBd1ySQG+BWwvr3dmnbi1ujPVuoZYAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECAyFQDnQEzucQj29ytQ27RuKAeokAQIECBAgQIDA3gW2C/rsaurGPM931X7vXXYkAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQGDoBKphnXKIJ+0r18UBpvrq+tANXocJECBAgAABAgQGE9gu6DPYGbQiQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBDYrUA5xJOOLdel9Vim9dROSYAAAQIECBAgMKICBxL0MbvPiL5ajnBYs3NrzXj52wsb3fIIu+LSBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIEBgIIFf/ZXnXi2KIv/eb/2df1Q5IAV3ymVaj03Teiorh9skQIAAAQIECBAYVYF9DfrktbwYVSjjOnqBm3fCPrfmt0I/R98jPSBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAr0FLsxMbMY9E/ny4p0WKbSTynTgTtupnZIAAQIECBAgQOAECOwp6JPntW6gp7ZNsCfO6pMeJ8DREA9B4NbCeiNeZnZhs1sewiVdggABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIHJbAXgM/1eMOq7+uQ4AAAQIECBAgcAACuwn69JytJ4Z5yv2qbpf3WSdAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAoLfAwEGf537pH/9KPMVvf/mFh2O520BPnt0bCIrnsBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIETpjAPV+wXhp7tb66XWp6z+qg7e45yAYBAgQIECBAgMDxFKgGfeKbvfIbvu76xz/3hetZbfzzL71+c+a3v/zDp6pD2W3o5/7j77lmdbdtAl2B2bm1ZlyZXdgqsRAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgSESKN+fmbpdvW8z1vdql9orCRAgQIAAAQIERlygGvTZ83DzvOaN5Z71HDiIwOzCejfoM7e4VQ5yjDYECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQOAoBfIs73V/ZTXgk7ZT217bRzkM1yZAgAABAgQIEDgkgV0FffKaMM8hPS8u00Pg9tJGI1anskcTVQQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBA4DgKpABPv75V96ftFPjpd5x6AgQIECBAgACBERPoBif2e0x53jN9vt+Xcb4TJPDM9enVzzx3ZeHNd+azzz53dfkEDd1QCRAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQGA0BFJ4J40mhXhSfXU7tYtl2leus06AAAECBAgQIDCCArua0WcEx29IQyJwcWZiM3b1/PR4txySbusmAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAoC6TATq9wT7kuHlNtWz6PdQIECBAgQIAAgREVOJCgT1EU+Yh6GRYBAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAYCCBf/X7P74aGz79C3/vL1UOSKGeSnU33BPrdtqfjuvXLu1XEiBAgAABAgQIDJnAgQR9hsxAdwkQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAEC+ypwa26t+ca7y6fWsqkzE2euPFk6eQrnlMvqetwu18XDy9tpvXTa7v5e9eU21gkQIECAAAECBI65wK6CPkWn03emnqLov++YG+geAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQOAwBFIQJ5bpEa9bXk/96FWX9ikJECBAgAABAgRGVKBRGVffIE+l3T2bRVHs6bh7TmKDAAECBAgQIECAAAECBAgQILCNwMpmu7bezvI8/BZislHrjNXz+MetE7m0Wu2uQ71eP7EGJ/KJN2gCBAgQIECAAAECBAgQIECAAAECBAgQGBWB6u/3e233qhuV8RsHAQIECBAgQIDANgLVoE+1aTfA0+m08nplz27DPUXWPwxUFJmgUMXXJgECBAgQIECAAAECBAgQILAl0NrczP/Pl5anv/LG6tn5zaxeC79FeGiqvvGfPTM199lrU8snyenWwvr4m0v1s7dX2uONWq24Op0vP3KhtjCZZZ2T5GCsBAgQIECAAAECBAgQIECAAAECBAgQIEBgSAWq4Z04jHJdeX1Ih6jbBAgQIECAAAECDyqwU9Bnx/NXAz/V7R1PoAEBAgQIECBAgAABAgQIECBAoIdAu1Pk33l3aeKL31m+/NZSZywL3xSS/tY1u9ZpfP/W7clfeGxj/r9+dnL2ytnx1ih+i0j4PUv4616e3wwBn9cWx2beXRw7U282s06nk+XhO1XmZ7PJl2c3zz82nc9dP7u5cGqs0a6FANAoWvR4iagiQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECIycwJ6CPkXR6d4v0gk33GwnIvSznY59BAgQIECAAAECBAgQIECAQFkg5njeX9ls/Ph2a/zVuY3xGwsbY28ttMdur3Xq5ZBP95jYOM+z//dGK8z0c/Psn71+auHx6cb6U+fG15+YaW5MNWtDOcNNO6R61jeL+sJ6MbYUHxtZc62VNdZbzcZaO2vktazotNvh9zEhABR+LRN+RxPmUM5rry6MXXhlLjt/qlhZu3h6bO3xC82F6Ylso+xrnQABAgQIECBAgAABAgQIECBAgAABAgQIEDhygV73XJbryuvVzm63r9rWNgECBAgQIECAwBAL7Cno02+8RSn4k0I+qex3jHoCBAgQIECAAAECBAgQIEDg5ArEvM7yZqe2sN6uz6626z8OAZ8f3Nw4FWapmbi12m5uKxMPbq1nmyHy84evr559+XR94+1L7dWbK+Orj5xubE6fqrdPN/PO5BCEfpY3isZGu6ivtfL68mbRnFstJhbW84mw3Wh1stq9DinDFMYflsCQt1vdTE++nE+dWlnKTr2xnM3MjBVrz15o3bx0ur62sJ6NNWt5Z7yRteu1fOvAe09qiwABAgQIECBAgAABAgQIECBAgAABAgQIEDg8gWpop9d2te7weudKBAgQIECAAAECRyowcNCns77010NP/+O/8V/99Pd36rFwz05C9hMgQIAAAQIECBAgQIAAAQJRIEzKk727tNn8D2+tTP7xW6tn3lnpNFudPN/t7xY6YXqbG4ut8beW2mN/9ObqmSfO5OufeXRq8dMPnVo97kGfGMJ56/bm1K217NTyRmN8o5OH39eE2Xr28hIJqZ+t4/J8frNx6o/fqT86Xmtvzoy3Vy9O5SsPn85Was16O7pbCBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgSMRSL+lj2V6xI6U11PHetWlfUoCBAgQIECAAIERFRgo6PPClz7/ehj/m8/8k7/6c41Gc7bTaVe+SXZEdQyLAAECBAgQIECAAAECBAgQ2HeBdruT31xt1V+b3xx74YPWxGvzGxPvrbSa82udRtiVx9DOXi7aDbiEY9dbWe31xWJ8/pWV+vdubkw+c6659tGLY2sPn2luTo/HkMueTr+XLm17zAe3V8dfXR4/d3O5NjXWaLQ2w4w+YbLk/ZluJwR+Ou1WN0kVZgVq3i5q+dJmNv7uUn7mzERnfWY8Xz891tmcbGSbzXpe1Gq1PeWKth2gnQQIECBAgAABAgQIECBAgAABAgQIECBAgEBZoPwHirieHrFNr/VqXbld2lf9/X6sj0u1fqvWfwkQIECAAAECBIZCYLugT3rDN9BAdvtNuwOdVCMCdwRuzq01L85MbM7OrzcvX2hyIUCAAAECBAgQIECAAIEhE2i3i3y1G/DpNG7MbzRfnd8Yf3OhNXZjoT1+e63dWGsVd5ImD/Z3p3h0K4R9Fjez+lKrVZ9bbzfeW2433wjXun62sfH4ubH1q1ON1vlT9dZ4CLgcdOin3enk7U4tH2uE3E0Y/wfLnYm3b69P3W5PTq1n58ayopO1s41sZTMf2/ob3j4/sSHwE5f1dt5Yb2eN5c1sbCUEfxbXsvHJZt6aaBQbU2N5a7JRtE41stZYM2vXQ9bomGSh9hnD6QgQIECAAAECBAgQIECAAAECBAgQIECAwLEQ6HdvZgrvpP2p3KnTsd2D/YFlpyvYT4AAAQIECBAgcKgC2wV9DrUjLkZgO4FbC+uNGPS5tbgxdvlCuAPKQoAAAQIECBAgQIAAAQJDJfDucqvx3tJm48XbmxNff2dt6q2l1vjqZnGgMwbHjMviRlFf3NisvzLXmrhwqrb55LnNtecuja88c765HsI+7dNj9c6pZq0z6F/KdoPeKbJ8Zb1orLTajfdX8qn3l/KplVajmedjeRECPkWxupvT7UvbYJKvbISwT3jEkFN4FGea+dr0eLE+M1GsnZkoNiabtRCCyjq12v5MLrQvHXcSAgQIECBAgAABAgQIECBAgAABAgQIECAwWgLxTxPpzxPV9TjS6r5ym9GSMBoCBAgQIECAAIH7BLYL+sSEd3qzeN+B1Yp4Y0i1zjYBAgQIECBAgAABAgQIECBA4JXb62P/+oXF8z++vTGx1spq62F2n1Zn8N857I9gkc2vdxrfe3996kc3NyZnJmqtT14eW/mPrk0u/cSlibX9ucaHZ+mEWYXCBD75y3O1c7dWssn1YqzZ6bRDuGfr8WHLo1vrTvYTgj9LG9n4Sisbe285P92o553rZ9tz16fzxfFa3e96ju7pcWUCBAgQIECAAAECBAgQIECAAAECBAgQGE2B6j2ZKcBTrq/WVfeNpoxRESBAgAABAgQI3BXYLuhzt5EVAgQIECBAgAABAgQIECBAgMBuBV58d378N15aP/ftm5tTE428s7Re1FshALPb8+xX+1ZnK2C0lhVZDBttvrs+9dZCe+zR6bX1X356fG7m9Kn2fl1rdTOvv7PQnppbzSdWW3mjKI7n5LQxydMuilr7zsg3w0RDs2u1U6fHss2HmtnKfnns9jwz01Pjk+NhXqEdlqWV9c2FpeXNHZptu7ter+VXLsyc2rZRZefaxmZ7dm5xvVLd3Ry075utdueD2fl9CZmdnzkzPjHW3NFrdn5pfW19Y99e573GPwx102emxqZOjW/7e9GV9fX23Pxyz+d4GMaoj8dfYNB/K/bj37njr9G/h35e+9vYQ4AAAQIECBAgQIAA7ixPJAAAQABJREFUAQIECIyMQPnvJmk9lXGQaT2VIzNwAyFAgAABAgQIEOgvsO0ftPsftv0es/ts72Pv7gVm59aa2fXp1dsLG81w9PG8O2r3w3IEAQIECBAgQIAAAQIERlLglVvrY1/87sKl788Wk3nRybJOka21itpxGWwMt4SgT+2dpfbYB8ud5o/nNia+9PLS+T93fWr+r3zyzK2ZU40HCkK0Q6BoeSNrvr2Qn1kLIZ/wN7jwx7fhmBwnPFVhhp98/OZqMXlxKlur10IK6Ahmcf7pTz5zdWJibGyn18zs3NLKv//6D97aqV2//WFs2c986pmHLp6fnurXplf9yur6xh989TuvdwJYdRm07+G44v/7+g/evD239MBhko88+cj5i+fPnq72pbr9ze++/Pbb780uV+tP2vYTj16ZvvbwxZntxl2E5ff/6E9f2VgP8TcLgQMQGPTfigf9d+4Aun6op/TzeqjcLkaAAAECBAgQIECAAAECBAgckMCv/spzr/6Lf/mN/Hu/9Xf+UeUS1fBO3C7XpfVqWTmNTQIECBAgQIAAgVET2NegT17Li8yfvkftNXJsxnMzhn3Ccmt+rXlheuKBvq332AxKRwgQIECAAAECBAgQIDDEAjHiEIIO4ZcBWdYIvxP4kxtLk3/wxsqZb763eXq1U6vlnfhLgvuDEMdpyHGGocWNrB6zOF9+c236ex+sTf7ZaxMLf+GJ8cVHzk7u6bPnequoL2wUY3Mb9VN5GH/8v2FaVjbz5uxqcWp+rRg7M55vhnlPHij4tJexh98xpT9abnt4aDZQu14niUc+/9wzV3cb8lldW9/86jd++FavkE+8zqB9j00/9bEnLv/h1777ZjFcL5FenCNXF15aeT08mSM3MAM6NgKD/lvxIP/OHZvBHnBH/LweMLDTEyBAgAABAgQIECBAgAABAg8kcGFm6z63iXx58c6J0u8dUxmr43p5O9XF0kKAAAECBAgQIHACBfYU9Mnz8HWuRTsPt+wU3Xt2esCFP64V6REaV9+E9jhCFQECBAgQIECAAAECBAgQIDBMAhvtTv7uYqv59XdWJ79yY+3MawvFRFbcyYSkclgGFJMWoc8frObN33xp9cJv/mjpwp+7vjb/Vz4xfevc6Xo77h4kUhJ+B5LdXMlPvbuYh9lVhi3is/Vkxd/jrG1mjZdnOzMfu1SbHW/khx70OYyXzU9+4qnLVy7NnNnNtdbWNza/9o0f3ghhn9ZujuvX9vTUqYmnHnt45uXX3p7r10Z9ll26MH3q2kMXt32uWq1O54WX3rjVarfFprxoCByhgJ/XI8R3aQIECBAgQIAAAQIECBAgQGBUBKr3Wla3+40ztvP70X466gkQIECAAAECQyawm6BPzzeBMcxTHnN1u7zPOoEHEbi1sN59vc4ubDbM6PMgko4lQIAAAQIECBAgQIDA3gU22kW+sN6q31jYbL6x0Bp7ba41/uO5zfHXFzsh5BNm8Bn2qUm6/Q+/6qjVsz94e2P6m++9d/rPX5+Yf3xmfP3a2cbmtbPNMMNNrdNrno84u9HSeqcxu1KbWNrIxveufPRHbnay+uxqNjm3WiyP1/P2RPPwZ/U5SIXnPvbExUeuXJjezTViyOerX//hjeXV/Qn5pGs/88TDF95699bSfoWH0nlHqTxz+tTYI1d3fr7ev3V75b0P5lZGaezGQmDYBPy8Dtszpr8ECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQLHUWDgoM9zv/SPfyUO4Le//MLD/8Wf++g7MdCzm5l68iy0z8zscxxfBPpEgAABAgQIECBAgAABAgQGFRir58W33lk99a9/tHzhg+VOc2S/HC6GltqdbKGd1X/r5ZXzebaSfeLyxPLfen76/avNWth5/xJnPi7am9mNxfHpTpEN+g1795/oGNSEzFKYqrlR/9Fs68Jj57LFY9ClfevCx5559Pz1Ry6d280J19c3N7/2zRjyWduXmXzK167Xa7XnPvbYpT/+1ovvlOutEyBAgAABAgQIECBAgAABAgQIECBAgMCJFLjni9eDQHW7H8qg7fodr54AAQIECBAgQOAYCdQqfYlv9spv+LrrH//cF65ntfHPv/T6zZnf/vIPn6ockz3oLD55fs81q6e3TaArMDu3Fm4gy7LZha0SCwECBAgQIECAAAECBAgcnsDK2mbtT24sTv6Pf/TBQ//sW0tXP1irNcMvBEIHhjrPMjBgEWb4+e6t9tTf/v33H/uX35q9+OLNtfF2u33P4MMXomQ/nB+7WGuM31M/8EWOWcOi085a2XjzxmI+dcy6tufuPPPEIzNPPfbQhd2cIEzks/nVEPJZWt7/kE/qx6ULM6cfvnJ+ZJzTuJQECBAgQIAAAQIECBAgQIAAAQIECBAgcJ9Auj8zlbFBXC9vp7pYWggQIECAAAECBE6gwMAz+kSbvFarvpm8S5bncV/PL7S928YKgQcRmF1Yb05O1Ntzi+vdwM+DnMuxBAgQIECAAAECBAgQIDC4wJdeXDz76y8sXFjczOrt7kw14VcAYbabE7WE0EsYdLYefjvyuy+vnPu9V1Zmrk831v/qc+c++OTl8bVo8YP3ivPvLzdOF531kaFpbW5mL98szl+dzFYaYTanYR7YE9evnH32qUcu7WYMYSaf1le/+cJbBxnySf35+Eceu/T+rfmVViv8lFkIECBAgAABAgQIECBAgAABAgQIECBAYKQE8qzn79irvw+O2+W6tF4tR8rGYAgQIECAAAECBO4X2FXQ5/7D1RAgQIAAAQIECBAgQIAAAQKjKDC/ull/+dba+K+/tHbuhZvrk1kt/gohhHvi36HSn5NGceA7jikMPsxk1Cpq+SsL2cT/8JWb1/7TJ87e/rlHG8tvLY6d3fHwIWyw1GpMvLa4efbpmXx+CLvf7fK1hy+dDkGay7vpf5jJJ4R8ujP5bO7muL22HR9vNj/29KMXvvvD127u9RyOG0xgbmF57ezZyW5Ab7sjiqJzov+1287GPgKHJeDn9bCkXYcAAQIECBAgQIAAAQIECBA4JIFev3Ms16X1VMZupfVUHlJXXYYAAQIECBAgQOAoBQ4k6JPnPdPnRzlO1x5ygWeuT69enJlYePOd+ezyhdPLQz4c3SdAgAABAgQIECBAgMCxFWh1Ovn//v3Fc3/w6tLZ+Y2s0Y6plvC/rNM6tn0+9I4V8W9pYYaf8L+N8EuQ33h5/vxrC6fPPX91IvxCJM78M0pLkRVhvC+8l1+6dqa2OlHvbAzb6B6+fH7yUx97/Grod3ghD7ZshJDP17ohn9VDCfmkXl1/5NLMjbdvLtxeWBo65zSGYShfu/HeYnwMQ1/1kcBJF/DzetJfAcZPgAABAgQIECBAgAABAgRGUqAa2Inb6ZEGnLZT21TG/eX11F5JgAABAgQIECAwYgIHEvQZMSPDOQYCIeTTvbHm/PR4LJvHoEu6QIAAAQIECBAgQIAAgZERiEGO95c3Gv/2xVtnfu+t2sz8Rh5+X1AP4wuhlSLM4mPpKxDtLp1qZs9dmd4KRHVDQH2bD+WOotPJ8lo9/+47m+d++pHaeyHbNDTjuHRh+tRPfuKph0KfB+50yPiEkM+LNxaXDjfkE1FjPz/5scev/Ls//t6bQ4OsowQIECBAgAABAgQIECBAgAABAgQIECCwF4EU5onHVtdTXSrTfiGfKGIhQIAAAQIECJwAgdoJGKMhEiBAgAABAgQIECBAgAABAn0EljZbtf/1m3MX/+6/vXX9X7+SX5xf7zSyIsze04khH38v6sPWrY468Rcrn3lkJhur5d2Zb7ZrP7z7wqw+4fXwwUr99M2F2viwjOP8zJnx5597+uFaLR/491+bIeTz1W/88K2FpeVDncmnbHr2zOTEk49dnS7XWSdAgAABAgQIECBAgAABAgQIECBAgACB4RX4v79240Ls/ROf+Rt/4c4o+v0BJtanR2zar92d09wtBm139wArBAgQIECAAAECx1vgQGb0Cd9mO/C3pB5vHr0jQIAAAQIECBAgQIAAAQKjJxD/2vPe3Erjy68tnvmd19rnVtp5vRvq6QZ7/C1oN8/45clmd0afzgkIRXWyWu17tzpXfv506816vXGsXyjTZ6bGfuYnP/JIo14fPOTTaoeZfH741uLSysZuXgMH0fbZJ69deOe920ura+shcXe8llMT4/WJiWZjYmyscerUWH18rNkYazbr7XanCDmpdnxsbLQ6m612e25heWN9fePYjeF4iR5Ob05PTTTPnp4cm5gYq4fnKzxnjXonTNe1trbZXl3faK2vrbfmFlfWw9N3rH+2D0drtK4yPtaoT56aaEyMN+tj4YkPP7v18bAeR7m+vtleCz+wq2sb7bDeWllda4Wf3RM9lV8e0qEXz50dPzXebAav8G9co95oNGrtdqsTflTa6xvBLFjdur2wFv/dG61Xi9EQIECAAAECBAgQIECAAAECByFwa26t+e2XZs/OZFNnpi4/9elwjd+7c534u4X0iFW91qt15XblfbE+LbHeQoAAAQIECBAgMOQCuwr6hL/99g3wFEX/fUNupPsECBAgQIAAAQIECBAgQGBkBG4sbjZ/96XF6S+/sTq91mnWsng7b+E+/L08wdNj9ezTV89mm+E+3/F631+Z7OXUd7+iL541/kWuevaYK8pDZcoXhVxFFiYVyuqhH7W44wCW8LufbDUbG391ITv79Lls/gAusS+njIGGn/2pjzwScgzdG9kHOWmYyaf9x9/80Vvzi0cf8on9Dfmk+ieefezSn3z7xXcH6f9BtzkTAiKPXbt05qHL58/GYM8urlcshPDI+7fmlt/7YG759vzS+k7HPv/Jp680GvcGtEK4qLnTcXF/MLv8+LUr912j3el0vv7tl95L5wgzJp29dH56Km33KsMhna9/5+X3whca3d39Z37qI1fz7k/e3aqeKz/68Y1bMeTUc2efykeuXjx97aELZ/rs7laHEE7n2y+8+kEst2uX9s2cnRp75OqFM1cunZuaPDW+42xcIbTQ+eDW/NKb79xcfP/m7ZXS0NMplUMiEP79q117+OLph69cPHNueupU6PZA/48hPOfFrdvzK+E1MP/Ou7PLO4VYj/PP626eqvhvTvi348zF82emwmxwp2ph2en4YNOZm1ta/WB2fuX1tz9Y2FjfHOjncqfz2k+AAAECBAgQIECAAAECBAicGIEPf/HYO+BThii3LddbJ0CAAAECBAgQGGGBXn+YH+iPfiNsYmgECBAgQIAAAQIECBAgQGBkBML94PnbIdxT66wVv/NqMfPlN5bPbnTCDazxz0LFru5DHxmT/RjIZKOWXZocy86ONbNmTNjs0xImSMmunjuV/eST5+7elb0SJkT50x/PZreXN7PxcN3rl6eyRy9NZhfOjGenwqQMMdxTD3144Y357E9eupXNrWyGuXdCHGGf+pROEwMPnVYre/12MXPtdLY00cyPXUIsBEIaP/fpjz4SZ61I/d6p7IZ8vvXijbnF3QUzdjrvg+6/cmkmBjQW3vvg9sqDnmsvx4ecVH792qWz1x66eDbMBDOxl3OEY/KzZyYn4uPpxx++sBamwnjhxTc/eOu9W8v9znfxwvRkCCkM/PyVzxMDQb1CQSEYc89r9ezU5PilC9Ony8f2Wp8YH7tZnlVpPEztMX16MoYmtl2Wllc3QtDn1raNKjuvP3Jx+sK5s5OV6ns2w89g8d0XX/8ga90znHvaxI2pMHvLx5559OLVy+fiGAf+pyAEzGrhmLPxEca98e3vv/bezdvza/dd4BhWhJ+VyZ/8+JNXQvrxvvF2wtRFv/+Vb712DLu97106d/b02DNPPnw+/BxNhdDnjmGVagdCTjS/GEJw8fGJZx9vvf3u7OJLr96YDTPY9AyxHOef1+rYem2HgE/+5PWrM09cv3puN+HQeK7oe/5cCAaFx1OPP3ThjRvvz7306ju3w6xmPa16XV8dAQIECBAgQIAAAQIECBAgcOIFun+pKSlUAz3l/dV9pcOsEiBAgAABAgQIjKLATn807/5htNNp5dWvQA1/V777R9Pyej+k8GWAd9tX24T7RPruq7a1TYAAAQIECBAgQIAAAQIECGwvECZlyFdbRf7Bcrvx6vzm2Euz6xO/9+OVc51muD893h9uBp/tAXfYG3M90+ON7JHTE1kzTDyynzPojIUgz4UzY9lzj89k4f7jrBNuF15eb2VzYSKUy2vt7MLZ8eyjj05nl0I5OV7PJsYaIeSTZeMh8POpJ85l/+VnHs1+90/eyv6fb73Tne1nvyf3ibP6LG/mYz+e68x8/FK+qyDDDqwPvDtkMOqfef7ZR0I4Y6DZX+IFw0Q+7f8QQz4LS8cy9faJZ69fvjk7/3qYaeVQ/4gbZ/D5mU89c3WQWWB288TF5+anPvnUww9dOb/wje++FGbL2c3RR982zHCyNP30zkGfOIPO9198Y+Cfj2ajUYuziOw0wtm5MOVUn8BFOvbZp66de/rxh87newh5pHPEMgSmxn7u+WevvR7CCz946Y1bh/0aLPdlkPUwa81Ev4BY6PuJ+N1znKnqo08/emkvAZ9extEzzOR1LsxyM/nvv/HDt9bXQ+p0hJaL585M/NQnn35ol7OU9RQIwcjak489dP76I5env/ODV999+/3ZIwlo9uycSgIECBAgQIAAAQIECBAgQGAYBbb7zel2+4ZxrPpMgAABAgQIECDQR6Aa9HngP3oOEvrp0xfVBAgQIECAAAECBAgQIECAwAMIxJvmlzfbtVsr7cZbixvNl2fb49+5uTb59mJrrPv18purD3B2hyaBU416dvHUWHZ1ajxr7HOSJs7EcyoEeK7MTISgz9ZkDKvh3uqPPzYTQj9FdnXmVPbE1f4TkcQZgX4xhH1iOOjffff9rZl9Hvi3PWnkISMWv60lTBLxyu3auUdObS7OnG4ei4BMuCG99pnnf+LhyVMTYx/2dvu1OMvLf/jWj966fUxDPrH3cXaajz517fxuQiPbj3rnvZcuzEz8zKeefqQWlp1b761FnDHm0598OvvGd15+b29nOJqj3nr31uJHn752MVx925+qGJA6HXInS8trm4P09OqVc5MhmLPtOeN53n5vdqnf+fLwj8fzn3jqcrTt12YP9flj1y6fC8Gv8a9+84dvF/EfIcuxFHji+pXpn3jm+uWD6NzU5MT4Z5//6LWvfuOHN8JETyMR9nn82uWzP/GRxy6HH5sdf+52YxpmCKp/+rmnHz79ylu3Xnzlrdu7OVZbAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAmWBPf3BPnx7690/gG0X7NluX7kT1gkQIECAAAECBAgQIECAAIEHF9joFPkrt9bGf/NHCzNf/Pbi5d95een8q7dbE2F2n+pEvQ9+sRN6hniX+9WpseyRMxPZVAjVxNl99nOJtxxXZzmZaNay5586n/3sRy5mj16a2vFy9dCpv/znn8x+4vp01qmebMejd24QZm3O6vWx/IXbjRh4OPIl3Fed/+zzH304BCsmBu1MyPi0//hPQ8hnPkyVdETLwtLK2iCXfvzRK+emz0wOHGAa5Jz92sRwyqc/8eTDBxnySdd+6PL5s48+cql/ai01PEbl6tp6+/b88kCJyYcvX9j5h/XO2K5enNnRIWRsin5Bnxjy+ezzH3t4n0M+d+XPz5ye/DOfevrq/kYi7p7eygMKnD93ZvxjT1+/9ICn2fbwEPYZ++xPf+xaCB8O/fuJpx9/eOYTH338yn6HfEqA/z97dxrkSJreh/0FkLiBAgp1X13V933MPbM3lxsSZYsrm9zV4bAZwTC5NoNiOGyF9UFhRtARdjAY1CeHg7TJ/SCRkkiuNkRpSS5nTZHca86dnumevs/qug/c9w34eRKV3aisBDJRBVTh+OcMOq83M9/3h6OAzPfJx3TmxMwoZWTrir+RdfXCJAQgAAEIQAACEIAABCAAAQhAAAK9I9DsykOzdb3TQtQUAhCAAAQgAAEIQEBXYF+BPspe6QLzri+O1bp5JchHGSvbYAwBCEAAAhCAAAQgAAEIQAACEIBA+wWyxYo5mC5Jby9mfXeCBVcyX7EU6Xd6uVo1dSDWo/0N6IE98o3/JQqiGXfZhc8uNU/psc/28HOl7kzPiT44uw+vS2aL4uZiVHz/1pZ4+/q6ePdeUKyEMnuOxvv4B2/OCqtl16mbPeX2tYAqUi4XRSRjcm4lS8597aNNG5ktJtPr185M+b1uw/Wg81mVD288XIvGji7Ih5t/98FSsFyu6GbH4Ewvl88d70imDvXTcO3SqQkrpUdSL+/U/Kn5qUCn9t2p/a5vhRpm1ak/5piB4B0uT8EGYjTgc9VvqzUdiSUyxWJJTs6mXn/l/MLYsM+tuw/1dq3MU6YnD70OOxpM0kp9UPaFwJnjMyMdDFp5fiDKVGW7cHqup4NXxkZ8zrMnZw6lDQtzk8Oz070VzPj8ycYEBCAAAQhAAAIQgAAEIAABCEAAAoclwCfw60/i109zHerXq9cdVh1xHAhAAAIQgAAEIACBIxKQjB63kk/9MpX9mW98/dU7etsguEdPCOshAAEIQAACEIAABCAAAQhAAALtFUgXy+ZHkZx9MV60h3NViZI/4KJPe4nlIB8PZfHxOyThoMCbTgxykA+nDVINFJwiNmNZ8WgtKe6txkU0VaBsPULYKdvPHAX6/Nxbc8Im7a7TVMApfJR9KJIs7AkeUu2+5dlqpSIqlPblblAam/CK5ZZ30KYNhjwuw1l8lEMWisVy7Agz+Sj1yOaKpUeL6+Fzp2Z1g3j8Prfz+LGJocXlrYSyfbvHYwGfw+91GQ2Yqm4Fo6mN7SjlJcoXOQDFKklmr8dpn54IeEaGhzjoRPcziLKE2Ie8bmsimS4q7aHzijyp8S7Q31+D7UQylW1b5qb1zXDqwuljYxyApdRZa+wfohRT9AYlHs3gHGUbCjxwWSxm3eAqsk4q29SPF2bHvXNTo776ZUamybmq1wb1fo7NjPlWNoKJow6SU9drkOfdToc0GpDfb7oMqXQ2t7oRToRjiRy9Z8sc1EexO9L4mN89OTrskSg9mt5OKGuUl7L6hCm7VYnLdvv7tb49nI3o5UsnKTNV8/du/TY701XKAlchHv4j2/R9r9728tn5iUQik0+kXnzGqctgHgIQgAAEIAABCEAAAhCAAAQgAIGBFag/z8DTynz9tIKjrFPmMYYABCAAAQhAAAIQGAABQ4E+9/7815fIYuX0//WLb0qSNVKplHf3HBkAKDQRAhCAAAQgAAEIQAACEIAABCDQzQLRXMXyMFxwZEtVM4J82v9McdSBlTJvjOwE+Vho+rAGej5FiQJr7i7Hxbv3g2I1lH0euMNZhh5vJMXJCbd47czuJAWS2Sw8TkmEkxzjYHp+lbBt9aZ6JQtV+4vrj23bc0d35LDbrBfPzI/euv8s1NEDGdj542fr8enJwJCRgKUzJ2ZHKcgknS+UdLMAGTj0niIUSDS8Z6HGAg4QePf6/dVkKlNQr47Ekvml1e3EqYVpn5EAJt7e7bTtCvT5/37w8aJ6vyfmJ30UXKMbEPWTmw/Xt4KxvSmu1Ds8wDz7U6BLJjDsdTfbDb01TZNjAfez1S3NAB1lWy6jTDcaUzBFZY2ee/V6Dq46T0FH6uVa8xUaltdC8WgilYvFUjmK+SjtBGfZZqdGvRzEQ9vpfbCZLp1bGPvR+7dXtY6BZYcvMD7uNxRUR++L5PVPH23y35O6oRQVIr++FUnTayH4xktnZziosG79nkkOkpmbHvU8fLoW45Xd/n6tb8Dp49MBCm4ydD2Egmur9J6LL61tJeIUqMMBTRwf5PO4bHMz40OzUyM+ivvRvUbCZc6dmhmlLHIb9XXBNAQgAAEIQAACEIAABCAAAQhAAAIDLVB/Do6nlQejaE2rl9WXU9btOumzsx8up17OyzBAAAIQgAAEIAABCPSIgO7FKKPt4JtAGi2LchBoVSAUy1l5m0g8L49b3R7lIQABCEAAAhCAAAQgAAEI9LtAIl+xPImVHPlytW2/9fvdrNX2lamjb7pUETzu1CDvWnWGhZflCxWxHcvtyc4jBwGVq+I2BQGpB8494LTuJGjoUJUdFiFndVAfu9vn52fH/eOj/qYd2g+rDbfuPdum51j3GaLkG5bL547vjuZqYyV9Xreh7Eg37j7d1Aryqa8KBzAFw7FU/bJG0w6HrefO9axthQ21bWLM52nUbmX5+KhPN9AnFElkSqXynsxAp45P+Y1kA8rlCoV3P7q3cvvBs9DaRogTu8jv22KpVKHgrNyn9xaDH3z8YLVQKOq+nynQwTkzOarbLqV9GHdWwEUZeYwc4dnKVkwV5LNrM3otVN//5P5aPq//GhjyuijAs7cGzuYzOz06ZKTW5FT55Pbj9Zt3nwZj8bQc5MPbcbBPLJku3Lq/GPrJjQdrlOTHUNAl/a1x+72UXg8DBCAAAQhAAAIQgAAEIAABCEAAAhDYLaC6EvB8pRK8o6xXxs8LNJgwWq7B5lgMAQhAAAIQgAAEINBtAs06/+DLX7c9W6gPBCAAAQhAAAIQgAAEIAABCEBAQ4A6gJso0Me8mS7bimXdjAwae8AiPQE+SVKuVEWqUKbsOhSVoRuWobdH7fWUMGDPvvlY3EG7SP38CxRopB6483EyW1QvlrMPUBDAnuXtW2ASXrvgdEG9OJiunj8+abNKnQQy5BKNp/Ir60E5O4beBpPjw0OdCFDizC52u1U3YCBLASNGM+ZE45msXnt4vdUi9dw5yPXNSIozfui1b2R4yEXvwYbtG/Z77JRgSjfQaWMrsiewSJIsZg5Y06tDJpvP/+CD2yuxRHpPBqb6bYOReO7Og+Xt+mWNpuemR7yN1mH54QpQhjLd963RGtF3iWqIIln0ynvdzp4L9Dm1MDVMGfB0P+8589X1Tx+vb2xHm2YGC0WTOQ6MogRnRoJ9TKdOTAf0XLEeAhCAAAQgAAEIQAACEIAABCAAgYEU4HOHyvlD9TSDqNfVlxlIMDQaAhCAAAQgAAEIDJJAs4tbuher66FMJlNL5eu3xTQE9ATCibx80TqcLODuh3pYWA8BCEAAAhCAAAQgAAEIDJxArlwxJXJFS7JQtVAwinLhZ+AcOt1gSpwjMhRJVaQJA33891UdiiGSA3TqN+bgH76e1zisoNm6+j21d5qSHnCgT9PggfYesb1748CWaxdPjLd3r/vb271HK+F8obg3Wktjd5fOzo+bzI2DRzQ20V1kt0s7qZ+aF6XsL4aCd3gv2VxeNztM86N179paJpyEbkCEmYbxEb+rUUumxwO62XwooKiyvr030Gd2csRNSZ50n7f7j1fCxaJGhKBGpShTUToYju8JKlIXpQAmdzcEyanrNYjzFEjW7Pz+c5JL5xbGvR6nblDZymowsbwWjDV7PF7aiDzfcY9MUICkoSxU9x6vhLaCUUOfc9FYKn/r3uKWEYKxgM9NgUZGiqIMBCAAAQhAAAIQgAAEIAABCEAAAoMhoD5RwPPKQxFQ5pWyypjX108r5TGGAAQgAAEIQAACEOgzgbbd8a/PXNAcCEAAAhCAAAQgAAEIQAACEIBAzwjEc2VLPFexVAX39zVyc/meaVpXVbSWVacqCpWKKFPUjaUD19Jq4Ru776VSC/CpUgBQY47GQUCNtznIGrrhi5x6yOOo5ARJ9OpAnb+9lBUls7S6nTjKNlDgSPXuo+XgSxdPTuvVw+W0286dnBmm4KC2dbZPpXPFv/rhx0+FTsKLconSShkcxkd8ukEsBnfVlcU4q89owKcbPDA5Meze2I5oBgWNjegHH4Si8TRnWlEjjI34GgYQKWUTqUxufUv72EoZ9fjZ6lac9t20XfT+N81MjXgWl7eO9H2jrvsgzucLJUN/9N0uu/0Lb1yaX90MJ548W4/ye17Li15vOX5orevVZR63U3I6bLpBTuVypbK6Hm7pNc3v7Xy+WNLLiMYBWRQg5+DMWb3qiHpDAAIQgAAEIAABCEAAAhCAAAQg0FGB+rP/yrQy5gMr08q4o5XBziEAAQhAAAIQgAAEukPA0B3/Wq0qsvu0KobyegKRWE6+GBtNFHQvyurtC+shAAEIQAACEIAABCAAAQj0m0C6ZDJHC1W6mceevuD91tQjbw/HtxQo1oEDfToxUAwRDbuv1dUCfExNswg1CwLqRD056oiyE1S8kqnns7ZcOH1szON2HPn5hrWNcDoU0c+mws/niWOTw0ayc7Ty3HPAQD5faPoolfcGnKiPEfB7Ha9fOzM1NREYUq/rp3nOssPZdvTaxJk8tMrQa06ih11rXf0yCtTRzLBDzrqBPqFwPFO/LyPT2+FElgMe9Mr6fR6HXhms77xANpvXDNjROjIHaM1Njfq+9NaVha98/trCS5dOjh+bHvO6nY6+vhnY+Kh+UBx7bYWiKQ661LJrtIy/CqxvGQsOGh0d0n3PNjoOlkMAAhCAAAQgAAEIQAACEIAABCDQ+wK/9LNnVqvVqmnxnd/5fVVrdl8Q0M7sw5so5ZSxajeYhQAEIAABCEAAAhDoN4G2XsQzmU1VoXsZuN8I0Z7DEgjtBPuE4znriM9h+CL2YdUPx4EABCAAAQhAAAIQgAAEIHBUAlHK6BPNVyyiQ8EnR9Wubjwu9ZMWeQr0KVaqwtmNFTykOpko84vZVKq6nBL9Pu/tk0GcaeGly6cmfvzBHb7QekiC2oe5dW8p+IU3L7m4TtolakvpdWi+cu74+Dsf3V1rVq6T6zi4zOWgYBWP0zrkdtpcFLTiH3LbOWqgk8ftln1zlh0KzEpzVqhmdbJZJWl02OsIRZO7MnlMjgWaZs3hfXLAzeZWdE82IMpQYrXSfpsdl9dNjgc8Q16XTa+cer3e64/LUx1a3q/6OI3mJYvFxG1stF5rud1ma5hajD+3/UOeluqby+dLuXyx6z/c1jZDqTMnZ0bJpKUOHg67zTozOeLjB3sWKMIlnkjlorF0lgJeMvFkpqDl3IvLvB6Xoc+k1Q1jATtqgxXKAnT82GRAvVw97/O4dAP71NtgHgIQgAAEIAABCEAAAhCAAAQgAIH+EBjx1/q5OUzpZDr0JEqtUs7lKGNuKE/XzyvLeIwBAhCAAAQgAAEIQGAABXQvCGuZUF8C6vdQNpkpsKfR/R3pAqrcM4LHHI2utR8sgwAEIAABCEAAAhCAAAQgAAEIQODgAiMeU/lGSFCn8aMNUjh4S3pgD0S8nMiJ1yd9okDBPu0etuM54aT+6pLlRZyHxWwSbodFhJMFUaJjqk+ycMBFo/gULmvi/9QbHbDiVUpkYjNXy9ZKviLMLfXHP+CR9Td//Gw9nMsVi5fOzU/ql66VoA7YznOnZwP3Hq5EjG7TiXLpbK70ZGkjfObEzJje/of9Htf87Lh3aXU7qVf2oOs5e1DA53X4htwOCuSxORw2q8Nulei8X5tfWQet6eFuv7YZSekF+nCNJicCbnWgz8SoXzPTT30LQpFEWiuLktPeOKilfnsXFeRH/bJ2TXucjo7sl+vnH3LZ33zl/Fy76krnsM2fe/3CfCv729yOJj/69NFmK9scRdl0Nl9aWQ/F56ZH/Qc5PgekjY34PfygwCGRLxSLoWgiQ5nGktuhWPYg+z7qbemjqmEQWH3dkqnsvm4slUxneDv+QtD089BqsxqqR32dMA0BCEAAAhCAAAQgAAEIQAACEIDAwAqozzOo5xvBcLn2X7hodDQshwAEIAABCEAAAhDoqEArgT6aXwKVgB6llvXzPI0gH0UG44MKhBN5+fUaSRQlZPQ5qCa2hwAEIAABCEAAAhCAAAT6SeCd5YK77ZEc/QTUzrbQZbJEvtSRIB+uJgfscGDO3sFE62gln53RWn3I1+44o4/LVi5IklXzfNHe+h/OEg6Suf94VQ7WmRz3e0cDPt1gCqVmJ+amAsFgLKMOyFDWH9b40eJ6bHpiZMhDGXL0jnnu1NzoxlZkT8YXve2MrKfsPLaT81PDY6M+N2VYQQd1DbTNYCRdLi9U9DLgjI/4OHtPWNkFBVWY/T63blKw9e2wZhCXjXag7OuoxtRmCwV7mXsh681+jKh9mp+0+9lXp7e5efdpkGJZLJPjw02zS7VSD0r4Y52ZoIw/9IjGUtmHi2vhYDjekwE/FMNk5POrms8XSq0YKWX5b3OxWCrrZdmyG6uHsluMIQABCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEBlzgxe1haxANO2dc+uq//AIX+fDWSoDH9QE9PK83UCeVhvvW2xbrIQABCEAAAhCAAAQgAAEIQAACENAW4A6md7azLlEqaBfA0rYKcM/vYrkqUoVyW/er7KxZfhQ6F6MU0xg3W6dR/ICLONDHazPtK/vBAQ/dcPOnSxuRe49eZOS5effZVonSoTTcQLWCeE1XL56YpE7hh4upqge/pz+9v7hNi3XPpVHnfuniuYVR1S4ONDs24nN+5pXz0597/eL81ERgCEE+jTnL5Uo1GImnGpeorXFR9hvOiqSUo4AMN72fm77O6KVb2dyKZpRt6sd2u6HAhfpNOjTdvA0dOih2qyFw/dbjze1wTDMwTKN4S4soe5jzjZfOzr5+7cyUuQefcptN//1CgTqVCgfT7nOgDEi6f2soEMhIwNE+a4DNIAABCEAAAhCAAAQgAAEIQAACEOgzAfWJCvV8o+YaLddoeyyHAAQgAAEIQAACEOgiAXWgj7pq8pe/i1/9zWNmm+ubj5ZC/t/79x9dVBdqNehn7/b6HRfU22B+8AQisZzcISKSqI0HTwAthgAEIAABCEAAAhCAAAQgsFcgnK1IW5mqVU4Fs3c1lnRAoEynMcK5wQ6sMpkp0MdRyXeAd1+7XFzejNx9tPI8YwrvJJvLlynwJ9jKDp2UouTK+YXxVrbpRNlINJlb3QjHjex7hoJxhn0e3ewwRvY1PRFwv37t7Exg2Gs4E5KR/fZzmbWNsG6gD7d/aizAWX3kYXJsWNc3HEmkyhR6oGxTPzabuiPbjE6sUn2VMd1hAQ4Q/PCTh5sffPJglT4/OpLla3zU73n5yqmJDjel7bs3098rvYGS7egXarITChLSfK/Wb6IX3FdfFtMQgAAEIAABCEAAAhCAAAQgAAEI9L2Aci5BGXODebp+XlnGYwwQgAAEIAABCEAAAgMocKALWPVedCdX9RfN+tWYhsCBBSKJvBzoE0vWxgfeIXYAAQhAAAIQgAAEIAABCECgDwSCqbyUyJelvdd/+qBxXdoE7twezhZF03Qc+6x7867CzU69NFu3z8o02ozaz32a7eVkV0Q7PVvZitx5uLwryEep+tLadjJkIOOKUp7HnMVmdnr0eVBG/brDnL7zYClcKJZKBo5psljMB84UQcE99muU0Yie3gO9tCkRTSUcTaQ5+MpA3Xu+yFYomqbsO7rZPMYpiw83loLkTCPDQ7qBPmubjQOICkX97CGHBHug18oh1XGgDhMMx7PvXr+3/s5Hd5eX14KxdKa9UakUpDZ0uc1ZxDr9BHG2Hr1jNP/bq7e1EDYD2Xro41z3c0L/SCgBAQhAAAIQgAAEIAABCEAAAhCAQC8L0KlXrRP56mU8X79MmVaPe5kCdYcABCAAAQhAAAIQMCBAHYH2DPylUPMiLV2IVr4w7tkICyAAAQhAAAIQgAAEIAABCEAAAhA4fIGnwYytaqI+/lX0Hz0sfT5pEskVBefaoKCItg61/Wmdfml4umbn+G2uSJNW8ZEqpXzV57QVmxQ7lFWpdDZ3mwJimh3s5t1n219485KT+mEbDoa5dGZ+PBxJ5igrkJFAm2aH3/c66hReufd4JXj1/PGpfe/E4IZup1167eqZacp80cpNgarJdLaQSmXzKQomoEeRpgvJVKZA2S3EWMDnOH5sMmCwCj1bjJPubIXiKcqs5GvWCL/X5bDbbZaAz22nwKymzhQsVd4IxjKN9pcvGAsY4P1Q0FXD/TTav5Hl2VyhlMsf3fvDSB0HuUw0lsrTI8gGlKlMmhj1uUYCQ07/kMfpdNjkmynt12d+dnx4cWUrTp+/R/43wEgbjATGUfydiRK6mXP5om5QkNYx7Tar7t8XCtzc1761jodlEIAABCAAAQhAAAIQgAAEIAABCPS0QKMLAEqjlPXKmJcr08pYKYsxBCAAAQhAAAIQgEAfC2gF+hy4uXRnW3ypPLAidlAvcPqYL0vz2Ww2X7RIUlfcMbi+fpiGAAQgAAEIQAACEIAABCBwFALryZL1Zrjk8lkrpXhedOQ3/lG0qxeOycEuYUqUMOywCksbo33GfQ6RLZQFddAXFAwgU3AgQSZfFiNem5AsJlHmCKO6gTMRNKoCl6zyNcAq3SuwLbFAtBPakdsqCk6X68g7LVMszG6MOhdlkoJ1yvceLgevXDg+qSzTG0sUFPTypZMTlBVjTa9sJ9evrAVTc1Oj6YDfq5sB5iD1oIAcHwVCGfoMoQCP4tPljcjqRjjVNFNGe15wB2nWoW27vhnSDfShypimxobdPp/boVex7VAsXeU3foPBSOACb7q4shm7/3h1IDIrNaDCYhLggMVnq9sJfjCI02m3UFYp51hgyDU+4nNbrZKh93495rHp0aG7j1aaBlnWlz/KaUqAZSgSmiLxJAr0afm8s91Gf5lNpqbBe9x++rw8ssDRo/THsSEAAQhAAAIQgAAEIAABCEAAAhDQFFCf++N55aFsoMwrZZUxr6+fVspjDAEIQAACEIAABCDQZwItX8Trs/ajOT0iMOp3yHeITNtEUZIOdNPJHmkxqgkBCEAAAhCAAAQgAAEIQKC5AF/FKVOERzAnrPlyVbeDafO9YW2rAoVyVaQoIMdvp9+obQmgqdWAM6EU6Kb/CUqUIHGgDz3RHNiTocQZxVLr1+7aHmsht9UkRhwVuiFHGxve6hPQYvnl9WByaiLgGRvxeYxuOuz3uM4cnxl+uLgWNbpNJ8p9em8x+IU3Lzsp4UTH3udk4zVS91Akkf7wkwfr/DrVG6ySWTfDhd4+emX9diieKZbKJb1gqcnxYTclVNEN9FnfiiSbtT2VppRitYv5Td+EXrfL1mw/3bounswUPrzxcLWV+lFA3BC9joe0tqHXa+Wjm4/WtdY1WlYoFA0FhzTavpuX042UyqvZYGp1PZjienL2rVkK3JmZHGG/pq8ppV0et7NnXltpunGUUu9m48lxvyeWSLUcGDc1PmIoEDNzhBnimrUb6yAAAQhAAAIQgAAEIAABCEAAAhA4UgE+0aqcbFVPc8XU6+rLHGnFcXAIQAACEIAABCAAgc4LdCTQp1ql28RigAAEIAABCEAAAhCAAAQgAAEIQKBjApTxxZQrls3xQkUqlTmcQ7ne07FDYsd1Ahx8k6ZAn1rAQ/tOg9A5FZGiPvwroYyQzLX98rE4y0+mUBJa8RX87KeyJfF4PSnkBDf0UuBlPJ2m5fLQpirybqqVsvA5zPlee83dvLu4/cU3Lzkpe4XhAJRTx6dHtiOxTCyepvYezcBBHU+XNyOn5qdGO1EDG0Xk2G1W3buqFCgbxfVPH28YCfLhetodNsPO7WtXm17oLVaI37db29EUBUv4m206GhjSDTQrlcrlrWA002w/nEkpmcrmvTpBQx63w95sP926joKmKpTViLN7Gx4Cfo+zUeEqfRa2ur9G++qm5UMet9U/5GoaOJbMZAvRWKrp51cwEs/xY3ltO36VMp+5nA7dIJ72vL8P5/0aCicypxamRvSeu5nJ0aH9ZMCamxnTDDBTH4/roV6GeQhAAAIQgAAEIAABCEAAAhCAAAQGR+Dt91fl8xPH3/rGVxbf+73vUcsbXdRRgnmU9cpYD8toOb39YD0EIAABCEAAAhCAQJcIdCTQp0vahmpAAAIQgAAEIAABCEAAAhCAAAT6ViBdrJq3M1WJYj9MlNnncHrL9q1m6w3LVyoiW660vqHOFhzQ82w7Lb7zwZqcVkEO4aLLc5y9KZoqUKDP3mt1lOlFLAXT4rf/9C7tnV4KXEZ+RZjk8ry+fYNJWMzVikvKF4TQ7QvevsO2YU+5fKF89/HK9tXzx6eM7s5MeC9fOjn5g/dvL1Nw3V58ozs6YLmHT1aj0+PDQ0Y64Ld6KLvdZuj8YCyeylKsj2GD8YDPUJaLVuvbrLzNJnUs61Gz4/K6ta2wbqCP3j54/VY4njISTBWOJjJ6gT5ul8M2MTbs0gscUteLMl85L5+bH1cvV+b5I+bOw+XtfgyeUdrYC+PREa/zwuljE83qSn8zKt/92+tPqxX9z69wNJm/92g1+MqVUzPN9snr6K/Kgf+wHNb7NRxL5Ch+riJZOE1e44Him6zjo35nK6/rIa/b6vO6GgaZ1R2tuh2JI9CnDgSTEIAABCAAAQhAAAIQgAAEIACBQRIIx3LWm48iQ37h9rrHT75MbedAHx74fKvyqJ+vn1avb7SOlysDb4MBAhCAAAQgAAEIQKDHBbQubjW8SEcXBBuvqzZe1+NGqD4EIAABCEAAAhCAAAQgAAEIQKDrBGL5imUjWbRWRNWEKzaH//TIWXZK5bYfuFSmjD6UhWeZAnc4eIeDfni8Shl+0jnK6KNxRCWOhzvfcyAQl1GmNYofbBGdGZJMouK2W3dSBR1sd4e99cpaMEWduFOtHJeDay6fXehINh2j9eA++rfuL20bLd9KOYfdpnV+cM8u8gXjL3hJspgpe41rz046vMBJqYk6fIiGuw+G49k8pT1qWMDgivXNkKHX51Yonjayy8tn58csFLFmpCyXoVgI08Uzx0b5dd/owQFEWkGHRo+Bcu0R4GxfensymUzmUb/XcGanEGX20dsnr8/nD/5aP6z3K79WI9GkoSAbCpwa5SxnRgwocMh06WzjgLj6fSSSmXwhX2x/dHD9QTANAQhAAAIQgAAEIAABCEAAAhCAQK8JKKf75VP6VHn1fH17lDL1yzANAQhAAAIQgAAEINDnAnoXrQxfBD6IE11rO5TjHKSO2BYCEIAABCAAAQhAAAIQgAAEINBNAol82byaKNr079HfHbW20o307dR31mFVxhZ53r4zz+uUaYn6pO/3RAEHvfD28v7q9lm/f4e1dmylLryOB+UqmhGxIsHnS4PYZ9ckbJKpTGY92/ib955tF4vGg1b49TA7PeqfGh8+9Aw19a9FDiRZ3won6pe1Y7pUNpalx+t1Gg4WuHh2fpQDDNpRv1b2MTc9NtRKUEsr+zZSdisYSxop16gMvy63Q8ayfgTpNqCJVEY3KMPhsNmuXDwxRsFXuh+rNvoQfuvVCzMet9PRqI68PEvpsfj12KwM1nVeIJ3O6gb6cC1OLkwOKwGherXibE56ZXh9rg2BPof5fn26tBU10i6P2+H4zKsXZinRmaVZeaskmd54+dxMwO8xFND4dGXT0PGbHRPrIAABCEAAAhCAAAQgAAEIQAACEOhLAfVlCa159bK+hECjIAABCEAAAhCAAAT2Ckh7F+1dUqmUTOorW3QnvOcXh+un925dW0L3k31evlEZLIcABCAAAQhAAAIQgAAEIAABCEDAmEAkV5XW02VbpbLvmBhjBzpgKc4sQwkihNchUYCIWZiptzHfXZ9DeWq5Z9SnCyijTb4kMoWy4Kw5rQ6S2Sys1J/d51QSe/D+eT/KcV4cmwIRRIUrSENip790tlimZS9Kyys1/inTdrlyRS7LuzDaiVpjVz21iM2solS2mCwU6KOY9lQTKBNFoXzn0fL2tQsnplqp+ZXzx8ej8fQyxTi0P5WTwYrcfbgcHAv43FZr807oBncnF8vl6EVvYPB73Y6ZqRH32ka4aSaZa5dOjM9OjvoM7FIuYuIPBZ2B3mK1N6pOOUpCY/vyZ68ubAajSc44Qu/vKnXYl6hTvvnG3adBnc0PvHp1I5Q6NjM2vN8dbYVjKf58NDo8XlyPvHz51LRe+ZmJgG902Ou692glxHVUl+cgoBNzk76FufFhG6UzUa9Xzy+tBuPqZZg/fIF0Nl/iLFKUyKrpczYa8HmuXjw5fuP2k6ZZwSjIxcoZbYy0JJnOFBqV68b3aygaz0ViqYyRwBxysH/2tYszt+4/C2oFtAX8Xselc/NjQx5X04A4xSeTzedX1/e+75T1GEMAAhCAAAQgAAEIQAACEIAABCAwkAJaJwHrl9VPq4GarVOXxTwEIAABCEAAAhCAQA8LqC8C6l5YV7dVHeSjnleXxzwEIAABCEAAAhCAAAQgAAEIQAACBxMolcumRK5oCWbL1nKXX9KpUCTSF86Mib9/ZVqcHHdTiEhVDvypUDQNB41wsI9yMoKbYqFlf/rJmvjenS0RSjXsR6wJSPFE4pV5v/i7FyfE2UmvnNmH91m/fznAiDrSm6kwBxJx9h8ucGXGJ5YjGfG1331fRDJF3cAdDvShKAJRoGAf3oekH6ugWeeeWii30SQ8TkuBn7teHrjT9fR4IDk+6vcabQcF10jXLh6feP/jB+tGt2l3OcqiUbn/ZDV0+dzCRLv2TYFP9JFSqVgoFY7OPk0UHDVJndujy6vBRDqbK9WXnxgbdh2fG/dTUEFLmY+skll9f6H63crThYKxYCQubLdbpfnZ8V3BNiVqobgrOh7oE4klcxQIVnRQ5MWeRhhYsL4ZaSkj0PpWJH3qeCZnJOCAqmS9dvHE1JULxyvZbL6YzuSK9DFWpeAoq8vF+Uso7ZqBgbL5FJ8sbyLQx4DVYRRZWQ/GTy1Mj+gda3ZyxEfxPs7Flc3Y6kY4SdmjnmdlowRO0tzM6ND8zLjfSBAhBdBVVtZDDV+r3fp+ffhkJfzmK+c5Y5HuHzCX025/46Wzs/x6T6Vzef4MoXhBC2W7sjnpDa7nXb/+wZO1SP08piEAAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACEIAABCBgREAd6GNkG7rzbkX3YhjvCEE/hjhRCAIQgAAEIAABCEAAAhCAAAQg0JJAulgxx/JlSypfsVCHW0O/0Vs6QJsKyzFIFAzjtknip86OiZcpCMfI8Hg7JX74KGSk6K4yUz6nfJx//PqcODHqlgOKdhXQmFECgTizz//7w6ciykE+GuXUi6i4HCiUKZWFnTIVSYa2Uu+lt+bZhQN8PNZq0UA/6a5v3E3K8PKlz1x1UnIcw+fHOIjlxPyk7+nS0QU6LK1uJyhjztCw38Md1g888Gs/HEukx0f0g57o+TefnJ8a4QcFCpTp/zLFh5gooQjFuu0v+ovS7egGmGSzR5dFqVVgzia0MDsRaHU7SsxSCoZj2Va3+/jWk43PvX7hGAXq6AZM8b4pgZLZ7XLY+dHqsbj8/UerwSpHamLoCoHFle34iWNTwxS8qvs+ouAV28Uz8+P8oOC+Mr3myvT5Z6GMToZeO0qDt4LRVH2gkLJcGXfr+zUUTeYeL22ET81PGcpaxO2hoB4rP5S2tTqmoKrY2iay+bTqhvIQgAAEIAABCEAAAhCAAAQgAIEBENC6DFG/rH56ADjQRAhAAAIQgAAEIAABLQHdC4BaGynL6Jruri+V1bp5JchHGSvbYAwBCEAAAhCAAAQgAAEIQAACEIDAwQSiuaollROWIv0O75Xe1hxMYHTgkpx5p5WBYg3E68cD4vOnR8VpyhzE80aGEmXkyVKykF/5N5+I3377obyJ0XCFCmUjSuRLclYfI8fq+TIEw7Ec3iEp3/NtoQZwIpvbD5ZazvJy7uTcqNfjaimjQ7u9Pr3/bJvOyxl/U+lU4NnKdoKKtLQ/zvzBgQOcKWa/QT5cLauBTDKxeCrHgUU6zeiK1asb++vUvxWMpfbzjKbS2dKndxe3DqPxy2vB2NpWOH0Yx8IxjAlQRq7y3YfL28ZKvyhFbzsLZXOytRrkwwFpdx4sN43E7eb36/1HK9FgOJ56IdG5qXgyk/303tOW/8Z0rkbYM3FRcWcAAEAASURBVAQgAAEIQAACEIAABCAAAQhAAAJdKKC+kKE1r7WsC5uCKkEAAhCAAAQgAAEItFvAcKBPtZz9P/jgX/2pc0/0KoHgHj0hrIcABCAAAQhAAAIQgAAEIAABCOxfIEHZfBLFUkt34N//0Q6+JQfOSAYDb/hofNWKzi0YOrBS6ljAKX7u5Wlxeca3swdDm4twqiD+w/U18QfvLclRDkaDfHjvJUpqEcwURK5EIT8G62usVt1ZioOvquVCxZFPUkaf/hjWKCiDAiySrbSGM2e8fPnkJI1b2aytZZOpTOHZ6ma0XTvdDsUyi8vt218r9bLZbLqfZRzTtLYZjrey36MqG4un85lsvtDq8de3wvsOPljfiqRv33+22c7gL3X9w9FE+tb9RQQtqGG6YP7Z6laSg7A6XRX6O1e9cefpZo6Ci5odq9vfr9dvPd7sdLBPNJbK/uTGg3Ukv2r2SsE6CEAAAhCAAAQgAAEIQAACEIDAwAsoJ5h5rDwYpX5aQdJapqzDGAIQgAAEIAABCECgTwUMBfrc+/NfX7r1p//sD0/Pj8a++lPn1/vUAs2CAAQgAAEIQAACEIAABCAAAQj0hMBWqixRfIqh3/Td0CCKh5GDYozWhYN3OHOMkYEDbLj8f/vGMfHyMb8IeIwnWlmLZsUHixHxr95dEoVSVZgNHlOpF2VUEpsU6PMsnhXbmaLcRiXwSCnTD2NiqUpWu3BbK/k3Z6trPo+71A/tUtpAwQvblC2mpTZ53U77BTpRpuzjKMYPnqxFcrlCywEljep65+FyOBJLti1bSzyVyWYN1M/rcdgb1al+OWVfCm8Goy0FZdVvf5jTWy3WM09pUijwIHuQOj5b3U7+5MbD1U5kPlrdCMc++PjB+gDEMx7kKTjSbT+9txh8tLjOmXY68meIX1c/uflojYICDb1Ou/n9WiqVqx988mCDghvDnfDi98t71++t5vLFypG+KHBwCEAAAhCAAAQgAAEIQAACEIAABHpBQLkQUj9WT/N8/TJuV/28Ml3f3vpt6pdjGgIQgAAEIAABCECghwTa1imIOtZofWnsIQpUtZsFQrGclesXieflcTfXFXWDAAQgAAEIQAACEIAABCDQaYFwtixFsqWe+X3EiU9skvFTEFyeMwIYOdFQLVfF6XGP+CcU6DMbcAm7geNwL+g8ZeF5sJUS37mxIX7wMEiBRRxc1Nozxxl94vmSWE7mxGI8I8LZgrxfDmzql4GDfBySKPmkXOa1iezaiMuU65e2Ke3gzti3Hy5tK/NGxwtz4/7xUb/TaPl2lyuXK9VbD5bammHlY8p0EYrEDxTsw1k/VtZDsXc+vLMajiV0gwIki8USGPY6jPhc//TxJgUa7DvzjZFjtKPMKmWKamU/lFWqpfKN9h2MxHM//ODOEvvz89ConNHl8WQm+8mdJ+s37jwJ8mcyhu4WePBkNUoBLGv0Hk7R09W2J4yz37zz0d1lo0E+ilK3v18puDHCXpSFS/dzSmlTs3Eqnc19/OnjNbxfmilhHQQgAAEIQAACEIAABCAAAQhAAAIkoL4SoZ5XkJTlylhZrozVy9XzSjmMIQABCEAAAhCAAAR6VEBqUm98+WuCg1UQgAAEIAABCEAAAhCAAAQgAIGjEtjMlK3xQtVyVMfvluNyx/Nxn0N86xtviDMTHuPVou7PMcrE8/adTfHt62uCYoX2XFkzvjMhB/tkKXAonC2KVyZ9YtRpFRaOkGllJ11X1iQHPkmmamXSXU1dnjRTpogji2npuM7aRjg9NRZITo4Pe1s4mOn0wnSAOr+vtbCNXJRiMCqUxOXA2R4oc0yGs9xMjhmrN2eOaVZXDnp6nzK3BPxe+5kT0yOjAZ+7Wfn6daVyuby6Hk48WdqIZXMUAUdDOJLMzE6O+urLaU2PBXzOSJQi5nQGjl358MbDDf+QxzYzGfBOjgc8TofNeBqvnf3nisWyzqEOtJoCZArpTC7vdhnLVrS+GWlbpiKyL9+8+zT4ZGk9emp+enhs1Oe226yGA0M5QGiLgqko20k0HE3mDwTRJRsXOvx8d0kz5WpwZih+OB12y/zM+NDMFL25HHbDz7/SFkrgUwqF45mnK5uxaCy1r9dBL7xfd7xWKWjTdeLYpG/Y53FZLGbDkcmVSrUSjSezS6vb8fWtyIGCJBV7jCEAAQhAAAIQgAAEIAABCEAAAhAYGAHum6k8uNHKtDJWlinj+uW8DAMEIAABCEAAAhCAQJ8L8BfA+kE9zxe1eBmPzfcWg/9ckqyfrVTKZrpQZ6I7h5p5ulKpjculsoWn6bo+jZXlFbksXfOSx4K24235oC/GB+pPw7vC0OcCD5bjzrPHfNkbD4O28wuBQp83F82DAAQgAAEIQAACEIAABCDQUIA6LJt+5XvB+XCuaqUf1g3LdcsKOncgfvbqtPjOr33GcJV+/4fPxP/wb64Ls06KHQul/vn9X3hZ/MJb84b3rRT87e89EP/iT+/yuQll0YHHvCenxSx+ej4gJj12OvEh/3/g/R7FDkwmOhVULYvzkyJ40meKmXSei6OoI47ZeQH/kNtGD7vTZbdSzIrVabdbrVaLuUhv7GKhVC6USuV4Ip2PRlPZWDJVaOPbyXDjrFbJbLdJFoplMdO0RZLMpgp97lAgYJU64VcpeKlMwS9Fqmr73uyGa9cdBX1el218dNjlctqtbMVPos1qsZTKlQoHZeVyhSIlI5HHsUQmz8FC3VFz1KIdApwxy+NyWCkmTnI4bBZ6K0s2etBLwFwolCr5YrGUz5dKHAiYy+fLqXSuEIl1Jsir29+vZvpeMTI85BwNDFF8lE2y0WeKld4sbEXBjJVCoUife+Vynt4j4VgqQ8FQOXobDexnSzten9gHBCAAAQhAAAIQgAAEIAABCEBgEAQi8bz0zT97OOvPf/ztxezJv3f7P/2z36R2882S+FGkB/eF4wffcIWzD/NNkZQHz/NyfnAZLq9sy+fx+IZS/OBzFOqbS+G8BaFggAAEIAABCEAAAr0q0CyjT6+2CfWGAAQgAAEIQAACEIAABCAAAQj0rcCzZNUWyVZavjt/L4FwTEmVL0c1yVnEAUTXjgXEP3x1tuWmff9BUPzzb9+Wt+NgoXYOGUrS8r1nYfHGlE+cDbjlO5v01JU0wjdTMgMzRUqcGakET/mlRDt9sK/eEogl0gV+dHOtKUahwo/ade9urunR1Y0zDPHj6GqAIx+lAGfLMpIx6zDq2O3vV47ZUbIiHYYHjgEBCEAAAhCAAAQgAAEIQAACEIAABDQE1BctlHkeK9Mam2ERBCAAAQhAAAIQgEC/CXCmnrYPdJfXnurD0nYA7LDtApFYTu7EFk0U+rozW9vhsEMIQAACEIAABCAAAQhAoO8EnkRy9n7/0S23r8nlKs4a4rJL4l//4qvCYW0SDaTx7G8n8uJ/+dZNwcFE7Q7y4Spz3FCROgq/tx4Xn2wlKKsIL2vSGI06Ht0iDvKRhM1UKn7uWHXt1BiCfI7uucCRIQABCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAoF8Efulnz6xSEnLT4ju/8/uqNvEFhPqLCMq8skxrXrULzEIAAhCAAAQgAAEI9KNAWwN9TGYE+PTji6Rb2hTaCfYJx2tBP91SL9QDAhCAAAQgAAEIQAACEIDAYQo8CyXtwtTWn/OHWf22HKtCkT7/+1cviIvTQy3tjwOEfv533hOfLEbpqplyjaylXRgqzHsu08E+2kyIv14Ki1yp3MGjGaqSbiG6aYswW8zCLRXyb0xX14ac5pzuRigAAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACEIBAU4ERv6PID4cpnUyHnkSpsNYFCiWgp35fWuXq12MaAhCAAAQgAAEIQKCPBfbVM8hkMss31zU3CezhrD7Ko4/90DQIQAACEIAABCAAAQhAAAIQgMChCqzlrL2X6bTFS1HNipfLVfHWyYD4xc8utOz+G392R/z4UUiYKQtQp5PscBvovIlYSuTE3y5HRKJQkrP9tFzpQ9jAZDYLk0USI7Z88q0585rPZSkewmFxCAhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACEIDAIAs0uhyiXq6eb2RmtFyj7bEcAhCAAAQgAAEIQKCLBFoJ9JGDe9R152Ce+mXq+fp1mIbAQQTCibzE20cSRXl8kH1hWwhAAAIQgAAEIAABCEAAAr0owD/AN1IlmxC7for3YlOa1plbpxWIw5l83A6L+JNvvCFGPMTQwvDjR2HxW28/pICWTuby2V0hvqLG7VhJ5sSfPtoW2+nC7gLdMEcVrJYr4pinEH1z3rrpkES5G6qFOkAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgAIFBFVAH+jTsKXTpq//yC4z04a2VAI9bDeihbjQN9837wwABCEAAAhCAAAQgAAEIQAACEIBAc4FsLmsOZyvWPo/zERwgU63sPY1AcT7iN372gpgLuJpDqdbeXkuIf/pHn4h8oUxZdQ7/hnZ0DkUUKRPR31BmnzUK+pEo089RD1wns8UqzKJSPT1SDF6ZNIeOvlZHrYLjQwACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAASOXEB9gUQ936iCRss12h7LIQABCEAAAhCAAAS6SEAd6KOumvzl7+JXf/OY2eb65qOlkP/3/v1HF9WFWg362bt9v3dRUrcY8/sRiMRyVt4ukqiN97MPbAMBCEAAAhCAAAQgAAEIQKCXBd7fFi5BwRl9n9GHzkaYVMEwHOTz0+fHxa9++WRLT2EqXxL//b/+SNxciQuLRe80SEu7NlyYA2g4vihZLIu3F8PiTigluD1HO1CgD4UffeaYZeX8uC12tHXB0SEAAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACAyOgXCFQxkrD9eaVchhDAAIQgAAEIAABCAyAQNt6uJhMZvUXzQHgQxMPUyCSyMuBPrFkbXyYx8axIAABCEAAAhCAAAQgAAEIHLXAw0jBvhov2ESldNRVMXx8+UQBZeYp0+OjZ1HD20UzBbEw4n5efshpFQG3VXzzF14RTqvl+fJmE3xszuTz228/FOuxnHDajG3XbJ8HXadkzPnxWlR8uFmLrVHFMx30EIa2J87ihKeSvDhuCrqsokRPj1I1Q9ujEAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAq0JmIRJq3+lsqx+rEzzAZRpZdzaQVEaAhCAAAQgAAEIQKBnBSSNmvOXQs0OHiYzgnk0vLAIAhCAAAQgAAEIQAACEIAABCDQcYF4tmTZShasXZAKpuW2cjCLtYVsOly+spPyRqKZhRGX+F//7hmxMOoydOxCuSKSuZL48eOQ+P7DoFiP57RPdBjaW3sLcWYfPu1yK5gWEarjT80NC6dkeX6lrr1H2703oqzaLNXyiMOUmRwS6TGvKUsvqMruUpiDAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEDgEAW0gnjqlynTPFamD7F6OBQEIAABCEAAAhCAwFEIaAX6HLgeJpNm9HnD/VLfHc3AooYbYMXACZw+5stSo7PZbL5okaTCwAGgwRCAAAQgAAEIQAACEIDAwAuE00UpmilK/AO6167iUMYYUaTgG6MDt89ci4gRbrskvnBmVHz9lRmjm4tYpih+9Cgk/vC9ZfHparwrTzpwMNNaMifeXgyJz88GxBil1mGnTg10rkZQUqPSjFckZn3VlMdmLlJ4UQeP2KmWYL8QgAAEIAABCEAAAhCAAAQgAAEIQAACEIAABCAAgZ4V4PPy6nPzyjJlzI1TppWyylhZx2MMEIAABCAAAQhAAAJ9LNCRQJ9qtYrAnT5+0RxF00b9jiIfN20TRUmyHkUVcEwIQAACEIAABCAAAQhAAAJHKpCtCHO0IKT6KzlHWqEWDs4nCSwc2dLCQOcW5NJfPjcmPn96VEgGMwIlKEvO4+2U+OaPFsViKC1ypXILRz3cohzMFMoWxfeehcSVMY/wUVCThZbxcs5oxME5tVgcxY5MdpY5rZbKkLVa8tlMZROVzViGnGaLRPl5qL0mc60hlKzHZLaISrkkApZUyu+y5GaGTCmHZC4TZy++lA73CcLRIAABCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAKdE+Dz9PXn6pVprbFSVlnXuVphzxCAAAQgAAEIQAACXSHQkUCfrmgZKjGQAvVBZq1mlhpIMDQaAhCAAAQgAAEIQAACEOgZgURRmFNFYemZCqsqWmkxXY3dahFDTqv48rlxcW3Or9qb9ixnDXq4lRTfubEuri9FRTJX7vqcNRzUky1VxKNoRnhtkrBTBA4H+fByOdiJA3ueX+erBf7wOpdkql4ds+ZnvZaMZDZVPeaNrefF1DxUvih5rG67KHlspqK8S3UZzEMAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEINARgQ/uBId4xzPXvvbK2o1vf0iT6oAdZV4d0KMs70i9sFMIQAACEIAABCAAge4V2HegT31ABTevWq0ot5c11Fple75BraENUAgCOgLKa0opxvMI9lE0MIYABCAAAQhAAAIQgAAEelmAr+JkCiVLpljdSdXSg61p4dc/J//xu6xiLuAUrx8PiJNjbt0Gs9F2Mi/+6u6W+LcfrohYtiRaDS7SPUiHCjBNlDIRRehhZODyTqtZnB4R+ZlhR8plkypCOPQ2lTPl6hXCeghAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACEIAABNonEI7lrN//eGPEL9ze4fkrP70T6MMH0ArqUQJ7lHVKOfVYWV9fnsvwoCyrzeFfCEAAAhCAAAQgAIGeFNAK9GnY9aZa0Q7mUQdYaElURbXhfrXKYxkE6gWU1xiPlen69Y2mjZRFMFAjPSyHAAQgAAEIQAACEIAABLpFoFCummL5qqXSw7+tTS3c58NKWW3OTHjEr37ppFgYdRl6GqqUMeg7NzbEX97aEqFkQfB8rw2tnDjJl6rmcK5qDWar0rxNFHqtragvBCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQGCABeovYvC0Ml8/zTzq+QEmQ9MhAAEIQAACEIDAYAloBfpoC1SrEx/f3/w6BU44Hi2FXpW/QXLgD6XkqXA2H/lB4Tw0pn9ploOCaJ0SHLQzX9s5l6O1FLTx4mC8RwwQaC6QzBSqdqup7nXTvLyhte3dm6FDohAEIAABCEAAAhCAAAQgAIFWBCKpjCmRLdn4t3SvDpUWKj8/4hL8y+/KnE9IZmNJjFaiGfHDh0GxGEqLYpkS3PT5QJ70mih7liI5p18S5T5vLpoHAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQKAtApQJ3jrktq5SZnnNFOu4YXBbmLETYwJyF8y6ouqrQPXr1evqNsMkBCAAAQhAAAIQgEA/CugF+sghECazNEsdbOy5bGmWb8CbzRWH5W+Ocicdup9wLWqHw3soeoc609B8bRmtk5ftfOfc6dRTW6Zw4juoIoGxvkCpVBUWuoc1BghAAAIQgAAEIAABCEAAAoMkcGe9LOL5Hv4tROcSJLpqanQ4Ne4RM36HcFotRjcRHNtToH9yxR52MtzaWsF4vmwJp8uW0gAENrVIg+IQgAAEIAABCEAAAhCAAAQgAAEIQAACEIAABBoKJNLFWa9LWrOYTUV1od03rhZ0Uyq65zUGCByuQLPXXLN1h1tLHA0CEIAABCAAAQhAoKMC6tviGup1E0vmqFJa3xnrl9VPd7QN2DkEIAABCEAAAhCAAAQgAAEIQKCvBd6PlURiz+XG3mky3/ejVDF+nuDi9JB4dSHQUgNPjLnFZ06OCs4GNChDhl4T4Zxx10FxQTshAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCDQToIzpUjJTmilTdp9m5XgdB/4oD72yWA8BCEAAAhCAAAQgAAEIQKBdAnoZfeTjVCsVOQDo+t0VcfHkuPiDP7shfu2/eUPYrWZhlSxy9p4qZfJ5nsVHnjY/X04TtXWc30fufyLn9JEz/7SrIdhPnwvsZIMq2S3C2sIdnftcBc2DAAQgAAEIQAACEIAABAZAoFgsiGfxkshShtNeHTiZj82ivtdI+1vzlfNj4vF2UjzYTFJmn7LmLUraf9Sj22OqVBHpcpXOzxjPfHR0tcWRIQABCEAAAhCAAAQgAAEIQAACEIAABCAAAQgcrUCFbkhV3MmQrgT7cGYfOoddUtdMK5OPku1Ha516e8xD4AACzW7W3mzdAQ6JTSEAAQhAAAIQgAAEuk3ASKCPqVzKrlkkp9iOZilQZ1P8o5+5IreDf/hYqKOOVTKJaoUDezjYh8cUw1PhaY7lqS3n3jVVQd8zaaHcNYn/afS1cyeoo9uwUJ+jE6iaai8WC40pbe7RVQRHhgAEIAABCEAAAhCAAAQgcMgCq8mCSNFvblHdc53xkGuy/8NxMp/CzsXT/e9Ff0vO6vOlsxzskxbvPgmLPAXC9PNQoCCfZKEiigTskDofSNXPlmgbBCAAAQhAAAIQgAAEIAABCEAAAhCAAAQg0P8C3OfITI883SiKhxfBPpZ1s8lEOdRfDEpQDy9RB/bwOvWyF1tiCgKGBdSd4LTm1csM7xwFIQABCEAAAhCAAAR6W8B4LxAO0CmXxVYoJf763Qciny8JiuURuXxZFIrNO87QD5veVkLtIQABCEAAAhCAAAQgAAEIQAACRyTwLEPZWuQbYvTeb2u5xnTRlG/a8OrCcMcFvQ6r+EevzdFjVmSyxb7P6JOl2K9Pt/MiXZRvqdJxXxwAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgECvC3CwT32W9FqwT3maxlY6Ga95Ip4De+oDf9hAa1mv26D+hyqgvNZ4rDy4AvXTSoW0linrMIYABCAAAQhAAAIQ6FMBvUAf/pJI2XlKtTFl7PG6beLNl8+Ib3/vE5EvFPnOBrVgH7275NYF+8g7e/HPXtq6sntXYskgCsgvl0FsONoMAQhAAAIQgAAEIAABCAy8wEqSojnkQB8Ecxh9MfzS54+LawsBukFJv5tVRYGu+S0ldt1o0igTykEAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQGEiBRsE+5YoS7MMBP8rjBZE62IfXaC17sQWmINBUgLvEKQ8uqDWtXqaUU8a8Xj3Ub6Neh3kIQAACEIAABCAAgR4RkPZTT6/HKd64dlp8+y+vi5//mZeF3WahoB9KaWo1Ccmy891RDtapChP1qVG61fAaZVr3uLy93JFJtyQKDIBALFkQPq9NxNNFMWqzDUCL0UQIQAACEIAABCAAAQhAAAJClMoVsRzNEoXhX9Ng2xH4ja9eEF/7f96TsxH39f1E6NzJ3VBevDThkK8ADsoLwONyiNGAd1dzY4mMiCXSu5a1MmO3WYXbZRc2qySsVouwmM3ye7BYLFE26xJlicrT+S8KvMMAAQhAAAIQgAAESIC/Kzgoo6TTbqOxja6PmeUb5OXyRZHNFeRpXObCSwUC7RPweV1i2Od+vkO+scPyeuj5PCYgAAEIQAACEIBAqwJKsE++SH3eaODMPqlsZcrjNG+YTSb5RCCdW+aeb0pnOPlEvRLYYzJxr7jawMvq55XlGENAQ2Dn9aSxZvcipZwy3r22FhRUv4zLPX9N1q/ANAQgAAEIQAACEIBAbwo0C/RRviTWxjuBO8p3xCE6mfrq1ZPi29/9ifja33tVDvbJFSqU2tRMFzNqpSjMhyb4904djvyVUv5nZ2H9dF05nkSwjwoEsxCAAAQgAAEIQAACEIAABCAwSAI5ur4YzNPv5gHvIRjLFEWxUhFjHrvhp/+/vDIp/s6FcfHdTzeFhTpd9u9gEs8SJboITZ1N+RTLAAzczDdeOi0Cfs+u1r7/ycOWAn3sNknMTY+KiVGf3GHQ6dB/fXGwTzSeFtvhuFheC8kBQLsqgRkIHKKAf8glnNSxXD1shxOiTIGiGAZHgAMVA/4XHZ/rW47XQ70GpiFwMAH+7jA7OSJmp0fE8JCbAoObXWLjr/BVwUE/W6GYWFkP0zguLztYLQZz6/GRIc3v9PiM65/Xg5HvNZfOzonpicCuRlNnXLG6Ed61DDMQgAAEIAABCECgFYFGwT5uh3mT1hXp64Z81rVRwE99cA+CfVqRR1kS4NeW8mAQZVoZK8uUcf1yXoYBAhCAAAQgAAEIQKDPBZpfhWjQePqRIq8Z8rjES5ePi2999wPx9f/iNeGgixx5CvapZfapffvc+b1Ti9mhrWpxP7Wl8v0O6oOAtI6HYB8tlYFbFksVhJ8z+tB4dFj7ovXAoaDBEIAABCAAAQhAAAIQgEDfC2wncyKc5c7aej+e+5vil//gusgVK+LPfu0zhhsqmU3ij7/xpjj3698TG/GcoDswGt62pwpyxzYK9MnkC8Kr0eG/p9pisLKnj0/tCfKJUfANd6A1MoxQgND507MU4OMXZnqdtDK4nHbBj5nJgLh6fl6sb0XF3UerIp7MtLIblIVAWwTeevms8Lgde/b19vc/Ecl0bs9yLOhfAf5c++xr5zQbyEGQRj8fNXeAhRCAgJifGRMLs2NijIJNlOtjRli4LAdkLsyOyw/OELi2GRGPn222FJxs5Fj9Xua1q6fk72DqduJvnlqkd+eNfK/h793qQB/+Tr5B38nLdGMIDBCAAAQgAAEIQGC/AlrBPulcZZKDfej0YYmDefYG/NSy+aiDe9Tz+60Ttut7AfWJaZ5XHtx4ZVpdrn4dT2OAAAQgAAEIQAACEOhjgUa3tFW+JKp6EtUWm+i7pNw/hv7xed3i2sUF8a0/f0++MxnfOSlPnW+K5Z1NaRNlZ88daxvXlssr95R4XlSekMvvXoQ5CEAAAhCAAAQgAAEIQAACEIBAvws8TNDva/kuGf3e0sbt+8P3l8S331sWf35rQ/zocahxQY01Xock/scvntBY00+LqiKer4pIuthPjWrYFg6yuXhmbs/6T+8v7VmmXsAdbd+4dlp8+bOXxdT4cMtBPur9mc1mMTs1Ir7yuSvi8rljwkLzGCBwmAKtBqodZt1wrO4RMJvw2dQ9zwZq0msCnGHky5+5JF6/dkqMUwbAVoJ8tNpqowxAx+fG6bvDZXHtwoKQJItWMSyDwEAKGPlew5k11dl7+PfB2ZPTA2mGRkMAAhCAAAQg0F4BJdhH2Sv1f5M42IcyqUscvMMPXqcE/NDU885u9etrZV6sU/aHMQRaEHj+2trZRpnnsTLdwu5QFAIQgAAEIAABCECgVwX0rvLt+nJYm6F/lUAdGvOFDc7sc+X8gviTP3uXMvoUhRLsU6JgHw4Kqi/P0/J+Xvyz8xVUXtDYUT5m49VY098C0WRBbmBiQDou9fezidZBAAIQgAAEIAABCEAAAkYF3lnpk4wMOj/5G3n8x0/WxK/+2xuUOdgsn0v4n/7opohlar8PG22jXv5rXz4pzk95RVm5IYm6QD/MWyTxMFHuh5botuGVyyf2dIrdCsUFP5oNwz633Kn22Mxos2L7WsedEs+dnJE7AnMHXgwQgAAEIAABCPS2gGQxi6sX5uVg3pFhb9sbw9fVOEPhz3zxmhw03PYDdMkOOZCJv7upHy/RzQMxQGC/AncerlDn2t33qTxHgT6uAcluul83bAcBCEAAAhCAgDGBRsE+5UrVyntQAno42KcW8LM7oEcJBlLKGjsqSg2KwH/9xYUtfo1s3v7Ot1Vt5iso9VdRlHllmda8aheYhQAEIAABCEAAAhDoRwF1oM/uM6O1FldNZunFcvrqyBchTHSXUhPdDZDHZrNFzuxzhdKj//F33hHBcJrvYPAis4+8TR2fHOxT+y5a+5fWyRPP5+oK100i2KcOY/AmYzvBPvFUa526Bk8KLYYABCAAAQhAAAIQgAAE+kGgUi6LxQRnaXnxk7wf2mW0DeuxrPjVf3dDpPNlYaHOlmY6J/DJcky8fXvL6C7kcn6XTfzKl07Q+Ys+lqSTMI+ilZZcerHwselRMTnm31V17uR36/7SrmXqmQm6A/+X3rwoHHabelVb5/0UTPTFNy8IBPu0lRU7gwAEIAABCByqAP8d/9JbF8WZ49PytbBOHpyzDb718hnNbIWdPO5h7ZuzHZ44NrHnMT87flhVwHH6UCCRyoqlteCullksFnGFsmRhgAAEIAABCEAAAu0Q0Ar2yeSrExzsowTyvBhzbzcO9nkR8KOs47rwdP18O+qHffSmwIjfUTxzbCjjMKWToSc/eEqt0OokycvUy9XzvQmAWkMAAhCAAAQgAAEI7Eug5duMcj4ejrfhYB++Y2mlwoE+tceQ1y0unT0mvvs3H4rPvHFVnJ4bFoUidTSh3zOSRNtx3yTaln7E8A7kb6byJHVaetFtib+fvpjbV6uwEQQgAAEIQAACEIAABCAAAQhAoMcFHgeToiz4ZzsHcPTm72S51pWqoIug4qNnUfHqwrChZ+UHD4PiX72zJNajWTnI5/lGtMN/8R9ui79/dUp47MZOaXC24a9enRbvPgmLdx6FxVqsT7IkPUepTTwI9/dNMbjT7TWNznsrG2ERjadVGi9muQPtm9SBlu8orzdEYknBHQdzuaLI5gvyeSuX0y7cLno4HWLI65TPgTXbj3/ILXfY/cEHd5sVwzoIQAACEIAABLpQwG6TxBfeuCD477mRIUnfG2LJjMjm8vQoiFKpIngf/P3D5bCLkYDXUADwhdOzgoNiPtUJXjZSJ5SBwCAI3Hm4KvgmAHx9WhnmpkbEk8CQCEYSyiKMIQABCEAAAhCAwL4FlGCffLGWRb1SrUqZvJhw2U1bZlEtUZ856vpWpRGP5S50dOaag33knnFygA+vUyqglFXmMYZAnQB3lNQa1MvV81rb8DIu9/y116gQlkMAAhCAAAQgAAEI9IaAXq8Y/uK380WRRjwlz3GwTy2jj5nGFQ70sUjCXKkIyWoXJxZmxLvv36DOERfEqTm/8HvtsoZkUQX78FKOGqKjmOgf+f4G8ldNPkiD75xy+Qbr5KPgn34ViO1k8uGxz9PZu/D2qyHaBQEIQAACEIAABCAAAQj0jsByzko/lkv087j3fwPTfUKElbLyGB0ebaXEp6vx3UE+tLGJdrQYSovf/Iv74v/8uUuGdscXZb0Oq/jHrx0TIcoUu5XIixIFHvXXUBXhXFlE8hURsBt37iWDy+eOCbud3hN1Q4XOQ91+sFy3ZO/k61dPNe1gm8sXxdJqUCyubIlkunkQmIOOf/bEtHxX+maBQ+OUQWh+ZmzPncb31g5LIAABCEAAAhDoFgH+O/9FCvIZ8rqaVqlQKIrl9bB4trrdNNiYd8I3y5uZCIj52TE5KyF19Gu477Mnp+m7L2WwvPOsYRmsgAAEagKZbF48Xd4WpxYmd5Fcu7gg/upHn+5ahhkIQAACEIAABCCwXwEE++xXDttBAAIQgAAEIAABCEAAAu0SMN774/kFCA7yqWXzMckBPpzNx1J7UGr0IY9DeCmzz9T0pLh1+654vBITz9YTokB3MuO76HJgj/wf70+epqbwtLxUHu20rfEFj1r5nWIYQQACEIAABCAAAQhAAAIQgAAE+lDgcbRYC/Lpg5gUjqspljkzkbEhmikKfqgHDhjicwK/+4On4uZKXL1ac55PObhtFvE6ZRN64zh1tBxp3nlTcyfdvpCCwcomSdzZbh6o0u3NaFQ/vjM+B86oh8WVbZGmW2k2GqbGhwUH3TQaIrGU+Mu//Vi+e75ekA/vg4OCbt5bEn/xNx+Lx882Gu1WXn71/LyQWghua7ozrIQABCAAAQhAoOMCb750WjfIh4N7/uJvP6FgnEXdIB+ucIW+BHP2wR//5L7463duyZkDmzXk1MIUBRSPNysysOvK9FuiVC7vehSLJZEv0I0RMAykwL3Hq/Qe2/0bk7NxTdNvAAwQgAAEIAABCECgXQJKsI+yv1pmn+oEZbC3cpYeXv5iXLt1Ni153uFNWadsr55XlmMMAQ0B9ZUh9bzGJvIio+UabY/lEIAABCAAAQhAAAJdJKCX0UdVVblHDfWpoUSkcu7Rnaw+FOhTtVSEpSrR8ooYcjvk9Vm6k+yt23fE5UsXRDyVF1fPjNL+zNTRgfZDXyu5sw1/u6REpvQzZ2cZMvuozDGrCETpzss8xHcy+yjLMYYABCAAAQhAAAIQgAAEINBvAoVCQazEstQsCz16/7oMn03gi6JGBy7J5x20BjOdP+AgoN96+4H4d7/8ulaRPctskllM+hziM6dGxEPKFrQcyQiOO6ILs3vK9uQCboepKh6G8+Lzc/0XyHR8bmJPdid+np6tBJs+XcfnGneUjSXS4ocf3qXOors7Bzbd4c7KAnUq5bvtc1afhVntY3D2oWm6g//yesjILlEGAhCAAAQgAIEjFOCsIGMjjYOD85TF5/qtp2JtM7LvWkbjafGfKdMIZyk8fXyq4X6unF8Qm8GYyGRr10MaFhywFW//4MaAtRjN1RPgIHx+r/B37vqB31/r29H6RZiGAAQgAAEIQAACBxJQgn3yxbK8Hw72yRZM405bdZvu8/P8blV00+xaVzoTn9DnYB86YUsDB/fwOqUS6nllOcYDJ6C8JpSxAqA3r5TDGAIQgAAEIAABCEBgAASaZfRReuC8+AJJnWk4Hocz+vDDTJ10atl8drL6UEYfi8UqLJIkB/scm/IJh2dUzuxTLJXFDz9eE4ViLbMPb097kvfDO5UPpixjeOXoLyb2Ph1y+b2LsaQ/BWIULMZDDIE+/fkEo1UQgAAEIAABCEAAAhCAwHOBEt2ZOE+Zcftp4DuaGx24ZO28wd4t+FQAP/7o/WXx48etBVG8Rll9/quXpsSQ0yqs0vMTD3sP0nNLarbZEt1IpV+Cl3aeA36uT85P7HlGkqmsiMRTe5YrC2xWSXBGH62B7/7+ww/uiuLOxXmtMkaWcYffUCTZsOjc9EjDdVgBAQhAAAIQgEB3CHhcDjn4plFt5Gtb9L3hIEE+yr7L9B3/xt1n4s7DFWXRnrGVAolfu3Jqz3IsgAAE9gosre39PcgZPX3e/rv5wd7WYwkEIAABCEAAAocpoAT7KMesBfuIcc7sw8s4eIcftWmloxsy+yheGL8QoB6SWhdKlGX1Y2Vaflnt7EFZpoxf7BhTEIAABCAAAQhAAAJ9KdAs0KdBg5UgHwt1rKGMPubawyIH+UgU6EPBPmYaS1Y52Gd2cqgW7HOL7pJKnZS+86PFfQT7NKgKL0awTxMcrIIABCAAAQhAAAIQgAAEIACBXhRwORxi1u+g37z0s71Pfve22oxmV6qUIKD/+U9uilS+ZPgp9lGAz4Vpn/iFN+fFuMdueLuuL7jzOjk3aqeXSz8FMAn5Dt0u597nSi9TDnfu4xvUaA0rG2GRLxh/3Wjtg5dx8Nq71++LcoOsQJNjfjpHto9Tb40OiOUQgAAEIAABCLRd4JUrJ4RE17W0hgoF5rz70X0RS2S0Vu972d1Hq+LJ0mbD7TlQoVlmwoYbYgUEBkxgYysqOBhPPZxpkjVLXRbzEIAABCAAAQhAwKiA0WCfWtAPgn2MuqLccwGtSyL1y5RpZfx8Q0xAAAIQgAAEIAABCPSvQKPeBru+FJrMFrrNwE7nCO4wQg/uOCIH+tCYs/pQmVp2HwsH+Uh0YaQW7DM14hEc7JMVPrG0+Fh4HJL4w+/ebzHYR7tjxvOnheuEoa8Fhr02ce30CAWPWcXVU4G+bisaBwEIQAACEIAABCAAAQhAgAW+Rr99rFUKRuAgjr4YjP921yvJ600Wk7i1lhDvPYkY1rFazGJ22Cm+9sqMmB9xCY9dMrxttxbkWBaJbgJ4xmcWX1lwd2s1912v0wuTmtsurQU1lysLnU6bMrlnvBWM7Vm23wUcMBSKJjQ3N1OQj9u1N0hJszAWQgACEIAABCBw6ALDPrcYH/E1PO6NO8/Edlj773zDjQyu+OT2ImUGbLxvBCoYhESxgRbgLFlrm+E9BnPTo8Ju6/3fensahgUQgAAEIAABCBy5gJFgH64kgn2O/Knq9gpwv8xdfTN35pXlyjqteaVtShllHmMIQAACEIAABCAAgT4UMHKWs9a/hv417WQV5SAf/rbIY+60UPvuufuOZ1UqYNn5TsrBPvQrRtx6LMTTJ0/EiZMnxf/9rZvin/7Dq7StmYKCaH9UnuN15P3SjHwoObzoxfTe77h1z4i8MW+NoR8FFqY88mvDZnELq61xZ51+bDvaBAEIQAACEIAABCAAAQgMpsDssEn86jWP+N2bKZHvg9+8dHHT8BMpnxvQKW0mkwJlDv7t7z0QXzwzKmySsYCoYZdVXJn1iav0WI/lRJoyAhmvmU6lDnk1n7Cx0zkVv90ivnHFe8hH7/zhOCvPmEbn21AkKdKZfNMKuByNzx3k8sWm27a6cisYFxOjfs3NONAnkcpqrmt1ocflEBzA5LTbqOOiVVSqFZHNFkQmlxcZGheKB89S1GqdHHarcFPGJc665CRzbutmGwOpWq3PQcrDd6/eUZtIFJzpptc9v774dcZ/CnOFouD3MD/y9Ojk6/6oj7/3GemfJZztjD/P+LPa6bDLnbE5Oxo/n/zgIMpMNt/R57ebNI/6vaZl0U+f71rtU5admtcOKOb10XhaPFneUoq2fczfPz+5syi+8rkr8rU29QGG6HvQ+MhQ2wONrJJFeNwO4aDvE/w88zy/7/hzNZsr0HesnCg1yFaormM/zfP3GH6wCdvw3wDFJU9/e/i7J88fxWCzSnLwuFJHvi5boM/JQrEofweMJ9ubcUrdxm7/zF5eC4mF2fFd1bbQ83eS3t+cPQsDBCAAAQhAAAIQaLeAEuyTL9YyC1aqVSlbMI07bdVtWlfkIB8aaMQ93/gm2nz6WZ6WT0Mr65V6qeeV5RgPjAC/LuTXxk6LlWmtsVJWWTcwSGgoBCAAAQhAAAIQGFSBZoE+/KWQ+4xoDnKGHw7yqVCojtyXhn/AULCP3HGHdqvqwDM1Wutw8uHdihzs8/W/87r8LbVQpB3IwT61TZ4HEdHRq3RHWv6tw795+CfPzj+a9ZEX9kHHp8aNG+w1+IUy2M8/Wg8BCEAAAhCAAAQgAIFBFXhj1iM2M1Xxxw8pUIA69dM/vUlBv+nNnHrG4CCfAlCdV9DalM8h/NWtTfG//cc74re+dplORVQFBwA1G3g9X4z9796aFykK8lmLZUWeAoZ6ceB2zHgk8fNnvWJmqHFgSy+2jet8qkE2n2WdbD68rcWy+4Y0vEwZbG2+u/dWiDMEzSu73zV2UQf2gwwjfsqUPTUiZiZHdLMDpahj7tOlLbG4st1yR9SJUZ/cGVJd1wdP1kQ4ltq1mDsEnzg2IT8/HIBRP2xuR+V19cuU6SdLm2IrFFdm9zXm9+8bL53e0yGa3/s37j6TOyi3suNe812kDuedDqQ6LJNGzxMHPJycnxDHZsbkztaNyinLi9Tpenk9JJ6STSxx8I7OR318pV39OObX1qnjU2JyzC+407rewO/rUDQpVjfCYm0jIrL5gt4m4sq5YxTA4NQs9+HNx6JUqnXC0ixgcOG5kzMiQG1RD6uUUYI7mxsdDuu91q7P98P4/DFq165y/DrkrB+NhhsUhNPpgT+3+POLAxK0hlMLU7qBPp955eyeTTkg5aNPnzxfzplNuK0zEwExGhhq+r28QhlS+G/NynpYrG9FDAf9XDg9K/xDu7NL8ndVrYEDR7TqzWXXNiNCK3PjpTNzgoOf1ANnRjLy+aDejuf5vTwzGRDT5DLk0f7sULbjz6RwNCWb8PtdL+hc2U495r8zV87v/d74+NnGrueajWanAmJhblyM0XPGv3saDRyIxIHnDxfX5QC1RuVaWX4Yn9mt1KdZ2W36fpmjvxEcoFU/8PeJ+4/XKDi+R39D1zcG0xCAAAQgAAEIdJ0Af9e1Wy0CwT5d99R0dYU+uBMc4grOXPvaK2s3vv0hTaq/rCrzPFYevImynKcxQAACEIAABCAAAQgMkIDeFbXdXxTpPDKH3dSCcaq1DD87wT50MwK6OMAdY3iXdFcrybqHkYN9Xjsv6AS4W/zFf35P/JN/8EU68SpR5wMl2Icz+9B+6YQ1H7gW50NTrQb78JFx4naPPxZAAAIQgAAEIAABCEAAAhCAQO8J/Mxxr7gbLorNdElsZw7eQfUoBPgnermy+xRDs3rI5wSadGZTtpW7u9F5iW/+aFF8/dVZcXrcI/yUsUdvsNIdns9OesWbJ0bE7fWEuL7EgRq9NTDPjMciro3bxOmAfpt7q3W12nKnS/XA541WqNO33sCZPhoNo8ND1Ekz2mh1y8u5ky53rOSMI+qBO17uZ+A77V87vyCmJoYNb650HL1IHWEXV7bEzXtLomLwfccBO9zRVT2oO9qeoU76vH+Jgn20Bs7IMUOBSVoDP3cHDfQZp4AkDnzSGu49XjUc6NOrvlrtbteywzZR15uzVpw5MS0HgTTrzKzezkod9bmDPD8iFJTGAWXPVoPqYrrzR3183Qr2aAEOzpubHqHAwCnN4JhmzeLXAXdu58e1Cwvy5zYHLjTLqMHbaH2W8XFmtwL7em3U15GDls+dmpEzoNQv5+l0Nmco0Oew32vt+nxXt7cf5hdmxygwWDsjJAfxcqDZYQyccYQDaLU++6bpewBnmGmUjZC/Czd6zX98+yndJ6AqB+by327+vDQycLYY/g7GD/4+xYG0HFCpN4wMe+XPcL1yvJ7fS43qnUprZ0Kcp+dLHWDM+7p1f0mI5okeudiugYN6rl1caJiRcVfhnRl+fkYDXvlxmYIKOUDr9oOVpp9JWvuxUmdQrbYnKCvPdjghb8Kfe29SYLODMgwZGTjT47GZUfnzdoWeq+u3nhoO0Krf/2F/Ztcf+yDT/NuRA9NO0/fU+oEDf/i7Y6eDpOuPiWkIQAACEIAABAZLAME+g/V8H7S14VjO+v2PN0b8wu0dnr/y0zuBPrxb/kqrPOrn66fV6/XWKet5jAECEIAABCAAAQhAoIcFjJ3Zr28gXTlQLjhQnp3nwT58OYRu9KUf7DPmEaWiXQxTZ5Q/+k8/aBjsIx+STpzvK9iHN6ZtEewjK+IfCEAAAv8/e28WI1l25vd9GVvua+W+1b4vvbC7yebSzRnNjDgamSNZlO2xZMOCoBFgSIBgA9KTXgzbevCTYT0YhmHAHgM0xmOIMwKpEYcip5scNtlsdld3VXV17fuWtWRm5b77+58bJ/PGjXMjbkRGZtyI/J+qm2df7u9G3LjL+Z+PBEiABEiABEiABEiABGqYgM7tk//mjU753z59KbO6UMb8Ct7p1JbDYt4Q10R1KB915eUGbXZmcVX+7PxDY6WnrSklKTRQwOGRQbuWe31/t7zzZFY+fzQjC8u1I6LC7nU1JuR0b1peG2iU1nR0tgWwxCoLEzAxsTXoXs4uRJpQubAYbvkBloIwORMWcCrlPv38TqWaEliLOH1sVJ+xlXdcMWkZk+ox4fbnH12R+QIsShn0uRP75fjh4YJVMAF/6uVc3or+qDTU3yUpHduqioHKdaMOMRLamtY+o1pzqWW+5XIrVq/aTDA5+a1Xjmw+cy423rB8WGbo6TpiJvVCEBJV6Fbt/sP2p9bTm3WC9dffOuE8H5S6b1bA09PVKj/54FKoJQ2c2yEYczlYiSpHBOZva6i/2ynyQZlbdyf8RZ3han/XnIPSxCjn97C6tZwOAUCYu3O/uLAlrG6p6RDxTDyfdopO8Nnv39cZSWgT7BeL9r39xjEj2AnmRY036rUYLOnt1/P0L89fj3QNFrXtapTDHcK5U/vlqF4n2fec5YwDdSEwhZWk85duOy0QldMu6uBa6+zx8bLGh3HhXNeu19E//fCyLC3roowRXTXO2RGHFqkYvkNBoQ8qwqoZhT6RELIQCZAACZAACZBAmQQo9ikTHKtZAv6XPUExjz8P5YNx2wZ9EiABEiABEiABEiCBOiYQZcaA40LRs+pjHoTrk3G8MGjQyQeJRFIfPsNvkEQyZSYkJNWyTzKZ1E3j6qdSGTX2k5bOjnY5eWTUiH0Wl1bN1Sgs+6yueRZ9Nh+y64Np/MN/ryfjZf+YRGS4ndalIwESIAESIAESIAESIAESIAESIIFaJ9CoKz+/opZbhluj3MbHb29hVGSlhMn9KI8VpaM4PD+AbOD/+uCO3Hk+J4sr0QU7J9Sqz984OyhDHY1mrRDHA5AoQ9j1MrCDfLo3I28ONcvBrmgrfe/6ILfZIVYyd7nJ6VlXcl7aTMhq8CgIIcw7Xz4pne0tefWqmYBP/OtnDgpWiS9X5OMff3dnm/zWN87pJPvt7+cb5w4XFfnYvsMm0uP5YCkWimx71scpYThE6HP7QXELLvXC1/KohB8HJuM6SboSIh8/j/06yfnNc0f8SaHhavcfOrAaz4CFs9/82pmKiHz8KJqbGuVrXzouyRAh5MzcojzNWsTw10MYVptcAtJguUJxTOp3OViTghA1zMXhuxY2tlLO72Ft1Gp6rwpiXW51bU0ePC5uPdBVt9y0QsIiWJEpx71+9uC2RD7+PgdV5PbuV05JJqJVIH/duIRx3vjqG8fl2MHhskQ0rv0Aj7dePaIibbfA0FWnUNpRFaNDeLf5frRQ4QJ5uAZ869WjBUrkZlXrnJ07iu3FpqbnnA1A6ENHAiRAAiRAAiRAAjtNwIp9bD+6gFVqYVn61cK9WcVIrVzjtlCfP280qMFrE9ZY1vfSbV1bzh9nuO4J4LWE/9WEP4yd9+cH8+oeDneQBEiABEiABEiABPY6gUgzhBKJlONCUeU3+obdPHDW2w8jxwkR+0D0A6FPSkU/EPskkyr+SaWkszMr9vnee7Il9tkoQeyDw7d57+M+lhEnBrkrM5UESIAESIAESIAESIAESIAESIAE4kHgnfFW+bsndKISTNgUuxeOx5C9UepiIHjZ+caB7sij6mpOy20V7URxeCqA7e7zBfnn/+8FaWuMbry4tTEpv3GiT/7l3zylzyrMMiNRuqxuGX3O0ZhKyn92rElO7Gvc9kTA6u5MeO99OiHb5cIm8QXLYsJ1IVFQa0uTmYR++tiYpFVIFweHiaJYHb6SrjGTlq9+6cS2JuYeHOsXbFHdXRXdhFlSGRtyT5KP0jbEX9ifoNNJEnL3QXHLC/XCN7j/24lXm8nwQLeZIL3dCc0uBrDSAxFPIVft/guNrZbz8JuMz1aLin12wnV2tMqh/QOhTcOqj8vhc1bsM+GqZ9NgkWxYLZO53K17ha35VPu75hoz0ko9v4e1U4vpEPumQ0QrT55Ob8v6XDk8Hjx5gUl/zqqw0FeOOzAa/bc7Svtd+t1798unQq1aRWmjWmWwOOE3VOQ9PNCzI0M4q+KcM8fHttV2d2ernDu5f1tt+CsP9nUZS0z+NFe42uds15jKSYMFy6Xllbyq+M3Yrsgzr1EmkAAJkAAJkAAJkICDAMU+DihM2i4B902i12qhvO32y/okQAIkQAIkQAIkQAIxIhB99ouZNhO8ToTQx9ubDRWQN2DBAYh9NGldl9NNJPTPRthkCa+tzo42OXlULft87y/lD/7Wu9LYmJblFS8vpZNs4MwLDu2oQZN1fQP80dFoj8g2RTcDpnzeHwwy5CVJXlkmkAAJkAAJkAAJkAAJkAAJkAAJkEBMCZzr15Xsh9PyVw+zk5jq9F4Xk3E3YNYn+1wgyuGA/un8vSn58RdP5TdVvFOK+5vnBmWsu0luTswbwU8pdXe1rO5kJrEh/+hcp/S0Ne1q17vdWbhFn2gCMIz3xp0n8sa5ttChp3QxmlP6TOrowSF5PDEpjyam5PHTSZ0kuBpaZ6cyDuuk9XG1QhLmlldW5d7DZypempOpl3Myo0KmttYmwYrtmHgpsGlDAABAAElEQVQLUUPYKvutLY3yldePyU9/+bn3GC2sE0c6JkaeOT7uyMlPgrjnuVq1AL/HT6d0Mm2+uA+TTjFZfrUEC1+2p9GhfTaY4z95Nq0LCOVP7PQXqie+/v3aTjgOTApZLcDz4AePX+j3clKevnhpjvGafm4aMymBVZchFVwcUAFam4r2wtzpY6NyV783Ya7a/YeNq9bTD6tFit4Qq2zYt9XVNbn36Lnc121uflEW9PuLtJSKWJv1nIPzBL7vhdo4pMf+2q1HTlT31RLLa8sHJOMQBuI8ezWknrMxXyIsksEyWdCtqfUXnJ/DXBy+a66xlXN+d7VTq2mFrOTAQtNuO3wH8Nve4bA2aERJ+v1Y0TLbdRBCQBx779Ez/f4tmXNrGt+9poz57u0f7StoiatLxSivnDogH312I28o4BYUK8GKTr/DogrK4VrB5QpZx3KVj5J2Vq9lwq4tbX2cj+4om4cquppV62Dgjd8cXGeNqEVBWIvDeSrMnTwyKs8nZ8z1ZFiZQumwmuRyj55Mygu1aDk9My/TL+dlQQUtuAbsaGs21hZxLRjmjhwYMvsUlo/0ap+zC42t1DxcJ+M3JOj693UWvB4IlmecBEiABEiABEiABMolYMU+S1mL855ln4b+5szGhOat6HWwPvZWoz7Gwo+Zb+dNgDOz4TCtzcu3/QfjNp1+XRMwsyDreg+5cyRAAiRAAiRAAiRAAiURKEHog3Y94U1uD0XEPtnn3noDonclSchzxHSqcS9NZEvs816o2Ad94mo2q/MxEYp9co8EYyRAAiRAAiRAAiRAAiRAAiRAAvVP4B+e65Dni1PyxbTeo68u1+0ON+jK26W4BMRBKgz6H75/Wd491musCEWt392akf/7H74l7/xP7wn0RaX1HLWX7ZbTUaWb5A+OJ+UrI+ET27fbSxzqt+vkxSadcBp0eI4EkUtUBwsLY8P7ZKA3f8Kfvw1McB1Tyx/Y0AcsAT1W0c8znayJSauVmFjr7y8YxgTeV04eCCZvxp88m5JffXrDTOzcTNTAlE72xAZ3+fp9+dLZw05xDfIHdJLtwfEBCbN0gTIu96pO5k3oJN2gg+ACoiiIbJ4+f2nG5ud05/6EcyxJWMTQ1fQLiS+Cfdk4Jtm63B21IFTI1SPfQvsbJS8OTGC1q10nKbvcok5i/sUn14zAJ5gPIRk2nAsuX3+gVrAG5LXTB53Wzdpam1Us0i7PXswEm5Fq9583oDpKKGSZDOeg85/fFpxDgs4IHSB2mHss124/NiJMnINcDmIICFVcIj+IDm/ffyrHDg3nVYXFDEyOL0dIEGYN6P6jF6G/E3H4ruVByCaUe34Pa6/W0tv1/BDmClkEDKtTiXSIFFxCHwjgIexA/nYcRM0///hq3vcPv98rKjLC9wJCuOP63Tl7Ytx5XkX/sAQF630T+vvvd5eu3vNHTRiW+L7922/kpUPw+7NffZGXvhMJEBpB1F3I3dFzxscXb+YJkfF7g2sdbFdvPjLCaZxHwtwb547ID98/XxHROM5vH3123SkcMqIfFf5AMIl9gyUgfE6CrqerzQhiZ1XEFOaqfc4OG1c56bD86RL6DPRR6FMOT9YhARIgARIgARIojwDFPuVxY61NAvkX9ptZDJAACZAACZAACZAACexFAvlv6otScF1TQuzjbZgNoyETTySS6quFH32Jn0ym1E/qRJusn0pLMpUyWyqVUbFPe9ayz3uypA+w8aoPln1W19RSUPYBtfHRD8Zo0mzYDto1Nptn6/jiDJIACZAACZAACZAACZAACZAACZBAjRFoTqfkn7/RI8NNuqo3zNjUqcN6IeW4H196Iv/zf7hectW3D++T/+7bp6REfVHJ/ZRXAc87NuSbgxvyrYPhq3aX13b8avXpqtsuh9XVS7UE80sVCxSa3BjsB8+eerra5dSxMXnny6fk93/nTfnr77wib5w9ZCa2tjQ3BqtsO46V8SGACTqIjs5fuiXv//JynsgnWBaTQf/qoy9UEHRdrWy7vzwnj4zo57vIs7NAw0GRD8YEAdWf/+Un8vNfXzVWkzAx2C/yQRMPdTIxrBC5HMRXpTqINZoa88VfEAbA6kshV498C+1vlLw4MOlyWK2wY//lebfIx+b7fVju+vD89TwrErbMcIiFhGr3b8dXbz4mlUNI43IQBvz6ws08kYGrLNJgsefCF3fDsp3nBFv4pp6nwhwsoJXqIAh1TR5HO7dU2Bjm4vBdCxtbuef3sPZqLT3MCh72oxRRcSX3u1C/hcYbZQwQsvzsoyuRvn9Xbj6UXxhBULgFodfOHIrSbSzKvB4iBsXgcB2Ba6cPdSt2jYnryR///EKoNTG0BwHiab2G3K6DtaMfvv+pU+TjbxtXfBBnhVk4Q9nOjhZ/lZxwXM7ZOYPaRmQyZEEACN7pSIAESIAESIAESGA3CVixj+3Ts+wj/WvrG2mk6fM184AOvj5qyz6s89L8+ba+LW/j9OuOQNgDW5sO34btzgfjNp0+CZAACZAACZAACZBAnRHIn0UQYQet8Ca3qCfu8cQ4mgNBjm5+sQ+EPmZTAZAR/SS3xD5JFf74xT5PX8z5xD5ozrtG9dq3Ah/vWtbkbF7CbgZyh2djJU5osNXokwAJkAAJkAAJkAAJkAAJkAAJkEBcCDQ3JuQfnG2XJMze1qHYp9xbd/OUIJWQf/m9S/JgcqHkw/Vfvr1fuprTatXHLZQoucGKVNC90sVTjnWn5B+c6ahIi3FvpLe73TnEclayx0rs/+FnF2RCV2Ivx+E5FFbXhzWcN84dlt/7zdflW+++KrCEgEnfSYe1m1L6warwYZMPYfkCVi1KcbBiceXGA2cViJQOjvc786Ikrq+vC4RTH312Q+bV4kohB7HRvYfPnEVgYQmT5ktxo4NucdD9x88LTlquV76lsAuWjQuTMNEcJl0/fZFrJSK4D8E4LEQ9VwtcLhdmNaja/bvGWg9pmDTuchADfqiWyUp1hSx2NTeZ+VHOJmdUgBj2OQqzzONsKJsIi2JBYQyyMPEfVs1cLi7fNdfYgmmlnN+DdWs1nsmknEPH7xeuHarhFgr8tsIyTrnuqgp3IGSBWDequ68i2r/8xeeyEiLahaCvXy2zxd3hWi3sdwA83v/wc2MBLOp+4PMBq2QXr4SLEPeP9kk6Xdp1jr//hcUl+bmKspaWV/zJBcMX1ZrS/MKSs0xLU7hIPS7nbOfAy0gMs8bVrAzaWurbImoZuFiFBEiABEiABEhghwlQ7LPDgOuneTvJ0bza0N0K+v49tXn+NIZJgARIgARIgARIgATqnEBZQh8wscKbXD5bYp9NQY5OiIBVH2PZZ1Pgo5Z8dJKKseiTFfukjIWfLbHP9//iA7l+d1LXq4Vln3VdTWurz822vYFgNJ503V7+5gnZc0fJWO0R2Dy0tTd0jpgESIAESIAESIAESIAESIAEdoTAmb5m+YdndYLdBlbbrq+7Jp1Dp88RysMGiyXzy2vyv/y4dKs+I93N8i++ddxMhIw+FbK8cUaupfvTnliTf3yuTTIqYtoLrrkp33IL9ntOJ1SX42BZBhM5f33hhmDy93YdJowePTgk33jrpFr8eUPeeuWItLeWN3nwxOER53AwyfOzApYsnJWyiZ9fuy/TM/POIgfHBpzpURJhNeXeo+dRipoyt+89dZaF9aLhgW5nXlji6FCPMwsWCgq5euZbaL8L5cWFSSpE7AWhZQlz0Td3NcyyU3ur27pMtfvfHHidBcImUr9QIVYpIgOLBcKHsMnr7vcTtqYIxJIu16qTvcMEpa7ySBsbdlsBul3AclBcvmth++RPL/X87q9bq+Ew4czKanVEPuAYZgkPeWHCJOQVcrNzC/Lp5TuFioTmvZiaLSg4PrR/MLRuXDJwvRbmIEh+Pjkbll0wHVaP5ubdwpqULnh4aBvXWxev3JM1FVeX4tbW1tX6z6SzSnOz+7oaheN0znYOvsREHBOwcLmw+wtXWaaRAAmQAAmQAAmQQKUIUOxTKZJ7rh3/mxGE7eYC4S8bzC+UFyzLOAmQAAmQAAmQAAmQQEwJuJctizhYvEzLf0EHYY8xNaq+5mtbWO0Oz6XtIqeok9R/YS6d0ZVS9w/Lzz74tbycOytHxrqkqw2rTiUklUSf3oQftA07phumQ1zZIqyJZjbOZiC/G2+A+elMiS2BqZll6WzPyPTcivRmwl9MxHYHODASIAESIAESIAESIAESIAES2AECv7G/Re5OL8qf39Ob7nWdmFjO7OgdGFdOk3oPfu3JjPz337+sE6/MDbv3asrc1GvJbNJmHS3/8R33RLXNMkUCuO3/P352R59DNEgjJpP7udjHBdbPtoVnGKiHou1qJWBOxUJVd7pwSlNiQ/7Zm10y3FmekKTq+1DGABpDVtlf3sbkWxzXm3cnzDbU3yXHDg3rSvSdZYwut0pSJ3Ni5fbxkV6BVZHLKrKZmYsmSII1oDDBy/lLtwWWTcpxEEp8pJYz/trXz+ZVh4WJpsa0LC5FXyUejWCF9FJEPqjzQuu8VGEVVv0PurGhXrnzwG3xJ1h2n1oIwUrsQYfJ/xMhljRQtt75BnlEiceJSdgE6Uw6Jcf1+4lJ1KW4ew+fqwWF/Efdq2vu71G1+y9l32qpbJiA6lmIxaUo+4bzlcsCU3bpr9Am7qsw8bXTBwWfqaDDOTvqmFDf9XuBdxywouZycfquucbnTyvn/O6vX6vh/Pda3p5AMF4tB8tXYc71OQ4r608v1TKgvy7C12490mumIX0vl/8+b0RFuykV766GCCuCbe12HMzCrCZCDHKhTEE19gOWfS5cuSNfee2Yc7cgDiz1dwwNTb2cCz2vODvyJeKay+VaQgT0KBunc7Zr7OWkwQpVMpn/DrFRr3/pSIAESIAESIAESKAaBKzYZ2nFu97X53apheWG/ubMxoTmrei9iT6W1plv6uOhud6S6FNMEzZPzW2+HXswbtPp1xwB/80nwnazO2Lz/b4/jHL+OML4zFgf+XQkQAIkQAIkQAIkQAJ1QCD/LVeJO2XEPJgtkeMasuKe9U2xD8pBqKP3J5qXFKyplP9qwGuko827Fh0cGpLPPruoiWekt6tZDgzpSsUU+3iQ9uBf71OxB3ecu0wCJEACJEACJEACJEACJEACBQh850Sn3Ho5JVcm4/kOBy8zr07Myb/83ufeXuAZglXUbL53snd83rso1bfIdiZaou7zuWX5Vz+4khX55LZv3nnZMZjnFbmAMWZbIzdnl2M6tv/4WIuc6t07Ih8QDpuIt5J9Ib7do/BoYkpXPZ+Sro4WGRncZyZw96iYBMKwch2ee+0fUcGPTuzECvEfX7wlhSbsop/ennbz/CzY57qulvMwZFX2YNmwOEQ2EMK4JscP9XfLrQJWKFxtXr72wJVcNO3O/Qk5e2J/XrmBvk5JqwivGCNUHB3al1cfCRBWFXJ7gW+h/XflxYnJbAELXedO7tcFf1qMFYql5WiitIWlZbl09Z5rt51p1e7fOag6SDx/6ZbTks5sRAFkEEFrS6N+FvLFgiinS34Fi+fEMREfVr9cFj3G9LzyiQoqdYJUTh1XBOcg1+/Dk2fTAotDLhen75prfP60cs/v/jZqMRwmcIjyu7RT+1vo2jfKZzU4LggeClmdCpZ3xWFl6JYKpV3fIyzw163XT08LiG5dbe5WGix3ee8l83u8euuhzId8f/NLu1MgMD12cEZ6utrzCuAasxwR1I07bktkeR04EsLOs4Us2cTpnO3YpbKS8B123TlB6E5HAiRAAiRAAiRAAtUiQLFPtcjXRL94IG03DNiGrW/TrO9PR1oxh/LFH34Ua4X5JEACJEACJEACJEACVSOgU2e278Ieltt0+A360B8+RD54AQC/QTesfJpMpiSZ0i2Z9nwNd+gLvP597dK1r18+u3BRnk0tyKfXnsnyyrquELaRfUCP1Qz0mhTtYzcQ1pAXtvtlYjaS65vyuUmMxZPA1Kz30nQ668dzlBwVCZAACZAACZAACZAACZAACewuAZ3DKmldSfvbR1rlzcGMpCBQKXAbvLuj2+oNQ8ILTbPpeDd9tdqbRNz4W+FCEx23Wi0cAofcfrbaN31iPHYsdmxZv3DLO5+rOKQp1SC/e6BRRT6NRScz7/yIdreHTNo9EQ8TVivppl7OG2HATz64KH/6ww/lZ7+6LJj4OTU9F2nyt2sseE41roKf3/jqGbVCk7+auL9O2Crzk9o/Jqhv1z17MeNsoq8HC+lEd9O6uvyDJy+iV/CVhNUe1+RkPBscGezxlQwPQozlcpjAX8jtBb6F9t+VFycmsCLi+mzYccNS1re++aqcOjqqorxWm1wxv9r9V2xHYtYQLHu8mJrN2yAWKNVBjPPOWyf1tzpsubDiLd686540n8mkZaivq3gDWmJ82H0OKiSYjNN3rdBObuf8XqjdWsgLu6aACLVaLp0O73tpufTv0E0V9VbC2k4hyzT7HCKXavEL9gvBXZjbjqDG3+bVm4/80c0wrgf3qdCoVDcTYpUnSjuwUuRyLqGiLRe3c7Yd13b8sN+bRj3v05EACZAACZAACZBANQngOXWj75rfs+wj/WvrG+ZCRZ+RmKf68HVNChNWfUbW11A23+5DMG7T6dcUgc3jmx014nZDkg0Hy/nzEKYjARIgARIgARIgARKoYwLbtuhj2eDBtd5I2Kj6W5OLkG7kN/oSX2cqGKGPLRi07IN2zD/1O9pE9g81yOLyhhH7nDt7Rt7/5IG889qIVk/oiljoU3vSS1r0jLsdNWpqIrBmam55zJBwzesfm+0dlVA+JM9XjEESIAESIAESIAESIAESIAESIAESiBsBfT8oGb03PtSVlpfLazIxtypP5tdkcZX3uXE7VlHHgycYLemEjHek5NWBJhntSHvPVKI2UOPlMumUPjcChXy3rCt075TDREdr6Qd9QATW09lmJmnu6/b8UiYIwhrJN98+LX/x089kNWTcXdq+y2UyKRke6HZllZQWZq2grdW1znl401dCJrGG19jKgbWLCbV6MeCYUA8rGbeLiHW6O1sFFj2CDiKNl0Umw+4FvkEuxeJxYjI3v2QsvxzePxg6bJwPTh8bMxs+S4/U0tXTFy/l+eSMoP52XLX7387Y67VuW0uTdKoVDAi7RlUI2KHn0e06nCee6Wem1yFwHB/pLWo9DRYgXHVhaephAQFknL5rhRhGPb/DMso3VHRVTfeTDy7JlApPK+XCxABhv52V6rdQOzjnhbnliNbN/PWfVcjSDs6/i7o1OQTMsIgYV9cdcp2F67Iwa1yl7gt+k8Ic+oflr1LczNxCKcWrWnYnztmV2KEwq1y06FMJumyDBEiABEiABEhguwSs2Gcpa7XcE/s09DdnNiY0bwXiHXXqYbabmXOnD/lN2Dzst/l2HMG4TadfFwSCD8htHL4N18WOcidIgARIgARIgARIgAQKEwh/c1C4njO3oNhHhTYNuP8wYh/Ps434xT5owzjjN0i7vicYHeiQ+xq/cOGS7D94VP7spzfl2984pMVKEfvY3hw+xT4OKPFKmpxZlgNDIi/nVuI1MI6GBEiABEiABEiABEiABEiABGJAoLMxKWf7GkWNwMgffzEnSzqBjVKfGByYMoaAF749TUn5O0fbZUTFPhBy7SXXqCKXMBe2+n5Y+e2kY1V0TN70T+DEROeRoR4ZGdjnFJ8E+8MEyNfPHJQPz18PZpl42L62tzbL19444axTicT2EoU+251YDTGPS+gDixewXrCSndzg2jeIgVyumDUf1NkrfF18wtLixuTS1fsy1N8tLc35Yq7gPsBC1qHxAbMhb3FpRQU/L80k6idPp2V2fjFYpWi82v0XHWCdFmhpzkiPWgHpaGsWnO/a4bc16aJe4dZMtoPi5t0Jp1hneKBHIOoIE2OiT1gV2nxf4RvEXbVWVsjyWty+a76h5wSjnt9xrq6mAAaDbm5Kq9AnZ/jbioRZyMHxhsB0u2LCcgbXqtcNYW6pDKtYcwvbE0T6xzKr4kqX0CfO4omw7+HsXOm/F34W/jB+i+b098d17Bobw69p/W3YMM5FaC9ubrfP2dvd/7D7hVIE+9sdA+uTAAmQAAmQAAmQQCECFPsUolP/eX/73QNPfvLDj+XxxT/7k8De4iWA/0WAjds0G7fVbLqN0ycBEiABEiABEiABEqhTAqU9aY4AoRyxD+pgTdakWaNWr0V1VP4XaEN93vXpxZkVuXPrmhH7/NEPLst/8TewilxUsQ/aKDDNiWKfCEe3ukWmVOwDNz27LJ1tmeoOhr2TAAmQAAmQAAmQAAmQAAmQQIwI4Ja2PZOUoz2NagVmRS4+VcsHcztn/SRGu15XQ8GTi4OdKfnKUJMMq8inJW3sI9fVPhbbmUKT8AoJQoq1W4n8Z2pFBNunn98RWJo5rKKDA2P9Oc+wgv3sH+mTWzrJ3C8YsmUK7astsxN+JpPWCfUJgRWjKG67q94/ePxCsLp6WifU+11CFwMa0Yn2haz6jA7mC30wuf7uw2f+ppzhvcLXufMhiXFjAqsoP/6ri2op5IRacmkNGbU7GZPLR/TzgQ0OE61hlevqrYeRJ+hXu3/3ntVfKj53Y8P7BGLJ3p52FWwUF3ZVksL9R8/l1dMHJGgtBZbbYDmo0DlobLjXOZRb9yac6TYxbt81O66gv93ze7C9Worj+x/mYImlGkIfXFuEueXl1bCs0PT5Cgp9cI7F9zfogt+rYH4147jecblKW83B98gl9CmVzby2EwdX7XP2dhmEWeuKsyhtu/vM+iRAAiRAAiRAArVHgGKf2jtmlRjxvq6mFWw/l9nZZzfeuxXSpjdBMjfTn+YP55ZijARIgARIgARIgARIoC4JJHZir/wiHa99mBT1NujPMU2lQV/mNzQk1MBPUreEJJMpSeiqfdiSiZSJp1JpSaZSulpcRob62uTM4R5ZkC65eeOGjGj8X//xp7K8sq4TE9RaUPZS1vSNvtBx9o8/XHB/bSMFCzGTBEiABEiABEiABEiABEiABEiABOJHAJZfutQSzFsqEjnak9bwjtzyx2/H62hEvS1JOdObkXP9jdKWaZCUWvfZa66QxQBY2YmLm5yek48u3JS/+Oln8nJmvuCwDoz1OfPDVpp3Fq5wIia4R3FYXT5swmSU+iiztr4umGjvcmGT6FG2q6NF2hzWh548nZIwSwz+PvYKX/8+FwvHkcnC0rL8+OcX5fL1+/qMt3yBKiZZHzkwKL/7zdfkrVeOqKWYcMsYfk7V7t8/lnoLw1LTa6cPyu/95uvGx/d9t0U+YIpzUJgVsHEVY4Y5jH+fipOCbnJ6VqaLnPfj+F0L7kclzu/BNmspPqW/42GukOAmrE4l0iEwcrk1PTe+nF1wZYWmQWCLrVIu7PxcqpilUuOJ0k5GLVG5XCUt+qD9sOukxrRbaOQak0nbKLBQYWilymXE5Zy93T0Ks9KWKWA1dLt9sj4JkAAJkAAJkAAJlEPAin1s3fWNjdTCsvSvrW+YC8mNjQ3zYBi+XipmHxJ7aahj8239YNym0481Afvw3/p2sDZu/WC6jdMnARIgARIgARIgARLYAwSivdWvCAhP6OMJcfxiH6RD8JMV/WTFPgkV/kD8A7EPxD8Q+wz3tRuxz/RqmxH7/N3fOmps9Hhiny0rQFtiH73mNZe9ucKfgrtDsU9BPNXMnFJLPnDWr+ZY2DcJkAAJkAAJkAAJkAAJkAAJxJEAxD4n92Xk9YFGOdChVjtUKMLb3DgeqfwxNWWP3eneRhlp12cie/TArayEr1ifSu3iY6z8Q+RMwWTvn3xwSV5MzTrzkQirNEl97hUnl9BncVFcpaw93L7vtn7Rv68zz8qGHZe11GLj1r/z4KkNxtbfbb6xBeEbWCEmsC518co9+Xc/+UQufHFXnr2YwYQVX+3oQTwX3j/aJ3/93VflgPpRXLX7jzLGWivzysn9RnQF8VVUYWFwH2FxBZZzKmFZJcwCT/++Dgmz8jA2lG9RDGMMays4/mrFC33X/GOq1Pnd32YthWGhL8zB+tRuO4gsmpsyzm5xjVHqObHU8s6OfYlhVhUTMRalh425vF8XH4xAMIx1Q4zZBHZB4nbODo6vlLh5P+yosKEWIelIgARIgARIgARIIG4EKPaJ2xGpm/EEBUJ1s2PcERIgARIgARIgARLYiwRSO7XTeJia/4B7a4LRhkp0jPwGln30xa0urKdiH4h1PBGQCCZ2bA1vLTvBBZZ93tScuflW+f6PPpA/+P139WVcylj20RYkpRNj0K/pX8s16LNbXd8Af7Q/7RWXs94fDYS4bF/aUEgBJpMACZAACZAACZAACZAACZAACZBA/AjglhcLaRzvyZj77Huz6zKztCrLagmXLqYE8AxCD8/hzpT8xlizjHemzTONmI52x4e1qBO7w1w6vfWcKKwM0g/vH5B9XfmTdO89eiaPJqYKVS0rDyu5f3j+mvzOO6/q9w/fwlwHK0WtLY15q/EvLq0IJvZWw7nG6RrH/OKSK7nkNAg35uYXlUOulRWMY2SwxzlxftQxyR5CsAdPXkTqfy/xjQREC8WdCcb3xY0HZoOViMH+Lhnu75aBXhWEZUqzjIBnw2+cOyzLy6vycGIyEqJq9x9pkDVQ6OSRETl2aDjySJf0uM/q+QFWNmC15OXsvFpKWzBpaOQbb50059DIDToKQpT5XIUdQQs9+JyMq6Whq7ce5dVyWRyDZbm7D5/llQ0mxP27hvGWcn5fXllTAd7L4G7uahxjqKSD0AkiMvw+Bx0+Jy3NGZnX5bR3y+FzGObwG1qqwzkUImNYtKqEa2x0n4MraTWoEuP0txEmtKm0hch0yn19Wki87h9ntcNxPGdvh0nY/UIUa5Db6Zd1SYAESIAESIAESKBcAlbss5S95/Es+zT0N2c2JjRvRee/6a2rzqozFn7MnDtvApyZDaePlbP5tv9g3KbTr0kCwZc6wXjYTkUtF1af6SRAAiRAAiRAAiRAAjEi4H4CXaEB4kWZ3kQEWvOJfXyCHExEsu8cEklUSenElrWcyS1oKyUZgdhndaVRutuS8t0/fS9U7GM61jGUJfZBZa1LsY+hGIs/kzPei7XprGWfWAyKgyABEiABEiABEiABEiABEiCBmBGAzKA9k5SDXWn53QNN8pO7C/JwdtVYxI3ZUDkcEFDLKm3JDfnW4VYZUks+zelollbqFR4mfIe5tApmorgTh0ecAhqIiHZC6IMxzegE9Xs6+RuWRFyuSVfpxwR2vwubCH7lxkO5cvOBv2jFwxA/RHFLKhSslLt9/6mcPjaW19zY8L48oU9HW7NgC7p7j57r88Pgs8ZgKS++1/i6KeSm1gITO2II6O4+eGY2pOHz0NvTboQavT0d0hYQjdl6fh/Ppr/y+jF575eXVOQRbnXLX8eGq92/HUet+eMjvXLm+HjBYU+/nJPHT6d1mzTW0GBRaTfczbtP8oQ+6Hd8pC9P6NPW2iTdna15w3rw+IWEWQnxF66F71op53eIpGC9rt7cs8mXKvTJ/93GuWN8uM+IDndrn/frdyfMFbI+FFYH6S0qYpoJXHsUKl8oryXE2hDOlXF1uNZpdIhEGzOVfS2aCWmvFoQlcT5nl/u5CrtfgJU4OhIgARIgARIgARKIKwGKfeJ6ZHZ8XPYhp/Vth8Xithx9EiABEiABEiABEiCBPUCgsk+0HcBKFftgEQJj3cc/dyO1tVqYZ+cnYwREnR3tcvLIqEPs02As+2A4RmhUUOxjSjlGnk2i2CeczS7nTM0uSUsmIVMU+uwyeXZHAiRAAiRAAiRAAiRAAiRQawTwcrC7OSVfHW6QR3OrsqiTaJ8v7M5E2lpjVd3x6uIk66vyh290yyv9TZLE84vqDqjqvWPC99ramiST/gdD3rCwOn0Uh1X6XZZymhszUaqXXWZSJ6/vl/wJw2jQ1TcmgrscJozGZXIoLHJXyt158FROHR3NWdQHbffv69SJuLn77LLmg7JoI6rba3yjcKkFJmH74Vl6WZCbdydMEUw6h8UVTI7v7MgXZNh2ksmECszG5f1ffm6TyvKr3X9Zg97lSjgmb6oVpTA3v7AkH3x81Yh7wsrsZPq9h8/l1VMHJGjtAYKedhWS+QURYdZVbt33Pn/FxlkL37VKnt+L8Yhr/qMnk3oOcf9uH1DhLiyM7Ybr6WqTjvYWZ1ewCvP0eXnWlFrVaqD/c+3sIGJicy0KfUJESF0OEV9EDHnFYDXJJUxGwTiLoDC+uJ+zMcZyXNj9AoU+5dBkHRIgARIgARIggd0kQLHPbtKubl/ecuV5Y7APYf2+DaOwDVs/rwEmkAAJkAAJkAAJkAAJ1CeBXVkmFmKffKeXrpjAks0zfjaeUJM+DbqibUJfxCIMaz+JZEoneaQkpaKfhE72SKUykkylpLNzS+yzqKuM4op2eWVDVtc2ctrXiE6W0XGYoZhQNoyRucbnG3F2jL4UBkmABEiABEiABEiABEiABEiABEgg1gQakyr2aUnJu2NNcrpXBQ68t43Z8fKeUXznaKu8OdgsaRVn6X86JYDnOy6XTueLf1zlwiZY7+tucxWvWFoha0Sur9/L2Xln3y6RkrNgjSXOzS+JyyoBngmODO7L2ZvRwZ6cOCJz84vy7MVMXnpYwl7jG8bBn15PTOZV0Hfl5kP54U8/M+IRfD7CXP++Dmlq3FpIKqxcKenV7r+Use5W2TEVXeE5vss9npiUv9Bj9WKqNMtKrrbKTVvT1cXCxIL7VTTmd2NDueck5OEzNvFs2l8sNFxP37XQnayDjPtqoQniYJeD+OvQ+IArq+Jpr5zcH9omxGX47JbjwgQopbaV0vd0rWodyOVm1aJhXF2YyGmfCqsSrguzMnYEIq2w897MXK4lxzKa39EqcT9nl7vzYfcLha7Ty+2L9UiABEiABEiABEig0gSs2Me2u76xkVpYlv619Q3zUEMXujZPj+Fv6JQ4r5yXhrDNt/WDcZtOP7YEXCIef5oNw7fh2O4MB0YCJEACJEACJEACJFAZAu43b5VpO6cVv6hnK8MT+tgH4V6ZhBHoFBP7QOQD0Q+2zo62Tcs+mMyB1x4U+2xRrodQd3tGXj26Tzpa0/LKkfzJHvWwj9wHEiABEiABEiABEiABEiABEtgJAiN6P/VKf6M04QmALqZBFwcC+h5WFzE52ZOWbx3piMOAYjWGpWX3pNu0PguK4haX3PVbW5qkt6c9ShNllWnMhAsJXBOJw0Qr7a1NZfUfrIRV5iFuCG6pVPXOA3fuuy3y+CfVY/9dFlruPHgW3MWC8b3ItyAQzYwTkwTEjYGt2PjD8u8/ei4/+fklgcUYl8Mz5/bW5pysYN+Il+vK6b/cvuJcb6i/2zm85eUVI8Yq17pFpc6JGJy1CBUc6LiKlKzrVMsqLusqt0POX7ae34/Td80/LoZzCeikN/1MPMlN9MXOHB9TC1A7+5s5NrxPr03c14IY343b4ePzDdUZrJRQaVytHrksLaLTaor3nDvtS3SJi5GNfRkacJ+vfNUjBXH8wtyzF+VZYgprr9LptXDOLmefg1bbbBtxsZZpx0OfBEiABEiABEiABMIIUOwTRqbu0l1iHSve8efZsD/PwrBpNk6fBEiABEiABEiABEigDglEmyFRwR3Hi1W8oNhy3ktUiH2Qjn/6mldXGt7AX8FiZd48JAxVV3TdSJoyZuAoj7b0vyf2GZHv/un78ge//4406kQGiH3gUrqKsXVI0abFrGmgvo5mM4xYQdE7VvnKGbttlf5OEzgw1IbDLJlkq6QzuhI1HQmQAAmQAAmQAAmQAAmQAAmQQCQCLemEHOnKyB++0in/66fTsmzubVEVd1l0u09Any3oMTjS2SD//Ctd0uR7ZrH7Y4lnj9u16AOLC4f3Dzp37uThEfnpiy+cedtN7OpoCW3CJUB4PjljnmvhWZnfwaIPJo7ee/jcn1xy+JxaCDhyIJ/DxSt35fL1ByW3V4kK91SQ8drpA3kThvvU4kpjJiWYhBm07mP7DbPEYfOD/l7kG2QQjMeFCSYXf/3NE8HhyeT0rPzoZxfy0qMkLKjA7/znt+WrXzruLN7UtCXEq3b/zgHWQWJzk/uZ7V09l62ulWeRBEJFiDQr5aZn5gXfg33duaJP9IE05Lkm7uMdxG21rBLVxeW7FnW8e7kchD4nj4w4rbJAwPvqqQPyq09v7AgifL4LWfN5/HRKZgtYKys2KFglGlZBy8Mnk8WKFsw/vD/cshE+63F1hYQ2506MyyPloiuklz188D045maD6755XXo9zq4Wztnl8MuECNqXVHRKRwIkQAIkQAIkQAK1QsCKfZZW1syQPcs+Df3NmY0JzVvRe1R9nKhGfYyFHyywjQf9mAWH2XCY1ubl2/0Nxm06/dgQwHGzNyfBMAZp82zYXwZpdCRAAiRAAiRAAiRAAnVMYNcs+vgZBicweHmedR+Th9sP/NO7Eb9ln2QypaKfpCQTWV+t+cCyj2fdJ6Nin3bzUgZiH5hhD1r2QT9e+2jdRPAnG0YCXO7kCi/N9zcw+cKXw+AOEvDftexgN2yaBEiABEiABEiABEiABEiABOqSQH9rSt4ebZb/9GSXvu7je6DqHuQNySQ25O8da1ORz86uEl/d/Sy/9zCLPG0RJ3s/mpiS1VXvRXhwFIMqMMCk3Uo7rPg/GrKqu75Md072hHWLqZdzzqGcOT7uPcNy5hZPhHUSv4UKf41qTsrFcXnw+IV/OCaM53Wjg96q+KND+ZacMebZucW8eoUS9iLfQjyQFxcmC4tuyzvdnW0S9Xvu2tew7xPKZp8Am2rV7t819npIg2jB5cJ4u8oG08aHtyztBPPKjYdZcNmfteozNpTf58Tzaed5PGwMcfmuhY2P6VsEFvU9UthnAqUOjPbL6aOjWxUqFIJ1vW+8eVKamxqdLeLa4fK1+868UhKPHxoupXhe2Z6uNunqaM1LRwLELC9nF5x5cUic0euGsGuHNrXy5hJDlzJuiLTCrMFBpBV3Vyvn7FI4wpplmEUffNfpSIAESIAESIAESKCWCFixjx2zJ/aR/rX1DXPzDfEO8uDr7UN2opuXZtNtXVfcn8fw7hG4evelWSmq9/C7h7K9BqfD2bh9iROMlzpYW7/UeixPAiRAAiRAAiRAAiQQEwJVEfpg343gJg+CJ+7xxDimUJ7YB0Ifs6mZHyP6SW6JfZIq/PGLfZ6+mPOJfbb6pNgnDzwTSIAESIAESIAESIAESIAESIAE9gCB3x5Py7l+XXFfF9CgqwIBFTMkdfvDc21yor9yFgqqsCc72uWLqVln+92d7ommwcJrah764UT46vVHDw7JkRCLP8G2osTxnOlLZw+rRWm3cAuTPTEml7tx54kr2YgdDo+7V4l3VggkQjSTSed/zxcWl2Xi+ctA6d2N3r7/1NkhhFKtLY0CsUfQlWrNx9bfi3ztvof5cWAyO+8W+mDMA32dYUMvmt7RFm5VC59966rdvx1HvfmJBverhnIt8nS2twhEj2HOL94KK+NKh2WxFRVaBt3o0D616qNis9b83+db96Jb87HtxuG7ZsdCvzCBz764GyoIQc1Tx8bUUmD5v8nB3iEO+ZpaH+sqcF1z9dYjeR5yPRRsr1C8t6dDYMWsHIfrm9O672HudhnfC9tWkeX2bLFt+9dvPwpt46QKuFzXSqEVfBkDvZ0FuV7T4xd3Vyvn7FI4dqp1TfP+N1AJwrlCYuBAcUZJgARIgARIgARIIDYEKPaJzaGoyECeTy2m/817twcWpbV98My3v+NrNCjqQZZLoGPT/H6wrs0La8PXLYMkQAIkQAIkQAIkQAK1QMD99m2XRu564GrWV9QXCMgz+ZvhhMYTxsKPJ/BRSz5q4cdY9MmKfVLGws+W2Of7P/qFXL87aa5+l1fWBYu52j4328a+ah+mXxPGH7jdetXg9ca/JEACJEACJEACJEACJEACJEACJLDTBNK6evg/fb1Lxtr0njdkQu5Oj2FPt68Cq28dbJWvjeULGfY0l8DOP3k2HUjxopgsjhXwozhMsMSkvjD36ukDgknd23VYORyTdccKtHX99uPQbu4+eGasrLgKnD0xHmqVx1XepmFy/GtnDtpojn/34bOceDUiOL4uCx99OhnZJcBaV5HUvYfPyxrqXuRbDFQcmMCy01yI2OfkkVFpdwgtiu0X8ocHwiezz/usCFW7/yj7Uotllpbd1hL69nWUvDuwkvb268f0+X/464swSxrFOltbW5c7eu4NusZMWt585Ugw2ZyjXZbI8goGEuLwXQsMidEQAvhM/OrT6wWvG14/c0jeOAdRb/hnMqT5nOQuFSL89tfPSb8KRcIcrORcvHI3LLvk9K9+6ZhaJuorqZ65vnnjuAz2dTnr4RqrHAGcbQzXc+hjp90tFRevhFh5hMjna7qPzU26CEIJDtcrrnOFbQLXOXG2dGTHWSvnbDveKH7YogAQ+YR9DqK0yzIkQAIkQAIkQAIkUE0CFPtUk/6u9B18gO0X7gTDuzIgdkICJEACJEACJEACJBAvAjv/JL3I/lrhTW6xrMhHE60gJ6EP/T2hjyf2adB4UldKDRP7pDMtcnB8SH72i4/l15efyNTskr6U84t9fEIidF6q2MeUzx01YyRAAiRAAiRAAiRAAiRAAiRAAiQQdwKtmaT8s9fbpCOtI+W97S4dLk9Ydaq7Qb5zvHmX+qzdbuYXlnRl/YW8HcAzou6OaFZ9YBWokMAGbWES+V/72hkZGezJ6ytKAqw+fOOtEzJUQFzwcmZeYNEnzMHST9iq75gE++VXj+pk0sMFJ7v724ZA4htvnQxdof7uA7c1HX8buxG+cz9/kj2OybFDw3ndP5qYChVD5RUOJOxVvgEMOdG4MLn70P1ZxITrb759WjraSjtXHlNLXQdG+3P21UZwTpkPCIuq3b8dWz35i0tbVpP8+9Xe2iyvnXaLD/3lbPjgWL/87ruvSXuRz0DaYbXMtlHMv3XPbU0NYw06CHbW14PzboKl8uNx+a7lj4wpLgLPJmdCf49teXw2f+edVwTWXEp1EAidPDKi1x1npUMFuWEO4tZfnb9e1mcurE28W4Mw5czxcOs8/roYq7m+KWAJCNb55n2W0vz1/eG1NV19L8QN9rtFRCHFy0qGsPOL6w9C68Li0e9841xBoaitrFfzclqtAL37lVOh4iAIoC5drZxIy/a9E34tnbOj7r/LKiTqVtuaZdTxsxwJkAAJkAAJkAAJhBGg2CeMTN2k+wU92KngQwgbt+XqZse5IyRAAiRAAiRAAiRAAsUJpIoX2fkSeJGfv8pqg1rvSegLjXUj9sHVKsqJQPCzYSz7rGssbB3XDqxOrG5wcFA+u3BRQ2ekt6tZDgxhBcGErryGPr05TaZtjWygfaTpnw1UR4ax7GMCiOQ6Uz4kL7ckYyRAAiRAAiRAAiRAAiRAAiRAAiQQGwLDHU3yt4+tyf95eVFkDSvw8952Rw+OLlTSsLYq/9WpFmnaxsTkHR1jzBrHauhtjgnXWKn76YuXkUaL1fCHB3qktaUxtHxPV7t8VS3yzOjq+VdvPZTnk7NqaWRRrULjqVO+a27MyNjwPmNpJ2wyoa21qpNbf/HJNRsN9S/rBFRYIglrD+KFfTpOlHs0MekUvcCKz4nDwzq23uzzs/zuwHTq5Xx+RhVSbqvg6IROeI7i7uhk4u24vci3GK84MLl9Tz8Dh0ecn9cm/Z79llq8ePjkhWAy+RMVy7l+pSCG61drMQfHBgpO0r5x50le/Wr3X+wYVTL/jXOHyrIOFnUMsHZz8+4TM5E67Dx25MCgNDWm9Tz7SM+zMzlN45k/RIoQPxxXsV9PVzSrd/u620y/OY1FjOBc+GJqRvtqL1pjO1ZL4vBdK7qDLLBJ4NPLdwQCMgh6whysC77z5VPmWgG/T7AONavXDS6HV0x9Kgo6MNInI0M9+k4q7G2WVxuWhT74+Iq8mJ51NbftNFhMw3f0xp3H8lhFtOt4QeZzEPjA2iFEt7iuCHOLKvD59PLtsOycdFxP4d2f924vJ0veevWIPHw8KdMzc7K6uq7j8a69vO9n5RhcufFAhlRUBFGPy2XUmtfX3jhhzif4vYD1F7/D2CHuglArrA1bHt95XEvWgoP4pVbO2VF5hi0I8FT3lY4ESIAESIAESIAEap2AFfssrXhier2eTy0sN/Q3ZzYmNG9Fr7v10rVBPcx2w8LXeBRiwubC3+ZbDsG4TacfKwL+mzZ/GIMMxmM1cA6GBEiABEiABEiABEigcgRiIfTB7uBhud5I5O2ZTYev6h5R5Y8R+diCBcU+7boCn1ZbXF43Yp9zZ8/I9OyyvHK0V6tT7GMZ0icBEiABEiABEiABEiABEiABEth7BL51qFVW9B77u58v863Qjh7+BmlqWJN/8uU+GeuKzWOYHd3jSjT+5Om0HN4/mNdUlwp9ojpMLv3ph5/ryuunQ1det23BcsSXzh62UVlaXtFJvEuyuLSik36TZoJ6k04ELcWCxEef3tDJq8WFNXge9qGu3v9bXz9rrFdvDsIXwPgwIRZlX6ooCePC4jiwftLa3Fh0XLAs9MGvr/harG4Qwqook+yX9ThA3LQdtxf5FuMVByaYGH/l5kMj9nGNN6kTziFcwwaLDLAcgcnlKxqGwKcxk1KrPy36nBhT6cMdPmsQoQRdtfsPjmcn41hMa7Bv5yxngDHcvYfPjFAnbF8gIMBmLCyplSWco3H+gnCi2HF0tQkRJCzwpPXzgAnrn1y65SoWmnbz7kRRoc/U9FzepP/QBh0ZcfiuOYbFpAIEPvrshvl9dV2D+Kvhc3vq2JjZIOzF+WlBNwhWGhtT5vcZokXzXstfMSQMyzd/9dEVgSh3Jx3OBdhWVlaz1zlqiUvfvZnrCRVGFxMj4TP964s3tX64pZ7g+GfnFp0WutDX+Aje1WHbchDmwDJjpRzeOv5Sr7N+Wy33ZAoI7g+NDwi2hUVYllw0vzeNeu0HC3NRrv8gYvz82r1KDXvH26m1c3YxIPgd6cA74YDDZ/ZZxEUCAlUZJQESIAESIAESIIHYEaDYJ3aHhAMiARIgARIgARIgARIggR0nEKsZJlbUs7XXZpUBE8XDWI35xD4q+sm6oNgH7Zh/6nfoAoD7hxpU7LOxKfZ5/5MH8s5rWDWUYh/LkD4JkAAJkAAJkAAJkAAJkAAJkMDeI/A3VOxz7fmK/Orpqi6sEX3C3t4jVeYeY9GShqT8vdMqIhmI1SOYMndo96pNPJ92rgAftlJ32MhmdKLmTz64KO9++XRByz7B+pjYia0chxX5P9ZJsPcePY9cHeKd9z+8LF/XFeULTSbFMy+sst9Z3AjFZt+YfPzTX102E1Y3E2MQgKWWYtY0wDBocaCcoe9FvsU4xYHJpSv3jJWEMIsCdh8g7MFEa2ylOAjc3vvl504rWGin2v2Xsi+1UHZSRTGfX7svp46OFhxui4p7sEVxEDTCYkqYhZV93d7JcE6FQ6W6uypMeuXk/oLn3Fv3J0ptNq98HL5reYNiQkECH1+8ZQQ7x9VSXhQHwQqsELosEUapv6yim5+ryCeqxcIobaLMXf3ueEKa/Bq41ujqxLVpdAE13tFBCPXwSWkCXIiXIFiupoPA8Cc/v2isMUHUVMg1NzWq8CnaOcq2g+tWCLUUUc24WjtnFwOL62MIW4MOFqIgEqYjARIgARIgARIggXohQLFPvRzJSPtReHWbSE2wEAmQAAmQAAmQAAmQQK0TyH/qWeU9yl/hDGIfb4POxwh49GFtQ0PCPLTFg9tEIikNuiX1hUoymZIE/FTabKlURl8iNMnoQIc0tfcbsQ9WC4TYZ3llXVcOVAERJt6gZTMBBz0gmk0zYfwp4kz5ImWYTQIkQAIkQAIkQAIkQAIkQAIkQAIxIpDUe+p/+nqbDGDunQpS6CpNICFvD6Xkt/brKiR0JRHAhDzXau6YKFpoNXZXJ7DM8+OfXzDWJlz5lUwzE0lVWAQRS6nu2YsZ+ctfXFJrPbq6foUcLKH87KMv1IJG5dqs0ND0eKiIRyfxF3J3yuAY1t5e4xvGwZ9ebSYQcb33i89lYgcsWMCalvd9WvHvck642v3nDKZOIpeu3pMHj19UZG8gmsTEeVj32AmH9iH2CXMmX4USlXDV/q5VYh/2WhuffXFH/vKDSwLB4E66Ow+eyp//5fmKi3ww5o8u3Ni2VTy77/g+fPjp9bKub3BegKXEajuI7nA9WOljel9FyT9VsTauuWrN1dI5uxjbnk73/dZTFWHRkQAJkAAJkAAJkEC9EbBiH7tf+nwjpY/++tfWN8yqRSrSN9Pe4Js1tU1BLw1Bm2/rB+M2nf6uETDHy9ebK+5K81VhkARIgARIgARIgARIoF4JxE7oA9DliH0g8PHEPilJJSHyUd+IfeBnZKivTUb722VRuuXOzWsq8FmXP/rB5RLFPsHr5sDHgmKfABBGSYAESIAESIAESIAESIAESIAE4k4gnc7IPz7XIW2pdUknitz3xn1nYjS+zkxCzu1LyLcPtxrLNDEaWs0M5cGT/MnieGY0OrSv5H1YXFqRX3xyzVj3qPQETwwGq/FfvHJX/v175wUrpJfrsOr4n2sb1249UhFM+cvCr62tydWbD+UHP/lkW+Mpdz+i1AOzQlYBZuYW5PnUbJSmIpfZS3yjQqk2E4j6MEH6/KXbMqvHfLtOJ6fo5+qFmaC/tKzW6oq4avdfZHg1mf3h+WvbFhdg4vy/f/+8PH46JbDM9uzFyx1hcfPuk9B28TnCeapSrtrftUrtx15qBxZ2fvjTz+SCin5W9Xe1kg7XIhASfXj++o6JYHA+/Pmvr8hnl+/IyjY+y0/0e/jD9z81FoLKYYDv0a8v3NzWGMrp11UHwue/0GP66eXb2x7PrJ6b/krF1B98fHVb12yuce5mWi2dswtxCbs/wO8IHQmQAAmQAAmQAAnUIwGKfermqNoXMvDthp3zh+3OutJsHn0SIAESIAESIAESIIE6JZCK635h4gZeRGw5WNzxYhuiVniw2ADMsOvCnwmdiLSxgRVAU7LesPXCJWubx1RCexD7wF28IXLz+g05dOSw/Os//lT+yX/yiqYmVCCElQs8oRF6xtIGZk0D/aM9bIa1FJpxOwwyZ9zuYkwtjQAOfQHqpTXG0iRAAiRAAiRAAiRAAiRAAiRAAjkETvY1yd8/1S4/uDkvD2ZXRY3f0m2DQFOyQcY70vKdY23S26ILk9gHGttocy9WvXV3Qk4dHdXnNbnWpvaP9EqhydmFWMFyyL/Xyaq9Pe1yYLRfxlQ0lMIDoTIcnls9n5yR+2q94va9CYFgoBJuZWVNzn9+W27ceSxHDgzKUH+PtLY0RmoaK+7fuPtYLWA8VMtA0VfPXwopG5YeaTARCsHyUdjEzLsVsqQRHEa984WVpFLFCdVg4j8usKxz7fYjsw31d+nnfkgGejtLOndOTs/KnfvPjIWWUi1HVLt/P4tyw4tVtJYRPNdgga2f/eoL6epokeOHhvU73mue3xfbN3xuISi4dvuxObf6y0Mk8PU3T4aeC8sVRkJ8s6zsMhmz6LG/S7ml5/VKu2p818LO42Hpld7nWm8Pv/Vf6G8qPg8jg/vMb1b/vo6Szk+WAT5rD55MCoRsT/R6JPf9ly1VWR/fjSsq/L19f0JOHBmRUd2Hlubi1xQQDD+amBJYHCokyo06Wlj6wvcb116jQ7iuaTIWGpPJRB7L4DmlUB/l/ObhnH/15iO9dntqrrOGB7qlO8QaTLBv9AcB2P1H3rUf2irV4TcKxz54f1DKfpfSZ7F2437OjnKMm5sy0qffy6CDaBzfNToSIAESIAESIAESqFcCVuyzpM8S4fT6VC37NPQ3ZzYmNG9Frzv1slNnvhkLP2bOnV7AYhZcg7mQveDslQAAQABJREFUtfmWTzBu0+nvGgFMjYOzvg0jHkxDHpw/3cbtjQrybBh5dCRAAiRAAiRAAiRAAjVIIHjBh12wadZPnP72vzqQynReQ2ZHW7P84X/+1xDccac3EY4+VHCj6SZPszUkG/pw3Utb15WzsK3Jur6IMOE1naCk2+rqiklbXV2WR09n5VeXn0lnalb+o995S/p7WsxOZ9JW7OP16/Vheshe+iKsbuuPY3y+JOf4ffkMRiYwNbMsne0Zc+x6u1sj12NBEiABEiABEiABEiABEiABEiCBaASmF1flz67PyfkJvW9WsY93ZxytLkt5BPAgRecrypGujHxtpFm+Od5sJjfTUFL5n5DXzxyUw/sHcxrA8xpYqplfWMpJLyeS1EVkujpbpEcneGKSZ0d7s6TTKTP5NK0CIEzCxARJ9IVtYXHZ+HMafvZiZsdW4Q/uS2d7i+zrbpemxrQ06oR0+BgbxjQ7v6iWUBZlTn2Mq9wJ78E+91KcfPOPdrWZNDdmpLW1UVqaGgUTeO0G3SS+k962rN/JFZmZXTDfg/y9KD+l2v2XP/L41cT5qquj1YgLWlVgAJFBKpXQ8+eqQGyCY/lChVovVDhZ6NoD5+sDY336jLjFfB4gmkHd51Mz8kjFE+VMuIcY6be/gUXAch3Ord//8ce5iTsUq/Z3bYd2q66bbcykZHigR68bWvX3OGN+k62P32Kcr/DZXFha9ny9doDIZeL5S++9VgXp4NrzO7/3trPF/+/f/cJ5TdCu7/ggVsL3EePGdc/K6qoZ66KOFdcVT55Oy5q+a9srDuf8fhWY4tiZay09b83ptVVzc8Y7T6k4Z25+SSAYr5SwO65s43zODmMGUem5k/vzsj+5dEuuq3iUjgRIgARIgARIgATqncCaCvyt2Af7mmhoWNVLWSP2QRxiH+vrc5XsrbeXZtPhW2fL2zj9yhB4Mb2U+t//7dXRrqWP/+TWwuHfvfin/+3/qC3DlDA2rNi0rBseeGNb1A2mrxG2PtIQRzmURz2ovLDhBg4bjq//Zi57vDWVjgRIgARIgARIgARIoCYJxNaiD2hiwoIR2+SgDVj2gURHX/LB+g7eO8DID174etZ8cE27tYtryFAHyz5vqj833yrf/9EH8gd/611p0pczyyu41oXYx+vX9K8puL3Z8P5ouyr2QTPeHw0UcOiPYp8CgErL8o5eaXVYmgRIgARIgARIgARIgARIgARIIBqBzqaUvDHYJHMrGzK7vC4zeo/MW9po7GwprKLY25yQ1wca5fVBnciszxfotkfg2q1Hcmh8wDwjsi3heQ2s+ly+/sAmle1jEuvzyVmzuRqJy6Od6Zl5wUa3MwTIN59rtZlggjw2kZn8we1CSrX734Vd3LUuIHh4rCKH7Tqcr2/cebLdZnLq4/fF5WBtbLdctb9ru7Wf9dQPRGqw8HPrXm3uFcSR2Oi2COCcD+tFdJ6YNq7n7LDjM673BUG3qpY2d/NcHuyfcRIgARIgARIgARLYTQK07LObtCveF14g2A2N27D1bZr1/elIK+ZQnmKfYpSYTwIkQAIkQAIkQAIxJqCymHg7TN7IdxD7eBvyTBmNJyD4afC2hC6hm0ymdEtKMpXOhlOS0HgqlTFinwPDXXLq6Jh893vvyaK+nMGVLcQ++vw3ZwKJRjzhkBmKJyEyl9ben/zh+VOc4/cXYDgKgalZvNgXmc76UeqwDAmQAAmQAAmQAAmQAAmQAAmQQGkEjnRn5CvDTXK8J63LYNCVQgCPDNRQsLwx0CynexulqylZSnWWDSEwo6upuyYbjg/nT+gLaWJbyRS7bQsfK5MACZBAbAmk9P3B+Ehf3viw8NhtFXHQkQAJkAAJxJ9Ah1qogtW4oIPIB2IfOhIgARIgARIgARLYKwSs2Mfur1q9TS0sS79a+0kjTe91zYw3+Hrbm52I56X58219W97G6e8Igexx2Gwbcbsh0YaD5fx5CNORAAmQAAmQAAmQAAnUMYGamLdTqtgnkUgawQ/EPghDAGTFPikV/VixTzKVks6Odjl5ZNQh9tE7G5+YqLDYx3VN7fvUUOzjg8EgCZAACZAACZAACZAACZAACZBAXAmk1QLNeEdavjzUJH0tKWlKFbnfjeuOVGFcPc1JeaXfs+Qz0KrPIoiuYkcBVn2CrqO9xTmpL1iOcRIgARIgARJwERhTwWg6lS/Kffr8pcwtLLmqMI0ESIAESCBmBPY7BJsY4vXb+fcPMRs6h0MCJEACJEACJEACFSdAsU/FkVazweDbBRuHb8PVHB/7JgESIAESIAESIAES2CUCNSH0AYtSxD4o6xL7JIyFn5Ra9AmIfTpdYp8NtewTVexjRlj4kFHsU5hPkdzJGc+iz8u5lSIlmU0CJEACJEACJEACJEACJEACJLAdAl2NCTnSk5GvjTZJf0tSMlSsFMXZqqZ8xjtS8rWRJhltT0lrpmYetxTdtzgUePJsWqZn5vOGcmA03xJDXiEmkAAJkAAJkICDwOH9A45UkZt3nzjTmUgCJEACJBA/AuMj+VY+nzydElgFpSMBEiABEiABEiCBvUiAYp94H/Vvvj70HCOcvPPBjwIjDQp4bNyKemzcVrPpNk6fBEiABEiABEiABEigTgnU1MyTHAs7mwekwYiAYLUHziuTyKblW/bxi31g0QeiH2ydHW05ln3Wta3lFYp9DNSY/JnKin2mZz3RT0yGxWGQAAmQAAmQAAmQAAmQAAmQQF0RSKiwp1et0/zNw61yQgU/HSr8odbHfYjxNk2NIBlB1NneRnlNLfq0ZviOzU1re6lXbjzMa+DgeL80Nabz0plAAiRAAiRAAoUIHDs4JN2dbXlF5uYX5f4jM+cmL48JJEACJEAC8SIAaz4tzY15g7pGaz55TJhAAiRAAiRAAiSwtwhQ7BPP472vq2nly6f7XjbK7OyD83/ysY7S9SKhWJorP547zFGRAAmQAAmQAAmQAAlUhEBNCX3sHudb98F1LKz4eAIfXAo3NOSLfZJq0QdlIPZJJJNG4IM0bKlUJiv2GZHvfu89WVpeFZfYx/St1nnwTzsx/eIvop7bDNiEXJ+WfXJ5MEYCJEACJEACJEACJEACJEACJBA7AhD7pJMJ+cZYk7wx1CiNGqbYJ/8wpRRKd1NCvrm/Wd4cbvSeOfC+Px9UBVLuPHgqL6Zmc1pK6bOdU0dHc9IYIQESIAESIIFCBHq62uTsiXFnkau3HsmGM4eJJEACJEACcSKA+9Uzx8fyhvR4YlIeTUzlpTOBBEiABEiABEiABPYaAYp9auqIByca2rj17c4E4zadPgmQAAmQAAmQAAmQQB0TqEmhD45HvtjHpJp0T4xTWOyTTHhin2TWoo9n3Qdin3a17BMu9tns24h9zEDwx9P5bF5SbwZQPN9x0k8+kwgpU1lLPtaPUIVFSIAESIAESIAESIAESIAESIAEyiCAu1pYqhlsS8urfRl5tT8tLWldUKOMtuq1SlLv7bvU2tHbw01yvDstXU2wKlyvexuP/Tp/6ZZsbOROwT441i+tLfkrecdjxBwFCZAACZBAtQicUzHPN98+LUcPDEr/vg4Z6O2Us8fH5Z23ThphbnBcS8srcuvuRDCZcRIgARIggRgSOLJ/MM+az+rqmvz64s0YjpZDIgESIAESIAESIIHqEKDYpzrcY9Ar31LE4CBwCCRAAiRAAiRAAiRQKQKpSjVUjXYg6AlO8DCim+wl64ZZf88T4SQSSVlXEz3qaar+UYf8jaRuOkkkacp6aX6xz+/91tvS39MiyyuYSNIgKZ3phPKmb6RoeAMzeTRbczRsGjZlTaKGnM7UyZ2c4izHRBIgARIgARIgARIgARIgARIgARKoEoE2FfeMd6bl7bV1mZhfl4frG7KwyntZHI7WdIOMd6TlKyr06WtRS8FU+ez4p/S5WvS5++CZ7B/t2+wLlpvPHBuXX56/tpnGAAmQAAmQAAmkUknp6+kwWxQaV28+lDW8QKAjARIgARKINYG0nt+xYGPQXbx6T+YXloPJjJMACZAACZAACZDAniZgxT5LK2uGw/rGRmphuaG/ObMxoXkrOv9Np7/pzDf1s/Pt9OG/CZuXADbfQgzGbTr9HSEQfBETjId1GrVcWH2mkwAJkAAJkAAJkAAJxIhAzVr0sQwhuMl3Ku7RdLthSV0vrKsPNyR0xb6kCn6SkkymvC0FPy2eVR/46U3LPt//0Qdy7d6kkQEtr6yLLghl2kKfpm+07UWQkg0jAc41Ni+Hf0snMDnjPaCfzlr2Kb0F1iABEiABEiABEiABEiABEiABEiiVQHdTSk72Nssbg02yr1nXC3Heh5faau2XH2pNyVeHm2WkI2OsHdX+HtXGHnz2xR3Bat1+Nza8T7o6WvxJDJMACZAACZBAZAITz6blixsPI5dnQRIgARIggeoROH54WDKZdM4AXuiCANdvPcpJY4QESIAESIAESIAESMAjYMU+locn9pH+tfUNc1HliXxU3qNiH6x77ZUzy1yboM239YNxm06/ZAJWkGN920CxuC1HnwRIgARIgARIgARIYA8QqHmhD46REdzkHSxP3LOZrxORsMqrJ/TxxD4NGk9awY9D7JPOtMjB8WH52Qcfy68vP5Gp2SW17OMX+2T7KFfsw8lReUeNCSRAAiRAAiRAAiRAAiRAAiRAAvEj0JZJyO8fbZWzvRD61MWjhPIh4/mCbt861CxfHWuSRrX8S7d7BBaXVuTy9Qc5HeK50Jnj4zlpjJAACZAACZBAFAKLS8u0ChcFFMuQAAmQQAwINDWm5djBoZyRrKvV2Y8+u2EWbMzJYIQESIAESIAESIAESGCTAMU+myiqHtCZhkEhD8Zk0/y+Dbvyq74fHAAJkAAJkAAJkAAJkMDuENAZOvXhMKlDVw3I2xmIe9bX140YCLleHOKgDWPNB2vAJvNqeQkdbd5kncHBQfnswkVNPCO9Xc1yYKhDwwlJ6WQedKldmytuLG2gRk1NRHOMMVPvUhzt5I/N9GLKh+SZAvxjCUBo1aKTy6Zo0ccioU8CJEACJEACJEACJEACJEACu0YA991//3SH3Jh+IVenCtzn7tqIqtGRt9+/f7hJvjJCCzLVOALo8+qth3JwrF/aWps2hzDU3y29Pe3y7MXMZhoDJEACJEACJFCIwOT0nE4Ovy4QkdKRAAmQAAnEn8DpY2NmAUf/SK/cfCDTM/P+JIZJgARIgARIgARIgAQcBKzYZ2nFs5buWfZp6G/ObExo3gos9ahTD9Z8sPA1JrqZsJnUZvNt08G4TadfNgHX5EF/mg3Dt+GyO2NFEiABEiABEiABEiCB2iBQN0If4M4X+3gTcGy68bPlEomkCoDWVPijvqaFin3am3H/IovL60bsc+7sGZlWockrR3u1FsU+CmFXXHd7Rrp0W1xclp4uYz12V/plJyRAAiRAAiRAAiRAAiRAAiRAAlsEsHjGv3irW/7djZdy4cW6rKxt4JWfKVDszZJXynsD5d2tb7XrCtky/nqucjbNX87WtXku35bx13OV20rbkO6mpHxzOCOvDlPks8Vl90NYtfvDT6/JyOA+Sae2nuhk0nX1mGv3wbJHEiABEqgjAjOzC7K8vCKZTO6zZCwKNju3KDfuPpEbtx9zZkwdHfO9uCu4/j5/6ZZ0tOdfm+qku72IhPtc5wSePn+Zs4e4L/j82v2cNEZIgARIgARIgARIgATCCVDsE85ml3Nwwxa8abNp1seQbNiWtb7Ng09HAiRAAiRAAiRAAiRQxwTqbgaEFfVsHTOzyoCJ4sWGmYCkE5NU5WOs+9hyQbEP2jH/1O9oE9k/1KBin41Nsc/7nzyQd14b0eoU+1iGO+kfGGozdy/z80uSzmR2siu2TQIkQAIkQAIkQAIkQAIkQAIkUIBASyYpf+dkt/ydAmWYRQI7TeD55KxgoyMBEiABEiABF4FrKuLB1trcqGKflFqASMiCLiKF58v+WTGuukwjgVoigM85HQnsFQJ3Hz4TbHQkQAIkQAIkQAIkQALlE6DYp3x2O1TTinls8/axRdBHvi1r82wd+iRAAiRAAiRAAiRAAnVKQBUv9ecg0sl1EPt4GxYaNgIeFfs0NCSM2AcrEsOyT4NuySQ2ffGXwpY2WyqVkfa2Jhkd6JCm9n65cOGSrK6tC8Q+yyvrGlYBkenT9oEe1Nk0E84dkTOWN25nqT2ZyDuUPXnYudMkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkUDaBuYUlmZyek2cvZmSOIp+yObIiCZAACZAACZAACZAACZAACZBA/RCwYh+7R+sbG6mFZelfW98wZnF1IW0z7Q2+WVPbFPTSELT5tn4wbtPp5xK4evelMcfae/jdQ9mc4HQ4G4dvNxT1h7NVI3m2vUiFWYgESIAESIAESIAESCB+BOpS6APM5Yh9IPBJQOSDLeGJfVJG7JMSiH2G+tpktL9dFqRL7ty8ZsQ+f/SDyyWKfYIipMCHgmKfABBGSYAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAEKkGAYp9KUIzexvOpxfS/ee/2wKK0tg+e+fZ3fDWtiMeKcmwcRWyaP2zTbDnr+8sEw4jTkQAJkAAJkAAJkAAJ1CCBuhX6uI+FZ3HHiIDyLPsks9Z91FerPtiM2EdFP0Gxz5nDPUbsc/P6DRnpb5N//cefytPJhaxlH69nrw9r2QdpuWH3+LKpFPsUxMNMEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiCB8ghQ7FMetwrWsqId26SNB8U7/rgtS58ESIAESIAESIAESGAPEKhroU++VR8c0TCxD9ITm2Ifz7oPBD+ehR+IfSD+gWWf4b52gdhnerVNIPb5ytlB6WhrzFr22bImtCX2Maoir29vCCaMYKiD2IeCn1A8zCABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiiPAMU+5XGrYC0r4vGLfPzN23yk2TL+fIZJgARIgARIgARIgATqmEBdC31w3CKJfVRQ05DwRD6bYp9kQozYB+k+sU8ypcIfFf0M9bXJmyd7JdHcJZ9duCiLy6vmanp5ZV0t+2z1uy2xj7cDdfzx466RAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAlUgwDFPtWgXrTPQqKeQnlFG2YBEiABEiABEiABEiCB2iFQ90IfHIqiYh9bRgU/CRX2QOxjBD9ZsU9SLflA3APhj7X0A8s+EPu8fWZATh0dk+9+771QsY/5OEBMpP/wH3+yngmb/EJ/aNmnEB3mkQAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJlEGAYp8yoFW+CgU8lWfKFkmABEiABEiABEigpgnsCaEPjlCpYp9EIrkp9kEYAiAr9kmp6Ceh4h+IfWDhp7OjXU4eGXWIfTZMv5t9FxT7GOlP+IeJYp9wNswhARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIoiwDFPmVhq2Ql/+RBf7iSfbAtEiABEiABEiABEiCBGiKwZ4Q+OCabgpucA6TWdSDAyQppjJ+Nu8Q+iaxVnzyxT6dL7LMhq2tRxT5mhDkjy4tQ7JOHhAkkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQALbI0Cxz/b4lVE7iqAnWCYYL6NbViEBEiABEiABEiABEqgFAntK6IMD4hf1bB0gT+gDqz1bZRKmbDGxDyz6QPSDrbOjLceyz7o2trxCsc8WZ4ZIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgATiSIBin107KlawA9+/YQD+PBu3aYjTkQAJkAAJkAAJkAAJ7AECe07oY4+pteBj4/Z6GWIfz6oPREEa1rhf7JNUiz4og7REMmkEPkjDlkplsmKfEfnu996TpeVVcYl9Nq0G4ZrcWOlRoREGsnk5vhnYGp4/tAct+xQh4qfDMAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQQBkEKPYpA1plqmCKnJ0mZ8M2XkoP5dQppX2WJQESIAESIAESIAES2AUCe1boA7b5Yh+TatI3xT567YxwnthHRT7JhIp+4Gct+njWfSD2aVfLPuFin82+tV1zVU2xD5DQkQAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJVJkAxT47dgD8IhyE7WY7tPl+3x9GOVvH+jbNtkGfBEiABEiABEiABEigDgjsaaEPjl8UsY8WyhP7QOBjtqxlnwSs+qTsls4R+zx9MS8b2tfyyoasrm316YmJKPaJ8j2amlk2dyjTcytRirMMCZAACZAACZAACZAACZAACZAACZAACZAACZAACZAACZAACZAACZAACZAACZAACZAACZAACZBAmQQo9ikTXLRqVqTjF/G40tBaMD1KD7bdKGVZhgRIgARIgARIgARIIIYE9rzQB8ekmNhnU5BjBD8JLZ8wFn6MNR8IfKzIJ5k2Yp+UWviBlR9r2ef7P/pArt2bzIp91isr9onhh2onhjQ1u2yanc76O9EH2yQBEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEvAIUOyzI5+EoAjHCnlsZ8F8mw4/WNafxzAJkAAJkAAJkAAJkEAdEaDQJ3swC4l9UMSKfRIJK/TxxD4NGk+qdZ8wsU860yIHx4flZx98LL++/ESmZpfUso9f7ONZC9IOzFU4fFyPm6v1zUv2zUB2tD7PlPfFGSQBEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiCBChCg2KcCEKM14U0c9MrasJ04aOPRWmIpEiABEiABEiABEiCBmidAoY/vELrFPqLWezxMQbEP4olEUhp0CxP7dLQ1S3tbqwwODspnFy7K9XtTcvvRS4p9fNyjBCdnPIs+L+dWohRnGRIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIggQoQoNhnexC/+frQc7QweeeDHzlasmIeZFlBj02zcVvNpts4fRIgARIgARIgARIggTolQKFP4MDmi328a2ObbsU+VuQDEVAhsU8ylZKO9mbp39cuXT39RuzzbGpBPr32LCv22fCsBcGKD6zz6GZ6NJZ6bNgOssB1uilvy9EnARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIggcoQoNinPI77uppWvny672WjzM4+OP8nHwdasRMCrR/I3owWy98syAAJkAAJkAAJkAAJkEB9EKDQx3EcrahnK8sT4dh0yG8aVODjiX0g9HGLfVKpjKRSabPBss/+oS5pauuTCxcvycrqmrz/yQOKfbYgFw1NZa36TM961n2KVmABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiCBihCg2KciGK1ox/q2URsP8205+iRAAiRAAiRAAiRAAnuAAIU+IQfZinq2sn1iH72U3hL7WKGPW+yTVKEPNoh+2tuaZHSgQxpV7HPx4ueyurZepthna1R5oTq27DOVFfhYP2/fmUACJEACJEACJEACJEACJEACJEACJEACJEACJEACJEACJEACJEACJEACJEACJEACJEACJEACJLBjBCj22TG0223YCoS22w7rkwAJkAAJkAAJkAAJxIAAhT4FDkI5Yp9kMqXWfpICP5nQLZUyFn08PyNDfW0y2t8u8xudcvfWdSP2+aMfXC7Rsk+Ra/I6FvsUOFzMIgESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAES2GECFPvsKOCNMlsvt16Z3bEaCZAACZAACZAACZDAThKg0KdkuoUs+yQlkUgYkU8iqWHdjNhHRT8pY9kHvif2OXO4x4h9bt24ISP9bQKxz9PJBRX+bIjV6RihkUaMrCf7xx8uOHTbSMFCtZU5ObNsBjydtexTW6PnaEmABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEigPghQ7FP2cbSCHOvbhsLiwXRbnj4JkAAJkAAJkAAJkEAdE6DQp8jBzbfqgwphYh+kJ4zYJ5G16uMJftSyT1bsgzjEPsN97QKxz9RKm0Dsc/Jgj3S0NWYt+2gPWaHOlthHJT7liH3qUPBT5JAxmwRIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIYIcJUOwTHbDOLHQJdmya37dhNG7D1o/eIUuSAAmQAAmQAAmQAAnUNAEKfSIcPiu6yS0aEPvA8o5a84FFn02xTzJr3QfpKvSxYp9kSsNq4Weor03ePNkrDU1dcuHiJVlcXjVX5ssr62rZp0JiHwy6TsQ+U7NL5hBM0aJP7keRMRIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARKoAgGKfbYN3SXi8aeFhbfdMRsgARIgARIgARIgARKILwEKfSIem6JiH23HWt+xYh8j+MmKfZJqyQfiHoh9sFnLPhD7vH1mQE4eGZX/50/fDxX7mGFCTASz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+7Y+7bV82rdROtfL83l7y+eaed7a5Xp53trlsdfz6bxdrpfn8/aWzzXzvLXL9fK8tcvjXC/PW/tcL89buzzO9fK8b+81fdq3ydO5Xp639rlenrd2eZzr5Xnf3mv6tG+Tp3O9PO/be02f9m3ydK6X5317r+nTvk2ezvXyvG/vNX3at2lLe02fztt6TZ/O2+V5r+nTeTuv6dN5uzzvNX06b5dr5vm8veW9pk9bvcW5Xp63dnnsNX06b5fr5fm8veW9pk9bvcW5Xp63dnmca+Z5a5/r5Xlrl8dez6fzdrlens/bWz7XzPPWLtfL89Yuj3O9PG/tc708b+3yONfL87691/Rp3yZP53p53trnenne2uVxrpfnfXuv6dO+TZ7O9fK8b+81fdq3ydO5Xp737b2mT/s2eTrXy/O+vdf0ad+mLe01fTpv6zV9Om+X572mT+ftvKZP5+3yvNf06bxdrpnn8/aW95o+bfUW53p53trlsdf06bxdrpfn8/aW95o+bfUW53p53trlca6Z5619rpfnrV0eez2fztvlenk+b2/5XDPPW7tcL89buzzO9fK8tc/18ry1y+NcL8/79l7Tp32bPJ3r5Xlrn+vleWuXx7lenvftvaZP+zZ5OtfL87691/Rp3yZP53p53rf3mj7t2+TpXC/P+/Ze06d9m7a01/TpvK3X9Om8XZ73mj6dt/OaPp23y/Ne06fzdrlmns/bW95r+rTVW5zr5Xlrl8de06fzdrlens/bW95r+rTVW5zr5Xlrl8e5Zp639rlenrd2eez1fDpvl+vl+by95XPNPG/tcr08b+3yONfL89Y+18vz1i6Pc70879t7TZ/2bfJ0rpfnrX2ul+etXR7nennet/eaPu3b5OlcL8/79l7Tp32bPJ3r5Xnf3mv6tG+Tp3O9PO/be02f9m3a0l7Tp/O2XtOn83Z53mv6dN7Oa/p03i7Pe02fztvlmnk+b295r+nTVm9xrpfnrV0ee02fztvlenk+b295r+nTVm9xrpfnrV0e55p53trnenne2uWx1/PpvF2ul+fz9pbPNfO8tcv18ry1y+NcL89b+1wvz1u7PM718rxv7zV92rfJ07lenrf2uV6et3Z5nOvled/ea/q0b5Onc70879t7TZ/2bfJ0rpfnfXuv6dO+TZ7O9fK8b+81fdq3aUt7TZ/O23pNn87b5Xmv6dN5O6/p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nAtmggACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgggsIEFCPps4JPPoSOAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCNSPAEGf+jkXzAQBBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQGADCxD02cAnn0NHAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBCoHwGCPvVzLpgJAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIDABhYg6LOBTz6HjgACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgggUD8CBH3q51wwEwQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAgQ0sQNBnA598Dh0BBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQKB+BAj61M+5YCYIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIbWICgzwY++Rw6AggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIBA/QgQ9Kmfc8FMEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEENrAAQZ8NfPI5dAQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAgfoRIOhTP+eCmSCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCGxgAYI+G/jkc+gIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAL1I0DQp37OBTNBAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBDYwAIEfTbwyefQEUAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEE6keAoE/9nAtmggACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgggsIEFCPps4JPPoSOAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCNSPAEGf+jkXzAQBBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQGADC3g28LFz6AgggAACCCCAAAIIIIAAAggggMCGFGiN+qStySfNEa+EA25xuRoklc7JaCwtt0fTMnAnKUn9moEAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCwsgIEfVbWm70hgAACCCCAAAIIIIAAAggggAACqyIQDnrk/u0R2b05ItGQRzxul+j/i6uhQUT/P58XyeXyktVbOpOTvsGEnLg4IteHks7zqzJpdooAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCGwwAYI+G+yEc7gIIIAAAggggAACCCCAAAIIILBxBDzuBmnR9p49m8OyoyckEQ37BP1uDfhosqfU0OVtBHSZXT63dLX45dZwUs71jkvvQFwSKVp+SrHxHAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgggsFQCBH2WSpLtIIAAAggggAACCCCAAAIIIIAAAnUi4PO4pFNDOjs13LOpPSBNYa8T8ql1ehb38XtdevNJRNt/Opp90n8nJVdvxeRaf1zGYplaN8VyCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAvMQIOgzDywWRQAB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gAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgACBqgKCPlV5Ki8U9qlsYwkBAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgMDsBQR9Zm92fgthn/MU7hAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECMxTQNBnnoDCPvMEtDkBAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgEBRQNBnAZ4Iwj4LgGgXBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAIE1LiDos0BPAGGfBYK0GwIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIDAGhUQ9FnAgRf2WUBMuyJAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIrDEBQZ8FHnBhnwUGtTsCBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAwBoREPRZhIEW9lkEVLskQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECKxyAUGfRRpgYZ9FgrVbAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgMAqFRD0WcSBFfZZRFy7JkCAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAisMgFBn0UeUGGfRQa2ewIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIDAKhEQ9FmCgRT2WQJkhyBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQI1LiAoM8SDaCwzxJBOwwBAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAoEYFBH2WcOCEfZYQ26EIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAjUmIOizxAMm7LPE4A5HgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIEKgRAUGfZRgoYZ9lQHdIAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgMAKFxD0WaYBEvZZJniHJUCAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAisUAFBn2UcGGGfZcR3aAIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIDAChMQ9FnmARH2WeYBcHgCBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAwAoREPRZAQMh7LMCBkEXCBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQLLLCDos8wDUDq8sE9JwpQAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgsDYFBH1W0LgL+6ygwdAVAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgMASCwj6LDH4dIcT9plOyHICBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAwOoUEPRZgeMq7LMCB0WXCBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQKLLCDos8jAc929sM9c5WxHgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIEKhNAUGfFTxuwj4reHB0jQABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECCwwAKCPgsMutC7E/ZZaFH7I0CAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAisTAFBn5U5Lhf1StjnIg4PCBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQKrUkDQp0aGVdinRgZKNwkQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECcxQQ9Jkj3HJsJuyzHOqOSYAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBBYGgFBn6VxXrCjCPssGKUdESBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgRWlICgz4oajpl1RthnZk7WIkCAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAjUkoCgTy2N1qS+CvtMwnCXAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAjUlkBdbXVXbwkQIECAAAECBJZKQNBnqaQX4TjCPouAapcECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQGBpBIR9lsbZUQgQIECAAAECNSUg6FNTw3VpZ4V9LjUxhwABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQI1IiAsE+NDJRuEiBAgAABAgSWSkDQZ6mkF/E4wj6LiGvXBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIEBgcQWEfRbX194JECBAgAABAjUlIOhTU8NVubPCPpVtLCFAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAitcQNhnhQ+Q7hEgQIAAAQIElkpA0GeppJfgOMI+S4DsEAQIECBAgAABAgQIECBAgABRF/uqAABAAElEQVQBAgQIECBAgAABAgQIECBAgAABAgQIECBAYP4C5YI95ebN/0j2QIAAAQIECBAgUFMCgj41NVzTd1bYZ3ojaxAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgWUWyKGecsGecvOWuasOT4AAAQIECBAgsJQCgj5Lqb1ExxL2WSJohyFAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAnMXEPaZu50tCRAgQIAAAQKrVkDQZ5UOrbDPKh1Yp0WAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECq0GgVLlH2Gc1jKZzIECAAAECBAgsoICgzwJirrRdCfustBHRHwIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgMF4K9wj7eDIQIECAAAECBAhcIiDocwnJ6poh7LO6xtPZECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgMCqEBD2WRXD6CQIECBAgAABAgsvIOiz8KYrbo/CPituSHSIAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBNa2QL5+s1rYp1TtJytNvr+21Zw9AQIECBAgQGANCAj6rIFBzqco7LNGBtppEiBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgEAtCOTwTr6Gc2rgpxT+yecwOeAz+X5ephEgQIAAAQIECKxSAUGfVTqw5U5L2KecinkECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQGDJBSYHfEr3cycmB31Kj0udE/YpSZgSIECAAAECBFaxgKDPKh7ccqcm7FNOxTwCBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQILBEAuPjObCTr98sBXwmP86dEPbJChoBAgQIECBAYI0KCPqswYEX9lmDg+6UCRAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQGAlCZSCPpPDPqXAT+5ntbDPSjoPfSFAgAABAgQIEFhgAUGfBQatld0J+9TKSOknAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECKxCgYZ0TpPDPpMDP5PvTw785Pu5laYTj/wkQIAAAQIECBBYVQKCPqtqOGd3MsI+s/OyNgECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQ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AgQIECDQiICgTyNKxhAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBBosYCgT4uBrZ4AAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIBAIwKCPo0oGUOAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECgxQKCPi0GtnoCBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECjQgI+jSiZAwBAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgACBFgsI+rQY2OoJECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQINCIg6NOIkjEECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIEWiwg6NNiYKsnQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAg0IiAoE8jSsYQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQaLGAoE+Lga2eAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAQCMCgj6NKBlDgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAoMUCgj4tBrZ6AgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAo0ICPo0omQMAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgRYLCPq0GNjqCRAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECDQiIOjTiJIxBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBFosIOjTYmCrJ0CAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQINCIgKBPI0rGECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIEGixgKBPi4GtngABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgEAjAoI+jSgZQ4AAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQKDFAoI+LQa2egIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQKNCAj6NKJkDAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAIEWCwj6tBjY6gkQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAg0IjChkUHGECBAgAABAgQIECBAgAABAgQIEGiWQFtbSlM7J6dpXVNS55RJ6cLFnnT23IXUffZ8ZdrT29usTVkPAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQGBUCQj6jKrTZWcJECBAgAABAgQIECBAgAABAqNLYPH8WemmVYvTwnkzK8GeaV2TKyGftkj71GgR+tl76Gjas/9o2n0gTw8erYSAagw3mwABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECAwZgQEfcbMqXQgBAgQIECAAAECBAgQIECAAIGRIbB00ZxKuGfNqiVp1vSuAe/UlMkT06qlCyqPWLivry9t230ovbrpvfTO9n2pt7dvwOu0AAECBAiMHIFH7l6dblu9rN8dOn/hYvrzf3kqqe7WL4+ZBAgQIECAAAECBAgQIECAAAECBAgQIECAAAEC40BA0GccnGSHSIAAAQIECBAgQIAAAQIECBAYDoHb803bn7zvpjRjWmdTNxfVf65btqDyON19Lr329s707PrN6dz5i03djpURIECAwPAIdHVOSnNmTq25scmTJqQzZ8/X7NdBgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAYCwLCPqM5bPr2AgQIECAAAECBAgQIECAAAECwyCwaN7M9MVHbktRyafVbWrn5PTQnTekCBX97Lm30pvv7m71Jq2fAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIDBsAoI+w0ZtQwQIECBAgAABAgQIECBAgACBsSUwZfLE9Ml716S7b16Z2tvbhvXgpnVNSd/47N3pzpuWp+898Wo6fqp7WLdvYwQI1BeIYN71yxfUHLj7wNF0+Nipmv06CBAYGQKu5ZFxHuwFAQIECBAgQIAAAQIECBAgQIAAAQIECBAgMH4EBH3Gz7l2pAQIECBAgAABAgQIECBAgACBpgnMmTk1/f7XHkozp3U2bZ2DWdG118xPf/zrj6T/+YPn06EjJwezCssQINAigbmzpqWvffqummv/4a9eE/SpqaODwMgRcC2PnHNhTwgQIECAAAECBAgQIECAAAECBAgQIECAAIHxIdA+Pg7TURIgQIAAAQIECBAgQIAAAQIECDRLYMGc6ekPv/7wVQ/5FMczfWpnZX+WLppTzDIlQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECIxKARV9RuVps9MECBAgQIAAAQIECBAgQIAAgasjsHj+rPR7X3kgdU6ZNKAdOHvuQtq0bW/ae/BoOnXmXDp5+mzl0X3ufJoxdUqaPWNqmpUfUSlo9oyutGLJvAFto3PypPT7X30w/fV3n61sY0A7ZzABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAYIQICPqMkBNhNwgQIECAAAECBAgQIECAAAECI10gKub87pc/kSZPmtjQrvb09KYtOw+kDZt3p83v7U/xur929MSZFI+UDl3unjihI91987XpE7dfn6bnIFAjLZb55ufuSf/1n55M585fbGQRYwgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECI0pA0GdEnQ47Q4AAAQIECBAgQIAAAQIECBAYmQKdkyem3/z8vQ2HfKJyz3d/sT69f+zUoA7owsWe9MLrW9PLG7an29csTw/eeX2l6k+9lc3K1YC+8sk70r/8dF29ofoJECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAiNOoH3E7ZEdIkCAAAECBAgQIECAAAECBAgQGHECX3z09jStq35lnaja8+RLm9Kff+vpQYd8qg++p7c3rd+4I/2Hv/1FpTJQdV+t52uvuybdvnp5rW7zCRAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIjVkDQZ8SeGjtGgAABAgQIECBAgAABAgQIEBgZAjddtyTdfP01dXfm7LkL6S++/XR65pXNqa+vr+74gQyI9X33ifXpne37GlrssXtXp7a2tobGGkSAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQGCkCgj4j5UzYDwIECBAgQIAAAQIECBAgQIDACBSY2jk5femR2+ru2YWLPenvfvRC2nfoWN2xgx0QYZ9/+em6tH33obqrmDm9q6FwUt0VGUCAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQGEYBQZ9hxLYpAgQIECBAgAABAgQIECBAgMBoE/jcg7ekrhz2KWu9vb3pn3/yctq9/0jZsKb09eRt/cO/vtjQth644/qmbNNKCBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQLDJSDoM1zStkOAAAECBAgQIECAAAECBAgQGGUC06dOaagqzk+feytt2Xlg2I4uqgd96+frUlT4KWuL5s1MyxfPLRuijwABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECAwogQEfUbU6bAzBAgQIECAAAECBAgQIECAAIGRI3DPzStTe3tb6Q7tf/94WvfmttIxreg8frI7bd9zqO6qVy2dX3eMAQQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgACBkSIwYaTsiP0gQIAAAQIECBAgQIAAAQIECBAYOQId7e3pzrUr6u7Qj59+I1fWqTusJQNe27QzrVq6oHTdy1pY0SeMZkybkqZ2TUnTOifn6eTUNWVy6untTafPnEunu8/mx7l0Kj8/efps6X5ezc5JEyfk4+hMM3IFp+lTO/NjSurL/4t9PnGquzI9euJ06u0d2omO9cZ2ZsZjelea0NGR192djudtHD95pjLt6em9mhQf23ac49kzui6d43x+p+VzPXnShHT2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gXpBnyuXqw74VD8vqvkUQZ+YVoI+eXqhEvbZveHPipWp7FNImBIgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBC4JNBI0Keo5lNMC7t4HQGfKx9F2KcI+lyq7LP+B8+fFvYp7EwJECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIfESgkaDPRxbIL6or+VQ/L6vqU4R9XhD2uZLTawIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIpNRr0Kar5VE+vDPlUV/a5sqrPhYwdYZ8L76//gbCPdx4BAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgACBKwQaDfpUL3Zl2CcCPjGvv6BPEfiJaaWqT54K+2QEjQABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgEC1wECCPkXAp3r54nkR9qkO/BQhnyLgUz0V9inkTAkQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAhkgYEEfQKsCPtUT6ufV1f1iefCPqGmESBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIEKgjMNCgT6yuOthTvI55xUPYJ1Q0AgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgMQGEzQJ1Yv7DMAZEMJECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQI1BMYbNAn1ivsU09XPwECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAIEGBYYS9IlNCPs0CG0YAQIECBAgQIAAAQIECBAgQIAAAQLDK3Cxp3d4N2hrBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIEBgiAIThrh8LB5hn7YrpjG/aAP61/T31//ghbzgn01deut/jRUcP92d/uan69IfPH5PmjWts1inKQECBAgQIECAAAECBAgQIECAAAECBEoFfvir19LyxXP7HdMjBNSvi5kECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgcHUFmhH0iSMQ9rm659HWCRAgQIAAAQIECBAgQIAAAQIECBC4QuDk6bPprS17rpjrJQECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQGLkC7U3ctQj7RKuexvPiEZV9qh89+XU8LvbzuBCVfU7v3vBnua/Siso+x051F7NMCRAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECIwZgWYGfQKlOuRTvC6CPjGtDvrEc2GfUNIIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgTGvUCzgz4BKuwz7t9WAAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAYq0IqgT+yDsM9Az4TxBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQ+P/bu/MfO44DP+DFOTi8SfGmSJ3UZVmUZVmX5bW18dqy116v4ewBZ2NtAgQgECS/5X/Ib/ktCGAtkATQHvEuYm/WtBcrWbZ8ybREUwclijJ1k5JIiaQ4JIdDcjgz6Rq6yJ7Xb+53dL/3aaBV3dVX9afKDb/h+74mQIAAAQJdLdCsoE9EFfbp6qHl5gkQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBOYi0MygT2yHsM9cesO+BAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECXSvQ7KBPhBX26drh5cYJECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgRmK9CKoE9si7DPbHvEfgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAl0p0KqgT8QV9unKIeamCRAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIEZiPQyqBPbI+wz2x6xT4ECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQJdJ9DqoE8EFvbpumHmhgkQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBGYSaEfQJ7ZJ2GemnrGdAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECgqwTaFfSJyMI+XTXU3CwBAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgMB0Au0M+sR2CftM1zu2ESBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIdI1Au4M+EVrYp2uGmxslQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBCYSqAMQZ/YNmGfqXpIPQECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAQFcIlCXoE7GFfbpiyLlJAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgACBegJlCvrE9gn71OsldQQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAh0vULagTwQX9un4YecGCRAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIEagXKGPSJbRT2qe0p6wQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAh0tUNagT0QX9unooefmCBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIE8gJlDvrEdgr75HvLMgECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAQMcKlD3oE+GFfTp2+LkxAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgACBJFCFoE9sq7BP6jElAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIBARwpUJegT8YV9OnIIuikCBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAIEoUKWgT2yvsE9UMBEgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECHScQNWCPrEDhH06bhi6IQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgSoGfWKvCfsYuwQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAh0lUNWgT+wEYZ+OGopuhgABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECDQ3QJVDvrEnhP26e7x6+4JECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAh0jUPWgT+wIYZ+OGY5uhAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECDQvQKdEPSJvSfs071j2J0TIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBDpCoFOCPrEzhH06Yki6CQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIBAdwp0UtAn9qCwT3eOY3dNgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIEKi8QKcFfWKHCPtUfli6AQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIBA9wl0YtAn9qKwT/eNZXdMgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIEKi0QKcGfWKnCPtUemhqPAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECguwQ6OegTe1LYp7vGs7slQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECFRWoNODPrFjhH0qOzw1nAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECDQPQLdEPSJvSns0z1j2p0SIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBCop0C1Bn9g5wj6VHKIaTYAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBDoDoFuCvrEHhX26Y5x7S4JECBAgAABAgQIECBAgAABAk0V6O/rDVetWha2bV4brtmyNmxYuzKsXL4k9PV225/bmsrs5AQIlFxg0rMwex6uv2plWL50IPT0LCp5yzWPAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAQHkF+srbtKa1LIZ94r8y5sv8xcbyKzMtH9u7a3e2z87l23Y8GvcdHBoOjz2+Jzzy8D1hzYqlMx1uOwECBAgQIECAAAECBAgQIECAQMkFlgz0h9tu2BJuu3FLWLt6RVixbCAMLO6fstUnBofCu0dPhMNHPwqvvXM0nDx1dsp957ohhovWrVk518Om3X90bCycO38hnD13IZweOhfGxtJv5Ux72JQbb9i2IfT2XAk8nR8ZCYfePzHl/o3csP3ajdkf/vIBg/GsDz5o5CUadq44jjavX9Ow8y30ROPZn0tfr7Ey3qZXrdJ4m/5OZrd1Ls/Csey5cuTYYDh05ER45/3j4eDbR8Po6Jz+9F63UcZkXZbLld02Ji/fuAUCBAgQIECAAAECBAgQIECAAAECBAgQIECAQIcJdGPQJ3ZhPuSTQj/5rp3TvzgK++TpLBMgQIAAAQIECBAgQIAAAQIEqi+w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8oa3OF3GsFBKAWO2lN2iUQQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQWJCDosyC+th8s7NP2LtAAAgQIECBAgAABAgQIECBAgACBThC4fuv68Ll7br18K0ePnwqHjpy4vG6BQNkEjNmy9Yj2ECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIEGiMgKBPYxzbeRZhn3bquzYBAgQIECBAgAABAgQIECBAgEDlBW7YtiF862sPhsX9fZfv5WfPHri8bIFA2QSM2bL1iPYQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQaJyAoE/jLNt5JmGfduq7NgECBAgQIECAAAECBAgQIECAQKUFli1ZHBYtWnT5Hn6ahXwOvPn+5XULBMomYMyWrUe0hwABAgQIECBAgAABAgQIECBAgAABAgQIECBAgEDjBAR9GmfZ7jMJ+7S7B1yfAAECBAgQIECAAAECBAgQIECg0gIjIxfDz/a8OjFX+kY0vmsEjNmu6Wo3SoAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAg0EUCfV10r91wqzHsE396NF/m73ssvzLT8rG9u3Zn++xcvm3Ho3HfwaHh8Njje8IjD98T1qxYOtPhthMgQIAAAQIECBAgQIAAAQIECBCohMDpoXNh9wuvhaefey0MDZ+vRJs1srsFjNnu7n93T4AAAQIECBAgQIAAAQIECBAgQIAAAQIECBAg0NkC3ujTef3rzT6d16fuiAABAgQIECBAgAABAgQIECBAoIkC77x/PDzx9MtCPk00durGChizjfV0NgIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQJlEhD0KVNvNK4twj6Ns3QmAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgEBLBAR9WsLclosI+7SF3UUJECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAvMTEPSZn1tVjhL2qUpPaScBAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECDQ9QKCPp0/BIR9Or+P3SEBAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECDQAQKCPh3QibO4BWGfWSDZhQABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECDQTgFBn3bqt/bawj6t9XY1AgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgMCcBAR95sRV+Z2FfSrfhW6AAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQ6FQBQZ9O7dmp70vYZ2obWwgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECbRMQ9GkbfVsvLOzTVn4XJ0CAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgUBQR9iibdUiPs0y097T4JECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgACBSggI+lSim5rWSGGfptE6MQECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIEBgbgKCPnPz6sS9hX06sVfdEwECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIFA5AUGfynVZUxos7NMUViclQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECMxeQNBn9ladvqewT6f3sPsjQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIESi0g6FPq7ml544R9Wk7uggQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgACBSwKCPkZCrYCwT62IdQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIBACwQEfVqAXMFLCPtUsNM0mQABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIEKi2gKBPtfuvma0X9mmmrnMTIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBGoEBH1qQKxOEhD2mcRhhQABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECDQPAFBn+bZdsqZhX06pSfdBwECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIFBqAUGfUndPaRon7FOartAQAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAoFMFBH06tWcbf1/CPo03dUYCBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAwGUBQZ/LFBZmISDsMwskuxAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIE5iMg6DMfte4+Rtinu/vf3RMgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQJNEhD0aRJsh59W2KfDO9jtESBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAq0XEPRpvXmnXFHYp1N60n0QIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECpRAQ9ClFN1S2EcI+le06DSdAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgTKJiDoU7YeqV57hH2q12daTIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECJRQQNCnhJ1SwSYJ+1Sw0zSZAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBNomkL5317YGuDABAgQIECBAgEA5BQR9ytkvVWxV+tCRL+Nymsey5fw8mq3H+WKdeeTY3l27hw7v25ltm5gGh4bDY4/vCYNnhlOVkgABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIdIJA+p5d/l7Sd/HydZYJECBAgAABAgS6QEDQpws6uYW3mD5Y5Mv0ASSW+aBPXJ5z2OdnL77ewttxKQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAg0FSB9H27mS4y2/1mOo/tBAgQIECAAAECJRcQ9Cl5B1WweenDRL6My2leUNingh6aTIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIE6gnkv2cXt0+1Xnts2q+23joBAgQIECBAgEAHCPR1wD24hfIJxA8Ri7I5X+ZbGcM+s56O7d21O9t55/JtOx7NH3Tw3Q/D6eHz+SrLBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECgdAJnit91qw3rxPU0x/bnt+eX073Vq0vblAQIECBAgAABAhUWEPSpcOeVvOnxQ0TTwz5HTpwqOYPmESBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgACBKwI9vYvXZWvxO3a1c9wp1cXlOMX1NE23Le2jJECAAAECBAgQqLhAT8Xbr/nlFkgfMPJl+qARy/hmn/w8mq3H+WKdeSS+2Wfo8L6d2TYTAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBCopMDY6IVjWcPTd+jSd+rivcTlOKW62vLSVv8lQIAAAQIECBDoaIH4xhUTgWYLpHGWL+NymmPgLD/3Zutxjm+cqp37V95493UDqzdvGx8b7RsfH+sNY2OXyjDeky33jsdyPJsvl9nSeDz/eLp+dtqJa2fFpLpYbyJAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAg0SWJQP70yc88Lg0Q+Gj75xNFuJP5Rd++PYF7K66eb8D2nHY/M/tl17rbSe7WYiQIAAAQIECBCoikA++FCVNmtnNQXSWMuXcTnN+aBPXJ427JNt78/mGAJKZT4QlI5N54nXiMvpWrGMUyprlyc2+g8BAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIEFiAQD5ok5ZjMCcup4BODOvEeSSbY4gnllMFfdI+Kewj6JNhmQgQIECAAAECnSYQwxEmAq0QiB9MYrAmX+avGz+0zHVKH3xiWW+OgZ9YH0M+sRT0yRBMBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQINASgfi9tfyUvueWQj6prA3spPq0f70ynjfV569hmQABAgQIECBAoOICgj4V78CKNT9+qGhk2CeeL06pvLR2aT190Ilhnxj0qX2jT3qbTyrTsbGsV5ffbpkAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECMwkkL7bli/jcpzTd9xSyCeWaY7b8vukY2rLbLeJKdanKb+c6pQECBAgQIAAAQIVEhD0qVBndUhT44eIhYR98h9UEkmqSx984rhOy7HMB33ygZ90vGBPklASIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAQKMFUvgmfdctlfH7bSnck8p8Xf57cOmY/Lka3U7nI0CAAAECBAgQKIGAoE8JOqELmxA/aCwk7JMny394yS/nP+DUC/rEc8Q2CPnkNS0TIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAQDME8gGd+P22uJ6+5xZDPhdzcz70k/ZJx6TvyWW7mwgQIECAAAECBDpRQNCnE3u1GvcUP2zMN+yT/8CTPrTky/iBpjc3p6BP/m0+tSEfgZ9qjButJECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAQNUE0nfeYrvj99vilA/wxOV6QZ8Y+En75b8jV7scz5e/Rr31WGciQIAAAQIECBCogICgTwU6qYObGD9YzDfsE1nyH0zSB5f4oSaO6/ThJn7QEfTJEEwECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAg0BaBqb7rFuvjd93SG3ximQI/+br0fbhYpu/KpTKrMhEgQIAAAQIECHSSgKBPJ/VmNe8lftiYa9gnfUCJZZximT7ApA806Y0++ZDPdG/0iefxVp+oYCJAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgACBRgmk77ml8+W//5a+7xbLGOyJZQr6xDKFfdJ++WOzzRNTqkvrSgIECBAgQIAAgYoLCPpUvAM7pPnxg8Zswj5TfSCJH2LitljGMR0/3NQL+sRrxDkGfuKUgj2pvFTrvwQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAoPEC+e/Ape+9pe++5UM9KeQTy7hfCgHF5fxx8dj8VLue32aZAAECBAgQIECgIgKCPhXpqC5oZvyAEQM3+TJ/2/HDSQzoxDJO6QNJLGN9LGO4J63H/eKHm7gtzfH8+TlbvRz2qV2O6yYCBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQILAQgfRdt3iOtBzL/By/75bmFPjJl2lbLPPH5ZezTZenWG8iQIAAAQIECBCoqICgT0U7rkObHT9czBT2idvTFPdP4Z70gSV+kInBntqQT6wT8skQTAQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECDQcoF8+CZ93y2VKcgT1+N33+J6vkzL+f3y52v5zbggAQIECBAgQIBA8wQEfZpn68zzE4gfPqYK+8RtMbATP6yk5Wxx0i8UpLf3pGBPbZmCQin0E4/PT2l7vs4yAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBCYj0C9QE6sS/Xp+3BxPQV58mU+5JOOqy1ju9L5UhnrTAQIECBAgAABAhUUEPSpYKd1QZPjB416YZ9YFz/A5EM66QNLrJ8q5JP2j9vjlNYvrV35b6w3ESBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgACBRgrUhm/Sevr+W77Mh3zSctyeX07HN7KNzkWAAAECBAgQIFASAcGGknSEZtQVSOMzlXGnuFxvrvfmnlSX9s8fH5fjlD/3pZpL/52qPr+PZQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgMJXAVIGcVB/LtByDPHGKZaybqkzHpDIek86RylhnIkCAAAECBAgQqKiAN/pUtOO6pNnxQ0cM3KQy3na9DyKpLr9vXI4fdGKZ5mzxcrAn1k01TbdtqmPUEyBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgACBvED6blu+Li2nbfkyLqc5BX3Ser0ynivWmwgQIECAAAECBDpIQKChgzqzg28lP07Tcixrl2dTF5nScR1M5tYIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAoOQCKaSTL6cK9MTgT5zS9rQ8Ufm7+rSsJECAAAECBAgQqLCAwEOFO6/Lmp4fq7XLaT2WUy1HrrQt0dWup3olAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBBolkAK9qTzp/V8OZvl2uPTupIAAQIECBAgQKDCAoIOFe68Lmx6frzWW66tq11PZPn6VKckQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQKtFsgHetK1a+vieqqL+0y1nI5XEiBAgAABAgQIVFhA4KHCndfFTc+P2/xyJEnrqczXJbL8tlSnJECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECrRaYKrQz1/pWt9v1CBAgQIAAAQIEmiQg8NAkWKdtukDt2K1djw3I1+WXm944FyBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAnMQyAd74mFzXZ/DpexKgAABAgQIECBQZgHhhzL3jrbNRqDeGK5Xlz/XTNvz+1omQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQLNEqgN9NRep972enW1x1knQIAAAQIECBCoqIDAQ0U7TrMLAtON5em2FU6kggABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQItElguhDPdNva1FyXJUCAAAECBAgQaLSAAESjRZ2vDALGdRl6QRsIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAYKECwj0LFXQ8AQIECBAgQKBiAgIRFeswzV2QgPG+ID4HEyBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgEATBYR6mojr1AQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAvMS+P/g/G5TucZAvQAAAABJRU5ErkJggg==&quot; alt=&quot;&quot; width=&quot;502&quot; height=&quot;253&quot; /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[출처: &lt;a href=&quot;https://www.kubeflow.org/docs/external-add-ons/kserve/kserve/&quot;&gt;https://www.kubeflow.org/docs/external-add-ons/kserve/kserve/&lt;/a&gt;]&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;그림과 같이 런타임으로 TensorFlow, PYTORCH, SKLearn, XGBoost, ONNX 등 다양한 모델 프레임워크를 지원하며 필요하면 커스텀 런타임을 만들어서 지원할 수 도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;KServe 하단에는 Knative 와 Istio (Serverless Layer) 를 갖을 수 있는데 하단에는 다음과 같이 구성할 수 있다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;KServe + Knative + Istio&lt;/li&gt;
&lt;li&gt;KServe + Istio&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Knative 는 옵션이기는 하나 Knative 를 설치하면서 로깅 (fluentbit + ElasticSearch + Kibana), 모니터링 (Prometheus, Exporter), 트레이싱(Jaeger + ElasticSearch) 을 쉽게 연결할 수 있다는 장점이 있다. 또한 Istio 가 제공하는 Network 핸들링 기능을 쉽게 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;KServe 설치는 Istio 설치 &amp;rarr; Knative 설치 &amp;rarr; KServe 설치 순으로 진행하며, 이에 맞는 버전은 다음과 같다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Recommended Version Matrix&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Kubernetes Version&lt;/th&gt;
&lt;th&gt;Istio Version&lt;/th&gt;
&lt;th&gt;Knative Version&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1.20&lt;/td&gt;
&lt;td&gt;1.9, 1.10, 1.11&lt;/td&gt;
&lt;td&gt;0.25, 0.26, 1.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1.21&lt;/td&gt;
&lt;td&gt;1.10, 1.11&lt;/td&gt;
&lt;td&gt;0.25, 0.26, 1.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1.22&lt;/td&gt;
&lt;td&gt;1.11, 1.12&lt;/td&gt;
&lt;td&gt;0.25, 0.26, 1.0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서는 Kubernetes 1.22 에 맞춰서 설치한다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;Istio 설치&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Istio 는 Service Mesh 를 쉽게 구성가능하도록 지원하는 플랫폼으로 proxy 가 sidecar 형태로 추가되어 네트워크를 조절할 수 있다. 네트워크를 조절기능의 대표적인 것은 네트워크 쉬프팅이 있다. Canary Release 나 A/B Test 에서는 서로 다른 버전의 서비스로 호출되는 네트워크의 흐름 비중을 조절가능해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 이유로 요즘 Service Mesh 는 Sidecar 활용 패턴을 사용하는데 Istio 에서는 서비스 배포 시에 Sidecar 를 자동으로 Injection 해주는 기능을 지원하고 있으며, 많은 곳에서 대부분 auto injeciton 을 사용하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 Knative 에서는 auto injection 을 사용하지 않는다. auto injection 은 kubernetes namespace 에 label 을 추가하여 (istio-injeciton=enabled) 자동으로 해당 namespace 에 배포되는 pod 에는 sidecar proxy 가 자동으로 설치되는 기능이라, Service Mesh 를 사용하고 싶지 않은 서비스들에게도 영향을 줄 수 있기 때문에 auto injection 을 disable 할 것을 권장하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Istio 설치는 helm chart 로 쉽게 설치할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;helm repo 를 추가하고 value 값을 오버라이드할 파일을 만든다.&lt;/p&gt;
&lt;pre class=&quot;vim&quot;&gt;&lt;code&gt;$ helm repo add istio https://istio-release.storage.googleapis.com/charts
$ helm repo update

$ vi istiod_1.12.8_default_values.yaml
global:
  proxy:
        autoInject: disabled   # 원래 값은 enabled 임&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;Istio-system 네임스페이스를 생성한 후 helm chart 를 설치한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;base 는 crd 를 설치하며, istiod 가 실제 데몬 서비스다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ kubectl create namespace istio-system
$ helm upgrade -i istio-base istio/base --version 1.12.8 -n istio-system -f istiod_1.12.8_default_values.yaml
$ helm upgrade -i istiod istio/istiod --version 1.12.8 -n istio-system -f istiod_1.12.8_default_values.yaml --wait&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;외부에서 서비스로 접근하기 위한 North - South 통신은 Istio Ingress Gateway 를 통해서 가능하다. 그러므로 Istio Gateway 를 추가로 설치해 준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저, value 값을 오버라이드할 파일을 만든다.&lt;/p&gt;
&lt;pre class=&quot;lua&quot;&gt;&lt;code&gt;$ vi gateway_1.12.8_default_values.yaml
podAnnotations:
  prometheus.io/port: &quot;15020&quot;
  prometheus.io/scrape: &quot;true&quot;
  prometheus.io/path: &quot;/stats/prometheus&quot;
  inject.istio.io/templates: &quot;gateway&quot;
  sidecar.istio.io/inject: &quot;true&quot; &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;istio-ingress 네임스페이스를 생성하고 istio ingress gateway 를 helm chart로 설치한다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ kubectl create ns istio-ingress
$ helm upgrade -i istio-ingress istio/gateway --version 1.12.8 -n istio-ingress -f gateway_1.12.8_default_values.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;아래와 같이 잘 설치되어 있음을 확인할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;$ kubectl get pods -n istio-system
NAME                      READY   STATUS    RESTARTS   AGE
istiod-68d7bfb6d8-nt82m   1/1     Running   0          20d

$ kubectl get pods -n istio-ingress
NAME                             READY   STATUS    RESTARTS   AGE
istio-ingress-69495c6667-7njv8   1/1     Running   0          20d&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;Knative 설치&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Knative 는 Serverless 플랫폼이라 생각하면 된다. 서비스를 Istio 를 활용하여 배포하면 &lt;code&gt;Gateway&lt;/code&gt;, &lt;code&gt;VirtualServie&lt;/code&gt; 를 만들어서 연결해야 하는데 Knative 를 이를 자동으로 생성해주기 때문에 편리하다. 또한 앞에서도 설명한 모니터링, 로깅, 트레이싱이 잘 연결되기 때문에 일단 설치를 한다면 사용하기 편리하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Knative 는 설치 모듈이 Serving 과 Eventing 2개로 나눠져 있다. 일단 API 서비스가 가능한 Serving 모듈만 설치하고 테스트를 한다. 또한 모니터링, 로깅, 트레이싱도 다음에 설명하고 지금은 Knative Serving 기능에 집중한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Knative 는 Yaml 과 Operator 로 설치할 수 있는데 공식 문서에서 Operator 는 개발/테스트 환경에서만 사용하라고 권고하기 때문에 yaml 로 설치한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저, crd 를 설치하고, Serving 모듈을 설치한다.&lt;/p&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;$ kubectl apply -f https://github.com/knative/serving/releases/download/knative-v1.5.0/serving-crds.yaml
--- output ---
customresourcedefinition.apiextensions.k8s.io/certificates.networking.internal.knative.dev created
customresourcedefinition.apiextensions.k8s.io/configurations.serving.knative.dev created
customresourcedefinition.apiextensions.k8s.io/clusterdomainclaims.networking.internal.knative.dev created
customresourcedefinition.apiextensions.k8s.io/domainmappings.serving.knative.dev created
customresourcedefinition.apiextensions.k8s.io/ingresses.networking.internal.knative.dev created
customresourcedefinition.apiextensions.k8s.io/metrics.autoscaling.internal.knative.dev created
customresourcedefinition.apiextensions.k8s.io/podautoscalers.autoscaling.internal.knative.dev created
customresourcedefinition.apiextensions.k8s.io/revisions.serving.knative.dev created
customresourcedefinition.apiextensions.k8s.io/routes.serving.knative.dev created
customresourcedefinition.apiextensions.k8s.io/serverlessservices.networking.internal.knative.dev created
customresourcedefinition.apiextensions.k8s.io/services.serving.knative.dev created
customresourcedefinition.apiextensions.k8s.io/images.caching.internal.knative.dev created

$ kubectl apply -f https://github.com/knative/serving/releases/download/knative-v1.5.0/serving-core.yaml
--- output ---
namespace/knative-serving created
clusterrole.rbac.authorization.k8s.io/knative-serving-aggregated-addressable-resolver created
clusterrole.rbac.authorization.k8s.io/knative-serving-addressable-resolver created
clusterrole.rbac.authorization.k8s.io/knative-serving-namespaced-admin created
clusterrole.rbac.authorization.k8s.io/knative-serving-namespaced-edit created
clusterrole.rbac.authorization.k8s.io/knative-serving-namespaced-view created
clusterrole.rbac.authorization.k8s.io/knative-serving-core created
clusterrole.rbac.authorization.k8s.io/knative-serving-podspecable-binding created
serviceaccount/controller created
clusterrole.rbac.authorization.k8s.io/knative-serving-admin created
clusterrolebinding.rbac.authorization.k8s.io/knative-serving-controller-admin created
clusterrolebinding.rbac.authorization.k8s.io/knative-serving-controller-addressable-resolver created
customresourcedefinition.apiextensions.k8s.io/images.caching.internal.knative.dev unchanged
customresourcedefinition.apiextensions.k8s.io/certificates.networking.internal.knative.dev unchanged
customresourcedefinition.apiextensions.k8s.io/configurations.serving.knative.dev unchanged
customresourcedefinition.apiextensions.k8s.io/clusterdomainclaims.networking.internal.knative.dev unchanged
customresourcedefinition.apiextensions.k8s.io/domainmappings.serving.knative.dev unchanged
customresourcedefinition.apiextensions.k8s.io/ingresses.networking.internal.knative.dev unchanged
customresourcedefinition.apiextensions.k8s.io/metrics.autoscaling.internal.knative.dev unchanged
customresourcedefinition.apiextensions.k8s.io/podautoscalers.autoscaling.internal.knative.dev unchanged
customresourcedefinition.apiextensions.k8s.io/revisions.serving.knative.dev unchanged
customresourcedefinition.apiextensions.k8s.io/routes.serving.knative.dev unchanged
customresourcedefinition.apiextensions.k8s.io/serverlessservices.networking.internal.knative.dev unchanged
customresourcedefinition.apiextensions.k8s.io/services.serving.knative.dev unchanged
image.caching.internal.knative.dev/queue-proxy created
configmap/config-autoscaler created
configmap/config-defaults created
configmap/config-deployment created
configmap/config-domain created
configmap/config-features created
configmap/config-gc created
configmap/config-leader-election created
configmap/config-logging created
configmap/config-network created
configmap/config-observability created
configmap/config-tracing created
horizontalpodautoscaler.autoscaling/activator created
poddisruptionbudget.policy/activator-pdb created
deployment.apps/activator created
service/activator-service created
deployment.apps/autoscaler created
service/autoscaler created
deployment.apps/controller created
service/controller created
deployment.apps/domain-mapping created
deployment.apps/domainmapping-webhook created
service/domainmapping-webhook created
horizontalpodautoscaler.autoscaling/webhook created
poddisruptionbudget.policy/webhook-pdb created
deployment.apps/webhook created
service/webhook created
validatingwebhookconfiguration.admissionregistration.k8s.io/config.webhook.serving.knative.dev created
mutatingwebhookconfiguration.admissionregistration.k8s.io/webhook.serving.knative.dev created
mutatingwebhookconfiguration.admissionregistration.k8s.io/webhook.domainmapping.serving.knative.dev created
secret/domainmapping-webhook-certs created
validatingwebhookconfiguration.admissionregistration.k8s.io/validation.webhook.domainmapping.serving.knative.dev created
validatingwebhookconfiguration.admissionregistration.k8s.io/validation.webhook.serving.knative.dev created
secret/webhook-certs created&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;다음은 Isito 와 연동하기 위한 network 들을 설치한다.&lt;/p&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;$ kubectl apply -f https://github.com/knative/net-istio/releases/download/knative-v1.5.0/net-istio.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;그대로 설치하면 Isito gateway 와 연동되지 않는다. 그렇기 때문에 아래와 같이 selector 를 수정해 줘야 한다.&lt;/p&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;$ kubectl edit gateway -n knative-serving knative-ingress-gateway
...
spec:
  selector:
    istio: ingressgateway
    istio: ingress          # 추가

$ kubectl edit gateway -n knative-serving knative-local-gateway
...
spec:
  selector:
    istio: ingressgateway
    istio: ingress          # 추가&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Istio 의 Ingress gateway 앞단에는 LoadBalancer 가 연결되어 있다. LoadBalancer 가 External IP 로 연결되어 있으면 IP 를 dns 로 연결해 주는 magic dns (sslip.io) 를 사용할 수 있고, LoadBalancer 가 domain name 으로 연결되어 있으면 실제 DNS 에 CNAME 을 등록하여 연결하면 된다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ kubectl get svc -n istio-ingress
NAME            TYPE           CLUSTER-IP       EXTERNAL-IP 
istio-ingress   LoadBalancer   10.107.111.229   xxxxx.ap-northeast-2.elb.amazonaws.com&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서는 aws 를 사용하고 있기 때문에 Route53 에 CNAME 을 등록하였다.&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;서비스 도메인: helloworld-go-default.taco-cat.xyz
target: xxxxx.ap-northeast-2.elb.amazonaws.com
type: CNAME&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Knative ConfigMap 설정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 Knative ConfigMap 에 기본 도메인과 full 도메인 설정을 세팅한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 설정은 앞서 Route53 에 등록한 서비스 도메인과 같은 형식으로 설정되게 구성해야 한다.&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;## Domain: taco-cat.xyz
$ kubectl edit cm config-domain -n knative-serving
apiVersion: v1
data:
  taco-cat.xyz: &quot;&quot;
kind: ConfigMap
[...]

## Name: helloworld-go
## Namesapce: default
## Domain: taco-cat.xyz
$ kubectl edit cm config-network -n knative-serving
apiVersion: v1
data:
  domain-template: &quot;{{.Name}}-{{.Namespace}}.{{.Domain}}&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Knative sample 배포 테스트&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Knative 에서 제공하는 helloworld-go 샘플 프로그램을 배포해 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서비스 이름이 &lt;code&gt;helloworld-go&lt;/code&gt;, Namespace 가 &lt;code&gt;default&lt;/code&gt; 로 앞서 Route53 및 ConfigMap 에 설정한 도메인 형식과 동일함을 할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;$ git clone https://github.com/knative/docs knative-docs
$ cd knative-docs/code-samples/serving/hello-world/helloworld-go

$ vi service.yaml
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: helloworld-go
  namespace: default
spec:
  template:
    spec:
      containers:
      - image: gcr.io/knative-samples/helloworld-go
        env:
        - name: TARGET
          value: &quot;Go Sample v1&quot;

$ kubectl apply -f service.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배포가 제대로 되었는지 확인해 보자.&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;$ kubectl get route
NAME            URL                                         READY   REASON
helloworld-go   http://helloworld-go-default.taco-cat.xyz   True&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Knative 는 zero replicas 를 사용한다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Serverless 를 어떻게 구현했을까? 사실 Knative 는 Kubernetes 의 zero replicas 를 사용했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배포 후에 deployment 를 조회하면 아래과 같이 Ready 와 Available 이 &lt;code&gt;0&lt;/code&gt; 상태임을 알 수 있다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;$ kubectl get deploy
NAME                                       READY   UP-TO-DATE   AVAILABLE   AGE
helloworld-go-00001-deployment             0/0     0            0           10d&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배포도 잘되고 Route53 에 dns 도 어느 정도 시간이 지났다면 브라우저 혹은 curl 로 확인할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;haskell&quot;&gt;&lt;code&gt;$ curl http://helloworld-go-default.taco-cat.xyz
--- output ---
Hello Go Sample v1!&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 요청이 들어오면 실제로 pod 가 실행되고 있음을 알 수 있다. 1분 동안 아무런 요청이 없으면 pod 는 다시 사라지고 대기 상태가 된다. (요청이 없더라도 중간에 다시 pod 가 생겨서 실제로는 일정 시간 동안 새로운 pod 로 교체된다)&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;$ kubectl get deploy
NAME                                       READY   UP-TO-DATE   AVAILABLE   AGE
helloworld-go-00001-deployment             1/1     1            1           10d&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;TLS 인증서 적용&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인증서를 가지고 있다면 gateway 에 tls 를 적용하여 tls termination 을 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 istio-ingress 네임스페이스에 secret 으로 taco-cat-tls 인증서를 설치한 후 gateway 에서 해당 인증서를 읽을 수 있도록 tls 를 추가한 부분이다.&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;$ kubectl edit gateway knative-ingress-gateway -n knative-serving
...
spec:
  selector:
    istio: ingress
  servers:
  - hosts:
    - '*'
    port:
      name: http
      number: 80
      protocol: HTTP
  - hosts:
    - '*.taco-cat.xyz'
    port:
      name: https
      number: 443
      protocol: HTTPS
    ## tls 추가
    tls:
      mode: SIMPLE
      credentialName: taco-cat-tls&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;HPA 설치&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서비스에 요청이 신규로 들어오거나, 많아지면 replicas 수를 조절하여 pod 를 실행해주는 activator 가 있다. 이 activator 를 auto scaling 하는 hpa 를 설치한다.&lt;/p&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;$ kubectl apply -f https://github.com/knative/serving/releases/download/knative-v1.5.0/serving-hpa.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;hpa 를 조회해서 확인할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;$ kubectl get hpa -n knative-serving
NAME        REFERENCE              TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
activator   Deployment/activator   0%/100%   1         20        1          13d
webhook     Deployment/webhook     3%/100%   1         5         1          13d&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;KServe 설치&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;KServe 는 이제 막 Helm chart 가 만들어지고 있다. 그렇기 때문에 일단은 yaml 로 설치를 진행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 KServe 컴포넌트를 설치하고 이어서 각종 ML Framework 를 나타내는 Runtime을 설치한다.&lt;/p&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;$ kubectl apply -f https://github.com/kserve/kserve/releases/download/v0.8.0/kserve.yaml
--- output ---
namespace/kserve created
customresourcedefinition.apiextensions.k8s.io/clusterservingruntimes.serving.kserve.io created
customresourcedefinition.apiextensions.k8s.io/inferenceservices.serving.kserve.io created
customresourcedefinition.apiextensions.k8s.io/servingruntimes.serving.kserve.io created
customresourcedefinition.apiextensions.k8s.io/trainedmodels.serving.kserve.io created
serviceaccount/kserve-controller-manager created
role.rbac.authorization.k8s.io/leader-election-role created
clusterrole.rbac.authorization.k8s.io/kserve-manager-role created
clusterrole.rbac.authorization.k8s.io/kserve-proxy-role created
rolebinding.rbac.authorization.k8s.io/leader-election-rolebinding created
clusterrolebinding.rbac.authorization.k8s.io/kserve-manager-rolebinding created
clusterrolebinding.rbac.authorization.k8s.io/kserve-proxy-rolebinding created
configmap/inferenceservice-config created
configmap/kserve-config created
secret/kserve-webhook-server-secret created
service/kserve-controller-manager-metrics-service created
service/kserve-controller-manager-service created
service/kserve-webhook-server-service created
statefulset.apps/kserve-controller-manager created
certificate.cert-manager.io/serving-cert created
issuer.cert-manager.io/selfsigned-issuer created
mutatingwebhookconfiguration.admissionregistration.k8s.io/inferenceservice.serving.kserve.io created
validatingwebhookconfiguration.admissionregistration.k8s.io/inferenceservice.serving.kserve.io created
validatingwebhookconfiguration.admissionregistration.k8s.io/trainedmodel.serving.kserve.io created

$ kubectl apply -f https://github.com/kserve/kserve/releases/download/v0.8.0/kserve-runtimes.yaml
--- output---
clusterservingruntime.serving.kserve.io/kserve-lgbserver created
clusterservingruntime.serving.kserve.io/kserve-mlserver created
clusterservingruntime.serving.kserve.io/kserve-paddleserver created
clusterservingruntime.serving.kserve.io/kserve-pmmlserver created
clusterservingruntime.serving.kserve.io/kserve-sklearnserver created
clusterservingruntime.serving.kserve.io/kserve-tensorflow-serving created
clusterservingruntime.serving.kserve.io/kserve-torchserve created
clusterservingruntime.serving.kserve.io/kserve-tritonserver created
clusterservingruntime.serving.kserve.io/kserve-xgbserver created&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;KServe 설치를 확인한다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;$ kubectl get pod -n kserve
NAME                          READY   STATUS    RESTARTS   AGE
kserve-controller-manager-0   2/2     Running   0          7d10h&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Rumtime 도 설치되었는지 확인한다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;$ kubectl get clusterservingruntimes
NAME                        DISABLED   MODELTYPE    CONTAINERS         AGE
kserve-lgbserver                       lightgbm     kserve-container   7d10h
kserve-mlserver                        sklearn      kserve-container   7d10h
kserve-paddleserver                    paddle       kserve-container   7d10h
kserve-pmmlserver                      pmml         kserve-container   7d10h
kserve-sklearnserver                   sklearn      kserve-container   7d10h
kserve-tensorflow-serving              tensorflow   kserve-container   7d10h
kserve-torchserve                      pytorch      kserve-container   7d10h
kserve-tritonserver                    tensorrt     kserve-container   7d10h
kserve-xgbserver                       xgboost      kserve-container   7d10h&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Sample model 을 KServe 를 활용하여 배포&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;tensorflow 로 개발된 mnist 샘플 모델을 KServe 로 배포해 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;KServe 는 &lt;code&gt;model in load&lt;/code&gt; 패턴을 적용하여 인퍼런스 서비스를 수행한다. 아래에서는 모델이 gs 에 저장되어 있으면 이를 가져와서 서빙하는 구조이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;runtime 은 앞서 설치한 clusterservingruntime 중에 하나인 kserve-tensorflow-serving 이고 버전이 &lt;code&gt;2&lt;/code&gt; 임을 알 수 있다.&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;$ vi mnist_tensorflow.yaml
---
apiVersion: &quot;serving.kserve.io/v1beta1&quot;
kind: &quot;InferenceService&quot;
metadata:
  name: &quot;mnist&quot;
spec:
  predictor:
    model:
      modelFormat:
        name: tensorflow
        version: &quot;2&quot;
      storageUri: &quot;gs://kserve/models/mnist&quot;
      runtime: kserve-tensorflow-serving
    logger:
      mode: all

$ kubectl apply -f mnist_tensorflow.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&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;KServe 에서 도메인을 만들 때 namespace 를 추가로 붙히기 때문에 도메인이 아래와&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;$ kubectl get isvc
NAME    URL     READY   PREV   LATEST   PREVROLLEDOUTREVISION  LATESTREADYREVISION
mnist   http://mnist-default.taco-cat.xyz   True           100 mnist-predictor-default-00001

$ kubectl get route
NAME                      URL                                                   READY   REASON
mnist-predictor-default   http://mnist-predictor-default-default.taco-cat.xyz   True&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Route53 에 도메인을 추가한다.&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;서비스 도메인: mnist-predictor-default-default.taco-cat.xyz
target: xxxxx.ap-northeast-2.elb.amazonaws.com
type: CNAME&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같이 요청하여 결과값이 제대로 나오는지 확인한다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;$ curl https://mnist-predictor-default-default.taco-cat.xyz/v1/models/mnist:predict \
   -H 'Content-Type: application/json' \
   -d @mnist.json
--- output ---
{
    &quot;predictions&quot;: [[3.2338352e-09, 1.66207215e-09, 1.17224181e-06, 0.000114716699, 4.34008705e-13, 4.64885304e-08, 3.96761454e-13, 0.999883413, 1.21785089e-08, 6.44099089e-07]
    ]
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Kubernetes/Kubeflow</category>
      <category>KFServe</category>
      <category>KServe</category>
      <category>kubeflow</category>
      <category>ML Model Serving</category>
      <category>ML Serving</category>
      <category>Model Serving</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/302</guid>
      <comments>https://ahnseungkyu.com/302#entry302comment</comments>
      <pubDate>Mon, 18 Jul 2022 20:11:44 +0900</pubDate>
    </item>
    <item>
      <title>( go-05) Go Struct</title>
      <link>https://ahnseungkyu.com/301</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Slice 와 Map 은 값을 여러개 자질 수 있는 타입이다. 그러나 선언한 타입과 같은 타입만 저장해야 하는 문제가 있다. 또한 class 와 같이 다양한 멤버 변수를 가질 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 Go 에서는 다양한 값을 가질 수 있도록 Struct 타입을 지원한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;Struct&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;struct 의 를 만들려면&lt;span&gt;&amp;nbsp;&lt;/span&gt;type&lt;span&gt;&amp;nbsp;&lt;/span&gt;키워드,&lt;span&gt;&amp;nbsp;&lt;/span&gt;struct명&lt;span style=&quot;color: #f8f8f2;&quot;&gt;,&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;struct&lt;span&gt;&amp;nbsp;&lt;/span&gt;키워드로 만든다. 그리고 그 안에&lt;span&gt;&amp;nbsp;&lt;/span&gt;다양한 변수를 포함할 수 있으며&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;}&lt;/span&gt;&lt;span&gt;&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;type 으로 struct 를 선언했으면 그 자체가 하나의&lt;span&gt;&amp;nbsp;&lt;/span&gt;type&lt;span&gt;&amp;nbsp;&lt;/span&gt;이 된다. 그럼&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #66d9ef;&quot;&gt;var&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;로 새로운 만든 type을 활용하여 변수 선언을 할 수 있다. 아래와 같이 name 과 age 를&lt;span&gt;&amp;nbsp;&lt;/span&gt;필드로 갖는 person 이라는 새로운 타입을 선언하고 jina 와 jamie 라는 변수를 만들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변수 선언만 한 struct 내의&lt;span&gt;&amp;nbsp;&lt;/span&gt;필드들은 zero 값을 갖는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;person 타입의 변수를 초기화 할 때는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;}&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;로 초기화 할 수 도 있다.&lt;/p&gt;
&lt;div data-language=&quot;bash&quot;&gt;
&lt;pre class=&quot;go&quot;&gt;&lt;code&gt;package main

import &quot;fmt&quot;

func main() {
	type person struct {
		name string
		age  int
	}

	var jina person
	fmt.Println(jina)

	jamie := person{}
	fmt.Println(jamie)
}

--- output ---
{ 0}
{ 0}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&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;값을 지정하여 초기화할 때는 json 타입으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #f92672;&quot;&gt;변수&lt;/span&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;:&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;값&lt;span&gt;&amp;nbsp;&lt;/span&gt;으로 지정하거나&lt;span&gt;&amp;nbsp;&lt;/span&gt;값&lt;span&gt;&amp;nbsp;&lt;/span&gt;으로 지정할 수 있다. 변수 사이는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;,&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;로 구분하며, 마지막 변수 끝에도&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;,&lt;/span&gt;&lt;span&gt;&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;b&gt;Go 에서는 타입을 선언할 때는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;{&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;앞에&lt;span&gt;&amp;nbsp;&lt;/span&gt;공백을 넣지만, 값을 초기화할 때는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;{&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;앞에 공백을 넣지 않는다. 또한 타입을 선언할 때는 필드 사이에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;,&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;가 없지만, 값을 초기화 할 때는 필드값 사이에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;,&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;를 넣는다.&lt;/b&gt;&lt;/p&gt;
&lt;div data-language=&quot;bash&quot;&gt;
&lt;pre class=&quot;mipsasm&quot;&gt;&lt;code&gt;jina := person{
	name: &quot;Jina&quot;,
	age:  21,
}
fmt.Println(jina)

jamie := person{
	&quot;Jamie&quot;,
	18,
}
fmt.Println(jamie)

--- output ---
{Jina 21}
{Jamie 18}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&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;단, jina[&amp;rdquo;age&amp;rdquo;] 와 같이 인덱싱을 통한 접근은 지원하지 않는다.&lt;/p&gt;
&lt;div data-language=&quot;bash&quot;&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;var jina person
jina.name = &quot;Jina&quot;
jina.age = 21
// jina[&quot;age&quot;] = 21  // 인덱싱은 지원하지 않음

fmt.Println(jina.name)

--- output ---
Jina&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Anonymous struct&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;type 이 없는 struct 도 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때는 type 키워드를 쓰지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같이 바로 jina 라는 변수를 struct 형태로 지정하고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;.&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;을 통해 값을 지정할 수 있다. 혹은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;}&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;를 사용하여 jamie 변수를 선언하면서 초기 값을 지정할 수 있다.&lt;/p&gt;
&lt;div data-language=&quot;bash&quot;&gt;
&lt;pre class=&quot;go&quot;&gt;&lt;code&gt;var jina struct {
		name string
		age  int
}

jina.name = &quot;Jina&quot;
jina.age = 21
fmt.Println(jina)

jamie := struct {
	name string
	age  int
}{
	name: &quot;Jamie&quot;,
	age:  18,
}
fmt.Println(jamie)

--- output ---
{Jina 21}
{Jamie 18}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Struct 비교&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;go 에서는 type 이 같으면 대입(&lt;span style=&quot;color: #f8f8f2;&quot;&gt;=&lt;/span&gt;), 비교(&lt;span style=&quot;color: #f8f8f2;&quot;&gt;==&lt;/span&gt;) 를 할 수 있다. 하지만 type 이 다르면 비교나 대입을 할 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 type 을 convert 하여 맞춰 준다면 대입, 비교가 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;jina 와 jina2 는 type 이 같고 필드 값도 같다. 그래서 비교를 하면 true 값이 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 jamie 는 jina 와 type 이 같지만 필드 값이 달라서 비교를 하면 false 값이 나온다.&lt;/p&gt;
&lt;div data-language=&quot;bash&quot;&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;jina := person{
	name: &quot;Jina&quot;,
	age:  21,
}

jina2 := person{
	name: &quot;Jina&quot;,
	age:  21,
}
fmt.Println(jina == jina2)

jamie := person{
	name: &quot;Jamie&quot;,
	age:  18,
}
fmt.Println(jina == jamie)

--- output ---
true
false&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로운 anotherPerson type 을 만들어서 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같이 jina 는 person type 이고 jamie 는 anotherPerson type 이므로 서로 type 이 달라서 비교나 대입을 하면 에러가 난다.&lt;/p&gt;
&lt;div data-language=&quot;bash&quot;&gt;
&lt;pre class=&quot;go&quot;&gt;&lt;code&gt;type anotherPerson struct {
	name string
	age  int
}

jina := person{
	name: &quot;Jina&quot;,
	age:  21,
}
fmt.Println(jina)

jamie := anotherPerson{
	name: &quot;Jamie&quot;,
	age:  18,
}

fmt.Println(jina == jamie)

--- output ---
./main.go:88:19: invalid operation: jina == jamie (mismatched types person and anotherPerson)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 jamie 를 person type 으로 바꾸는 type converson 을 하여 비교하여 보자.&lt;/p&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;div data-language=&quot;bash&quot;&gt;
&lt;pre class=&quot;mipsasm&quot;&gt;&lt;code&gt;type anotherPerson struct {
	name string
	age  int
}

jina := person{
	name: &quot;Jina&quot;,
	age:  21,
}
fmt.Println(jina)

jamie := anotherPerson{
	name: &quot;Jamie&quot;,
	age:  18,
}

jina = person(jamie)
fmt.Println(jina)

--- output ---
{Jina 21}
{Jamie 18}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한가지 중요한 점은 struct 사이에 타입 변환은&lt;span&gt;&amp;nbsp;&lt;/span&gt;타입&lt;span style=&quot;color: #f8f8f2;&quot;&gt;,&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;필드명&lt;span style=&quot;color: #f8f8f2;&quot;&gt;,&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;필드 순서&lt;span style=&quot;color: #f8f8f2;&quot;&gt;,&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;필드 갯수&lt;span&gt;&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;그럼 type 으로 선언된 struct 와 anonymous struct 는&lt;span&gt;&amp;nbsp;&lt;/span&gt;타입을 제외한 필드명&lt;span style=&quot;color: #f8f8f2;&quot;&gt;,&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;필드 순서&lt;span style=&quot;color: #f8f8f2;&quot;&gt;,&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;필드 갯수&lt;span&gt;&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;/p&gt;
&lt;div data-language=&quot;bash&quot;&gt;
&lt;pre class=&quot;mipsasm&quot;&gt;&lt;code&gt;jina := person{
	name: &quot;Jina&quot;,
	age:  21,
}
fmt.Println(jina)

var jamie struct {
	name string
	age  int
}

jamie = jina
fmt.Println(jina == jamie)

--- output ---
{Jina 21}
true&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-language=&quot;bash&quot;&gt;
&lt;pre class=&quot;mipsasm&quot;&gt;&lt;code&gt;jamie := struct {
	name string
	age  int
}{
	name: &quot;Jamie&quot;,
	age:  18,
}

var jina person

jina = person(jamie)
fmt.Println(jina)
fmt.Println(jina == jamie)

--- output --
{Jamie 18}
true&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 person(jamie) 로 타입 변환을 하지 않아도 정상적으로 동작한다.&lt;/p&gt;</description>
      <category>프로그래밍/Go</category>
      <category>go</category>
      <category>golang</category>
      <category>struct</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/301</guid>
      <comments>https://ahnseungkyu.com/301#entry301comment</comments>
      <pubDate>Sat, 9 Jul 2022 17:38:15 +0900</pubDate>
    </item>
    <item>
      <title>(go-04) Go Map 타입</title>
      <link>https://ahnseungkyu.com/300</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=LqFEzkxyDIg&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/uPBPs/hyO7JuKMrd/5oLewFDjs337Y9phbHOPw1/img.jpg?width=480&amp;amp;height=360&amp;amp;face=0_0_480_360&quot; data-video-width=&quot;480&quot; data-video-height=&quot;360&quot; data-video-origin-width=&quot;480&quot; data-video-origin-height=&quot;360&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/LqFEzkxyDIg&quot; width=&quot;480&quot; height=&quot;360&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Map 은 key, value 로 저장할 수 있는 타입이다. HashMap 을 사용하기 때문에 key 는 유일한 값으로 key 를 사용하면 value 를 바로 찾아서 쓸 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 slice 와 동일하게 zero 값은 nil 이다. 그러므로 map 변수를 선언만 하면 nil 값으로 비교할 수 있다. &lt;b&gt;slice 는 nil 값이라도 append 를 사용하면 값을 추가하면서 새로운 slice 가 생성되어 return 되었다. 하지만 map 은 nil 값에는 어떠한 key, value 도 추가할 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;Map&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;map 은 key, value 쌍으로 이루어진 데이터 구조이다. 파이썬에서는 dictionary 와 비슷하다고 생각하면 된다. 단지 다른 것은 하나의 map 에는 사전에 지정된 타입의 key, value 만 저장될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 &lt;code&gt;string&lt;/code&gt; 타입을 key 로하고 &lt;code&gt;int&lt;/code&gt; 를 value 로 저장하는 map 을 선언한 것이다. &lt;code&gt;map[key타입]value타입&lt;/code&gt; 으로 선언할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 선언만 한 map 변수의 zero 값은 nil 이다.&lt;/p&gt;
&lt;pre class=&quot;go&quot;&gt;&lt;code&gt;var m map[string]int
fmt.Println(m == nil)

--- output ---
true&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;이렇게 nil 값이 상태의 map 에는 key, value 를 추가할 수 없다(slice 와는 다르다).&lt;/p&gt;
&lt;pre class=&quot;go&quot;&gt;&lt;code&gt;var m map[string]int
m[&quot;one&quot;] = 0

--- output ---
panic: assignment to entry in nil map&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;아래와 같이 empty map 을 생성할 수 있으며, 여기에는 key, value 를 추가할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;go&quot;&gt;&lt;code&gt;var m1 = map[string]int{}
fmt.Println(m1 == nil)
m1[&quot;one&quot;] = 0
fmt.Println(m1)

--- output ---
false
map[one:0]&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;초기 값을 아래와 같이 생성할 수 도 있다. 초기화 할 때 key, 와 value 는 &lt;code&gt;:&lt;/code&gt; 로 구분하고 연속적으로 key, value 를 입력하기 위해서는 &lt;code&gt;,&lt;/code&gt; 구분자를 사용한다.&lt;/p&gt;
&lt;pre class=&quot;go&quot;&gt;&lt;code&gt;m2 := map[string]int{
    &quot;one&quot;:  1,
    &quot;two&quot;: 2,
}
fmt.Println(m2)

--- output ---
map[one:1 two:2]&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;make 함수&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;slice 와 동일하게 make 내장 함수를 사용하여 empty map 을 생성할 수 있다. 이렇게 생성된 map 은 길이는 0, 사이즈는 5 가 되고, 길이가 사이즈 보다 커질 때에도 사이즈가 확장되어 key, value 를 추가할 수 있다. (사이즈 확장은 때에 따라 성능 감소의 요인이 될 수 있다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출력 결과와 같이 map 에 추가된 key, value 는 순서가 없다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;m := make(map[string]int, 5)
fmt.Println(len(m))

m[&quot;one&quot;] = 1
m[&quot;two&quot;] = 2
m[&quot;three&quot;] = 3
m[&quot;four&quot;] = 4
m[&quot;five&quot;] = 5
fmt.Println(m, len(m))

m[&quot;six&quot;] = 6
fmt.Println(m, len(m))

--- output ---
0
map[five:5 four:4 one:1 three:3 two:2] 5
map[five:5 four:4 one:1 six:6 three:3 two:2] 6&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;comma ok idiom&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;map 에서 없는 key 값으로 value 를 요청하면 value 타입의 zero 값이 리턴된다. 즉 에러가 발생하지 않는다.&lt;/p&gt;
&lt;pre class=&quot;go&quot;&gt;&lt;code&gt;m := map[string]int{
    &quot;one&quot;: 1,
    &quot;two&quot;: 2,
}
fmt.Println(m[&quot;three&quot;])

--- output ---
0&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;그렇기 때문에 해당 key 값의 value 가 제대로 넘어왔는지 알 수 있게 &lt;code&gt;,&lt;/code&gt; 로 구분되어 value 와 boolen 값이 리턴된다.&lt;/p&gt;
&lt;pre class=&quot;go&quot;&gt;&lt;code&gt;m := map[string]int{
    &quot;one&quot;: 1,
    &quot;two&quot;: 2,
}

v, ok := m[&quot;one&quot;]
fmt.Println(v, ok)

v, ok = m[&quot;three&quot;]
fmt.Println(v, ok)

--- output ---
1 true
0 false&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;map 의 item 을 삭제하려면 &lt;code&gt;delete 내장 함수&lt;/code&gt; 를 사용한다. delete 함수에 첫번째 아규먼트에는 map 을, 두번째 아규먼트에는 key 를 넣으면 된다. 해당 key 가 map 에 없다고 해서 에러를 만들지는 않는다.&lt;/p&gt;
&lt;pre class=&quot;go&quot;&gt;&lt;code&gt;m := map[string]int{
    &quot;one&quot;: 1,
    &quot;two&quot;: 2,
}

delete(m, &quot;one&quot;)
fmt.Println(m)
delete(m, &quot;three&quot;)

--- output ---
map[two:2]&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;map 의 key 는 중복될 수 없다. key, value 를 추가하는데 기존의 map 에 key 가 존재한다면, key 에 해당 하는 value 값이 업데이트 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Go 에는 Set 타입이 없는데 참고로 key 가 중복될 수 없다는 이 특징을 잘 활용하면 Set 을 구현할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;go&quot;&gt;&lt;code&gt;m := map[string]int{
    &quot;one&quot;: 1,
    &quot;two&quot;: 2,
}
m[&quot;two&quot;] = 3
fmt.Println(m)

--- output ---
map[one:1 two:3]&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;</description>
      <category>프로그래밍/Go</category>
      <category>comma ok idiom</category>
      <category>go</category>
      <category>golang</category>
      <category>Map</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/300</guid>
      <comments>https://ahnseungkyu.com/300#entry300comment</comments>
      <pubDate>Thu, 30 Jun 2022 20:55:25 +0900</pubDate>
    </item>
    <item>
      <title>(go-03) Go Slice 타입</title>
      <link>https://ahnseungkyu.com/299</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=UH_f6WL4N08&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/QQGh9/hyO14FjXEu/ScLd974izUDqLWwsd4RF2K/img.jpg?width=480&amp;amp;height=360&amp;amp;face=0_0_480_360&quot; data-video-width=&quot;480&quot; data-video-height=&quot;360&quot; data-video-origin-width=&quot;480&quot; data-video-origin-height=&quot;360&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/UH_f6WL4N08&quot; width=&quot;480&quot; height=&quot;360&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본 내장 타입에 추가하여 Array, Slice, Map 타입에 대해서 살펴본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Go 에서는 Array 는 거의 사용하지 않는다. 그러므로 이번에는 Slice 와 Map 타입에 대해서만 살펴 본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 Go 에서는 &lt;code&gt;nil&lt;/code&gt; 이라는 값이 있다. 이는 값이 없다라는 뜻인데, 기본 타입에는 이 &lt;code&gt;nil&lt;/code&gt; 과의 비교문 (&lt;code&gt;==&lt;/code&gt;)을 쓸 수 없다. (이전에 기본 타입은 전부 zero 값이 &lt;code&gt;nil&lt;/code&gt; 이 아니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;**nil&lt;/code&gt; 과 비교문이 가능한 타입은 앞으로 설명할 slice, map, pointer 이며, 이 3개의 zero 값이 &lt;code&gt;nil&lt;/code&gt; 이다.**&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;Slice&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;slice 는 값을 순차적으로 가질 수 있는 데이터 구조이다. 파이썬에서는 list 와 비슷하다고 생각하면 된다. 단지 다른 것은 하나의 slice 에는 사전에 지정된 타입만 저장될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 &lt;code&gt;int&lt;/code&gt; 타입을 &lt;code&gt;slice&lt;/code&gt; 저장 한 후에 출력한 결과이다. &lt;code&gt;[]&lt;/code&gt; 는 slice 를 만들겠다는 의미이고, 바로 이어서 &lt;code&gt;type&lt;/code&gt; 이 오며, 초기값을 지정하기 위해서 &lt;code&gt;{ }&lt;/code&gt; 를 사용한다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;var s = []int{1, 2, 3, 4, 5}
fmt.Println(s)

--- output ---
[1 2 3 4 5]&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;slice 는 초기화 값을 지정하지 않으면 &lt;code&gt;nil&lt;/code&gt; 을 나타낸다. 즉, 변수 선언만 하면 항상 &lt;code&gt;nil&lt;/code&gt; 값을 갖게 된다. &lt;code&gt;len&lt;/code&gt; 과 &lt;code&gt;cap&lt;/code&gt; 을 사용하면 slice 가 가지가 있는 길이와 용량을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Slice 는 연속적인 값을 가지고 있는 메모리 주소인&lt;span&gt; &lt;/span&gt;포인터,&lt;span&gt;&amp;nbsp;&lt;/span&gt;길이,&lt;span&gt;&amp;nbsp;&lt;/span&gt;용량&lt;span&gt;&amp;nbsp;&lt;/span&gt;으로 구성되어 있다.&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(이 부분은 매우 중요하다.)&lt;/span&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;아래 s1 은 nil 값이기 때문에 len 과 cap 이 모두 0 이다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;var s1 []int
fmt.Println(s1 == nil)
fmt.Println(len(s1), cap(s1))

--- output ---
true
0 0&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;슬라이스는 배열처럼 사용하여 &lt;code&gt;s1[0]&lt;/code&gt; 첫번째 값을 가져올 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 선언만 하여 nil 인 상태에서는 해당 index 를 사용하게 되면 런타임 에러가 난다.&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;var s1 []int
fmt.Println(s1[0])

--- output ---
panic: runtime error: index out of range [0] with length 0&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;&lt;b&gt;s1 slice 가 nil 인 상태에서도 &lt;code&gt;append&lt;/code&gt; 내장 함수를 사용하면 값을 추가할 수 있다(그렇기 때문에 특별한 경우를 제외하고는 nil 값인 변수 선언만 하여 사용하면 된다).&lt;/b&gt; append 함수를 쓰면 nil 이라 하더라도 slice 에 값을 추가 할 수 있다. 물론 값이 추가된 결과 return 값은 변수에 할당해야 한다. (변수가 달라도 됨)&lt;/p&gt;
&lt;pre class=&quot;mipsasm&quot;&gt;&lt;code&gt;var s1 []int
s1 = append(s1, 1)
fmt.Println(s1)

--- output ---
[1]&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;slice 에 slice 를 합쳐서 추가할 수 있다. python 의 extend 와 비슷하다고 보면된다. 두번째 slice 에는 여러 아규먼트가 들어간다는 것을 표현해 주기 위해서 &lt;code&gt;...&lt;/code&gt; 을 붙혀야 한다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;var s1 []int
s1 = append(s1, 1)

s2 := []int{2, 3, 4, 5}
s1 = append(s1, s2...)  // append(s1, 2, 3, 4, 5) 와 동일함
fmt.Println(s1)&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;slice 는 값이 추가되어 길이가 커져서 용량에 도달하면 용량이 자동으로 확장된다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;var s []int
fmt.Println(s, len(s), cap(s))
s = append(s, 1)
fmt.Println(s, len(s), cap(s))
s = append(s, 2)
fmt.Println(s, len(s), cap(s))
s = append(s, 3)
fmt.Println(s, len(s), cap(s))
s = append(s, 4)
fmt.Println(s, len(s), cap(s))
s3 := append(s, 5)
fmt.Println(&quot;s:&quot;, s, len(s), cap(s))
fmt.Println(&quot;s3&quot;, s3, len(s3), cap(s3))

-- output ---
[] 0 0
[1] 1 1
[1 2] 2 2
[1 2 3] 3 4
[1 2 3 4] 4 4
s: [1 2 3 4] 4 4
s3 [1 2 3 4 5] 5 8&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;make 내장 함수&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;slice 와 map 에서 &lt;code&gt;make&lt;/code&gt; 내장 함수를 사용하면 &lt;code&gt;nil&lt;/code&gt; 이 아닌 &lt;code&gt;empty slice&lt;/code&gt; 를 만들 수 있다. make 함수의 첫번째 아큐먼트는 slice type, 두번째는 길이, 세번째는 용량이다. 세번째 용량은 생략이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 make 로 생성한 s 는 nil 과의 비교가 false 임을 알 수 있다.&lt;/p&gt;
&lt;pre class=&quot;go&quot;&gt;&lt;code&gt;s := make([]int, 0, 5)
fmt.Println(s == nil)
fmt.Println(s, len(s), cap(s))

--- output ---
false
[] 0 5
&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;make 로 길이를 지정하면 그 길이 만큼은 zero 값이 채워진 slice 가 만들어 진다. 그러니 필요없이 길이를 1 이상으로 지정하면 초기 메모리만 차지할 수 있다. 아래는 make 로 만든 s1 slice 에 0번째와 1번째 index 까지 0 값이 채워진 것을 볼 수 있다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;s1 := make([]int, 2)
fmt.Println(s1)

s1 = append(s1, 1)
fmt.Println(s1)

--- output ---
[0 0]
[0 0 1]&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;길이가 0 인 slice 는 아래와 같이 만들 수 도 있다. nil 이 아니면서 길이가 0 인 slice 는 JSON 으로 변환할 때 사용된다.&lt;/p&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;var s = []int{}   // make([]int, 0) 와 동일하다.&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Slice 자르기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Slice 를 자르는 것은 &lt;code&gt;:&lt;/code&gt; 을 이용해서 자를 수 있다. 하지만 자른다고 해도 최종적으로 보는 Reference 는 동일하다. 아래를 보면 이를 이해할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫번째 단락에서 slice 를 자르면, b 는 0 index 이상, 3 index 미만 까지의 slice 를 갖고, c 는 2 index 이상 끝까지의 slice 값을 갖는다. &lt;b&gt;중요한 것은 c 처럼 중간에서 마지막까지 자른 slice 는 용량이 그 길이만큼으로 줄어든다는 것이다. (앞의 자른 부분이 없어졌기 때문이다)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두번째 단락에서 c[0] 에 30 을 대입하면 slice 자른 것은 같은 reference 를 바라보기 때문에 a 와 b 에 모두 영향을 준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세번째 단락도 마찬가지 이다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;a := []int{1, 2, 3, 4, 5}
b := a[:3]
c := a[2:]
fmt.Println(&quot;cap(a):&quot;, cap(a), &quot;cap(b):&quot;, cap(b), &quot;cap(c):&quot;, cap(c))
fmt.Println(&quot;a:&quot;, a)
fmt.Println(&quot;b:&quot;, b)
fmt.Println(&quot;c:&quot;, c)
fmt.Println(&quot;================&quot;)

c[0] = 30
fmt.Println(&quot;a:&quot;, a)
fmt.Println(&quot;b:&quot;, b)
fmt.Println(&quot;c:&quot;, c)
fmt.Println(&quot;================&quot;)

b = append(b, 40)
fmt.Println(&quot;a:&quot;, a)
fmt.Println(&quot;b:&quot;, b)
fmt.Println(&quot;c:&quot;, c)

--- output ---
cap(a): 5 cap(b): 5 cap(c): 3
a: [1 2 3 4 5]
b: [1 2 3]
c: [3 4 5]
================
a: [1 2 30 4 5]
b: [1 2 30]
c: [30 4 5]
================
a: [1 2 30 40 5]
b: [1 2 30 40]
c: [30 40 5]&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;&lt;b&gt;Slice 를 자른 것이 append 를 사용해서 추가할 때 같은 레퍼런스를 처다보지 않게 하려면, 용량을 길이와 동일하게 하면 된다. 그러면 append 했을 경우 용량이 초과되어 새로운 slice 가 생겨서 return 되므로 서로 영향이 가지 않는다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 처럼 a 를 잘라서 b 를 만들 때 &lt;code&gt;:3:3&lt;/code&gt; 과 같이 마지막에 용량 3을 추가하여 b slice 의 길이와 용량을 똑같이 맞췄다. 그렇게 되면 c[0] 처럼 값을 바꾸는 것은 영향을 받지만, append(b, 40) 과 같이 append 한 것은 새로운 slice 가 만들어져서 return 되므로 a 와 c 에 영향을 주지 않는다.&lt;/p&gt;
&lt;pre class=&quot;go&quot; data-ke-language=&quot;go&quot;&gt;&lt;code&gt;a := []int{1, 2, 3, 4, 5}
b := a[:3:3]
c := a[2:]
fmt.Println(&quot;cap(a):&quot;, cap(a), &quot;cap(b):&quot;, cap(b), &quot;cap(c):&quot;, cap(c))
fmt.Println(&quot;a:&quot;, a)
fmt.Println(&quot;b:&quot;, b)
fmt.Println(&quot;c:&quot;, c)

fmt.Println(&quot;===== (c[0] = 30) =====&quot;)
c[0] = 30
fmt.Println(&quot;cap(a):&quot;, cap(a), &quot;cap(b):&quot;, cap(b), &quot;cap(c):&quot;, cap(c))
fmt.Println(&quot;a:&quot;, a)
fmt.Println(&quot;b:&quot;, b)
fmt.Println(&quot;c:&quot;, c)

fmt.Println(&quot;===== append(b, 40) ======&quot;)
b = append(b, 40)
b[0] = 10
fmt.Println(&quot;cap(a):&quot;, cap(a), &quot;cap(b):&quot;, cap(b), &quot;cap(c):&quot;, cap(c))
fmt.Println(&quot;a:&quot;, a)
fmt.Println(&quot;b:&quot;, b)
fmt.Println(&quot;c:&quot;, c)


--- output ---
cap(a): 5 cap(b): 3 cap(c): 3
a: [1 2 3 4 5]
b: [1 2 3]
c: [3 4 5]
===== (c[0] = 30) =====
cap(a): 5 cap(b): 3 cap(c): 3
a: [1 2 30 4 5]
b: [1 2 30]
c: [30 4 5]
===== append(b, 40) ======
cap(a): 5 cap(b): 6 cap(c): 3
a: [1 2 30 4 5]
b: [10 2 30 40]
c: [30 4 5]
c: [30 4 5]
===== append(b, 40) ======
a: [1 2 30 4 5]
b: [1 2 30 40]
c: [30 4 5]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>프로그래밍/Go</category>
      <category>go</category>
      <category>nil</category>
      <category>slice</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/299</guid>
      <comments>https://ahnseungkyu.com/299#entry299comment</comments>
      <pubDate>Thu, 30 Jun 2022 19:32:53 +0900</pubDate>
    </item>
    <item>
      <title>(go-02) Go 기본 타입 설명</title>
      <link>https://ahnseungkyu.com/298</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=Sfen-TEEBsg&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/bbd3DV/hyOW3Gj5bs/vvIRIEKzKl0f1KbIuXCik0/img.jpg?width=480&amp;amp;height=360&amp;amp;face=0_0_480_360&quot; data-video-width=&quot;480&quot; data-video-height=&quot;360&quot; data-video-origin-width=&quot;480&quot; data-video-origin-height=&quot;360&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/Sfen-TEEBsg&quot; width=&quot;480&quot; height=&quot;360&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C 와 Java 를 안다면 Go 를 공부하면 헷갈리는 부분들이 다소 있다. 일반적으로 기본 내장 타입은 비슷해서 이해하기 쉽지만 pointer 와 interface 등을 공부하다 보면 헷갈리기 마련이다.&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;h1&gt;Built-in Type&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본 내장 타입에는 boolean, integer, rune, float, byte, string 이 있다. 물론 complex type 도 있지만 이는 생략하겠다. 기본 내장 타입은 zero 값을 갖고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 중에서 숫자 타입은 integer, rune, float 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;boolean&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;boolean 의 zero 값은 false 이다.&lt;/p&gt;
&lt;pre class=&quot;go&quot; data-ke-language=&quot;go&quot;&gt;&lt;code&gt;var isDev bool
var isTrue = true

fmt.Println(isDev)
fmt.Println(isTrue)

--- output ---
false
true&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변수 선언은 &lt;code&gt;var 변수명 타입&lt;/code&gt; 으로 선언할 수 있다. 이렇게 설명하면 zero 값으로 false 가 자동 대입된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 방법은 &lt;code&gt;var 변수명 = 값&lt;/code&gt; 과 같이 변수를 선언하면서 값을 대입하는 것이다. 그럼 값을 보고 알아서 타입을 결정해 준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Integer (숫자 타입 중 하나)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Integer type 은 &lt;code&gt;int8, int16, int32, int64, uint8, uint16, uint32, uint64&lt;/code&gt; 이다. 그리고 특별한 integer 타입으로 &lt;code&gt;byte&lt;/code&gt; 와 &lt;code&gt;rune&lt;/code&gt; 타입이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;byte&lt;/code&gt; 는 &lt;code&gt;uint8&lt;/code&gt; 의 별칭으로 &lt;code&gt;unit8&lt;/code&gt; 보다는 &lt;code&gt;byte&lt;/code&gt; 를 주로 쓰게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;rune&lt;/code&gt; 은 &lt;code&gt;int32&lt;/code&gt; 의 별칭이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 Integer Type 은 &lt;code&gt;int&lt;/code&gt; 로 많이 사용하는데, 32bit cpu 이면 int32, 64bit cpu 이면 int64 와 동일하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;int 의 zero 값은 0 이다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;var x int
var y int = 1
var z = 2
fmt.Println(x)
fmt.Println(y)
fmt.Println(z)

--- output ---
0
1
2&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Float (숫자 타입 중 하나)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Float type 은 &lt;code&gt;float32, float64&lt;/code&gt; 이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;float type 의 zero 값은 int 와 동일하게 0 이다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;var p float64
var q = 0.0
fmt.Println(p)
fmt.Println(q)

--- output ---
0
0&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;숫자 타입 간에는 편하게 해당 타입으로 변환이 가능하다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;var x int = 10
var p float64 = 20.2
fmt.Println(x + int(p))
fmt.Println(float64(x) + p)

--- output ---
30
30.2&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;String&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;string&lt;/code&gt; 의 zero 값은 empty string 이다. Java 에서는 null string 이 있지만 Go 에서는 null 이 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;string&lt;/code&gt; 과 자주 사용되는 타입은 &lt;code&gt;rune&lt;/code&gt; 과 &lt;code&gt;byte&lt;/code&gt; 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞에서 숫자 타입은 서로 타입 변환이 해당 타입으로 감싸주면 된다고 설명했는데 &lt;code&gt;string, rune, byte&lt;/code&gt; 도 서로 타입 변환이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Go 최신 버전에서는 숫자 타입을 단순히 string 으로 감싸는 것은 체크 시에 에러가 발생한다.&lt;/p&gt;
&lt;pre class=&quot;go&quot;&gt;&lt;code&gt;var r rune = 'r'
var s string = string(r)
var b byte = 'b'
var s2 string = string(b)
fmt.Println(r)
fmt.Println(b)
fmt.Println(s)
fmt.Println(s2)

--- output ---
114
98
r
b&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;rune&lt;/code&gt; 과 &lt;code&gt;byte&lt;/code&gt; 는 &lt;code&gt;int&lt;/code&gt; 타입의 별칭이라 숫자 값이 출력된 것을 이해하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나중에 설명하겠지만 &lt;code&gt;[]&lt;/code&gt; 를 사용하여 &lt;code&gt;slice&lt;/code&gt; (배열과 비슷한) 타입을 활용하면 &lt;code&gt;string&lt;/code&gt; 을 &lt;code&gt;[]byte&lt;/code&gt; 혹은 &lt;code&gt;[]rune&lt;/code&gt; 으로 변환할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;lsl&quot;&gt;&lt;code&gt;var s string = &quot;Hello,  &quot;
var bs []byte = []byte(s)
var rs []rune = []rune(s)
fmt.Println(bs)
fmt.Println(rs)

--- output ---
[72 101 108 108 111 44 32 240 159 152 128]
[72 101 108 108 111 44 32 128512]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  이모지 값은 utf-8 으로 표시해야 되기 때문에 &lt;code&gt;byte&lt;/code&gt; 는 [240 159 152 128] 와 같이 4 바이트로 표시되고 &lt;code&gt;rune&lt;/code&gt; 은 [128512] 로 표시된다. byte 는 int8 이고, rune 은 int32 임을 기억하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 보면 string 은 rune 으로 변환하는 것이 편리하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 &lt;b&gt;Short Variable Delcaration Operator&lt;/b&gt;(&lt;code&gt;:=&lt;/code&gt;) 를 사용하여 &lt;code&gt;var&lt;/code&gt; 와 &lt;code&gt;type&lt;/code&gt; 키워드 없이 변수를 선언하고 바로 할당할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;var a, b int = 1, 2
var c, d = 3, &quot;a&quot;

i := 10
x, s := 20.5, &quot;Hello World&quot;

--- output ---
1 2 3 a
10 20.5 Hello World&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;</description>
      <category>프로그래밍/Go</category>
      <category>go</category>
      <category>golang</category>
      <category>type</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/298</guid>
      <comments>https://ahnseungkyu.com/298#entry298comment</comments>
      <pubDate>Thu, 30 Jun 2022 09:30:55 +0900</pubDate>
    </item>
    <item>
      <title>(go-01) Mac golang 개발환경 설정하기 (VS Code)</title>
      <link>https://ahnseungkyu.com/297</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=KgsS8Lc4PHo&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/dzNJUy/hyOVX8mY3u/0oCNDQKNYsVa3KckIiLT0K/img.jpg?width=480&amp;amp;height=360&amp;amp;face=0_0_480_360&quot; data-video-width=&quot;480&quot; data-video-height=&quot;360&quot; data-video-origin-width=&quot;480&quot; data-video-origin-height=&quot;360&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/KgsS8Lc4PHo&quot; width=&quot;480&quot; height=&quot;360&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Kubernetes source code 를 디버깅하면서 분석하기 위해 golang 환경 설정과 사용을 계속해서 설명하고자 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 첫번째로 무료 IDE 인 (thx MS) VSCode 를 설치하고 세팅하는 법을 알아보자.&lt;/p&gt;
&lt;h1&gt;golang 설치&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;mac 에서 golang 은 home brew 로 간단히 설치할 수 있다. 혹시 라도 이전에 낮은 버전이 설치되어 있는지 확인한다.&lt;/p&gt;
&lt;div data-language=&quot;bash&quot;&gt;
&lt;pre class=&quot;vim&quot;&gt;&lt;code&gt;$ brew list | grep go
$ go@1.12

$ go version
go version go1.12.9 darwin/amd64&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로운 버전을 install 한다.&lt;/p&gt;
&lt;div data-language=&quot;bash&quot;&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;$ brew install go@1.16&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 1.12 버전을 unlink 한다.&lt;/p&gt;
&lt;div data-language=&quot;bash&quot;&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;$ brew unlink go&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로운 버전을 link 한다.&lt;/p&gt;
&lt;div data-language=&quot;bash&quot;&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;$ brew link --force go@1.16&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로운 버전을 check 하면 업그레이드 되어 있는 것을 알 수 있다.&lt;/p&gt;
&lt;div data-language=&quot;bash&quot;&gt;
&lt;pre class=&quot;vim&quot;&gt;&lt;code&gt;$ go version
go version go1.16.14 darwin/amd64&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h1&gt;Go Workspace&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;go 는 install 명령어로 다른 go tool 들을 설치할 수 있다. 설치 위치는 workspace 라고 부르는 곳인데 특별히 지정하지 않으면 디폴트로 $HOME/go 디렉토리에 설치 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;go install 로 설치된 툴들은 소스는 $HOME/go/src 에, 바이너리 실행파일은 $HOME/go/bin 에 설치된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;workspace 는 변경할 수 있는데 아래와 같이 .zshrc (zsh 일 경우) 이나 .bash_profile (bash 일 경우) 파일에 환경 변수를 추가하면 된다. 설정하기 전에 해당 workspace 디렉토리는 미리 만들어 줘야 한다.&lt;/p&gt;
&lt;div data-language=&quot;bash&quot;&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;## 디렉토리 만들기
$ mkdir -p $HOME/Documents/go_workspace

## .zshrc 파일에 환경변수 세팅
export GOPATH=$HOME/Documents/go_workspace
export PATH=$PATH:$GOPATH/bin&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h1&gt;Go Tool 설치&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 체크해 주는 golint 툴이 있다. 이를 설치해 보자&lt;/p&gt;
&lt;div data-language=&quot;bash&quot;&gt;
&lt;pre class=&quot;groovy&quot;&gt;&lt;code&gt;$ go install golang.org/x/lint/golint@latest

$ which golint
/Users/ahnsk/Documents/go_workspace/bin/lint&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 디렉토리에서 lint 체크를 하고 싶으면 아래 명령어를 쓰면 된다. 코드를 만든 프로젝트 디렉토리에서 수행하면 모든 파일을 lint 한다.&lt;/p&gt;
&lt;div data-language=&quot;bash&quot;&gt;
&lt;pre class=&quot;elixir&quot;&gt;&lt;code&gt;$ golint ./...&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 go 를 설치하면 일부 tool 들은 자동으로 설치되는데 그 중 vet 이라는 유용한 tool 있다. vet 은 error 를 잡아주는 tool 이다.&lt;/p&gt;
&lt;div data-language=&quot;bash&quot;&gt;
&lt;pre class=&quot;elixir&quot;&gt;&lt;code&gt;$ go vet ./...&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h1&gt;VS Code 설치&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VS Code 는 아래 url 에 접속해서 OS 별로 설치하면 된다. 설치 화면은 생략한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://code.visualstudio.com/Download&quot;&gt;https://code.visualstudio.com/Download&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VS Code 를 띄우고 나서 아무 화면에서나&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;Cmd&lt;/span&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;+&lt;/span&gt;&lt;span&gt;Shift&lt;/span&gt;&lt;span style=&quot;color: #f8f8f2;&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color: #f92672;&quot;&gt;P&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;키를 입력하면 Command Palette 가 화면 위에 생성된다. 거기에서 shell command 로 검색하여 install &amp;lsquo;code&amp;rsquo; command in PATH 를 선택한다.&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;607&quot; data-origin-height=&quot;86&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BZR7W/btrFHq6dbiW/7l3opCCZiTdkUQRLO6p8pk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BZR7W/btrFHq6dbiW/7l3opCCZiTdkUQRLO6p8pk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BZR7W/btrFHq6dbiW/7l3opCCZiTdkUQRLO6p8pk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBZR7W%2FbtrFHq6dbiW%2F7l3opCCZiTdkUQRLO6p8pk%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;607&quot; height=&quot;86&quot; data-origin-width=&quot;607&quot; data-origin-height=&quot;86&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;span&gt;&amp;nbsp;&lt;/span&gt;code&lt;span&gt;&amp;nbsp;&lt;/span&gt;명령어를 이력하면 VS Code 가 실행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같이 go-sample 디렉토리에서 실행하면 VS Code 가 뜨는 것을 볼 수 있다.&lt;/p&gt;
&lt;div data-language=&quot;bash&quot;&gt;
&lt;pre class=&quot;shell&quot;&gt;&lt;code&gt;$ cd go-sample
$ code&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1483&quot; data-origin-height=&quot;903&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ACw07/btrFGShCs0l/4ISEZKUiC3TOeeaHK3dak0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ACw07/btrFGShCs0l/4ISEZKUiC3TOeeaHK3dak0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ACw07/btrFGShCs0l/4ISEZKUiC3TOeeaHK3dak0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FACw07%2FbtrFGShCs0l%2F4ISEZKUiC3TOeeaHK3dak0%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;1483&quot; height=&quot;903&quot; data-origin-width=&quot;1483&quot; data-origin-height=&quot;903&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h1&gt;VS Code Extension 설치&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VS Code 는 다양한 Extension 을 설치할 수 있다. 그 중에 go 를 써야 하니 Go extension 을 설치해 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VS Code 화면에 보면 맨 좌측에 세로로 아이콘들이 여러개 있다. 그 중 위에서 5번째 혹은 6번째에 있는 extension 아이콘을 선택하고 go 를 검색해서 go Team at Google 에서 만든 Go 를 설치해 준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 그림에서 맨 처음 줄의 Go 의 install 파란 버튼을 클릭해서 설치한다.&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;399&quot; data-origin-height=&quot;904&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3ZAS8/btrFHJj6TVI/6sMwOAYgYJvWLoYCFc6Jr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3ZAS8/btrFHJj6TVI/6sMwOAYgYJvWLoYCFc6Jr1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3ZAS8/btrFHJj6TVI/6sMwOAYgYJvWLoYCFc6Jr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3ZAS8%2FbtrFHJj6TVI%2F6sMwOAYgYJvWLoYCFc6Jr1%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;399&quot; height=&quot;904&quot; data-origin-width=&quot;399&quot; data-origin-height=&quot;904&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;hello world 를 출력하는 간단한 소스를 만들어서 실행해 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VS Code 에서 새로운 파일을 생성해서 main.go 파일을 만들어서 저장한다.&lt;/p&gt;
&lt;div data-language=&quot;bash&quot;&gt;
&lt;pre class=&quot;go&quot;&gt;&lt;code&gt;package main

import &quot;fmt&quot;

func main() {
	fmt.Println(&quot;Hello world!!!&quot;)
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VS Code 상단 메뉴에 Terminal &amp;gt;&amp;gt; New Terminal 을 클릭하면 터미널을 VS Code 에서 사용할 수 있다.&lt;/p&gt;
&lt;div data-language=&quot;bash&quot;&gt;
&lt;pre class=&quot;erlang-repl&quot;&gt;&lt;code&gt;$ go run main.go
Hello world!!!&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VS Code 화면을 보면 다음과 같다.&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;884&quot; data-origin-height=&quot;902&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vqYNM/btrFGy4IpDb/Kwf2mhpduqK46CyeICWhhK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vqYNM/btrFGy4IpDb/Kwf2mhpduqK46CyeICWhhK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vqYNM/btrFGy4IpDb/Kwf2mhpduqK46CyeICWhhK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvqYNM%2FbtrFGy4IpDb%2FKwf2mhpduqK46CyeICWhhK%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;884&quot; height=&quot;902&quot; data-origin-width=&quot;884&quot; data-origin-height=&quot;902&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 세팅은 모두 끝났다. 디버깅 세팅하는 방법이 있는데 go 를 설명하다가 어느 정도 지나면 디버깅 세팅도 추가로 올릴 예정이다.&lt;/p&gt;</description>
      <category>프로그래밍/Go</category>
      <category>go</category>
      <category>Go 세팅</category>
      <category>golang</category>
      <category>Mac에서 Go 세팅</category>
      <category>vs code</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/297</guid>
      <comments>https://ahnseungkyu.com/297#entry297comment</comments>
      <pubDate>Sat, 25 Jun 2022 14:37:38 +0900</pubDate>
    </item>
    <item>
      <title>python package, module import 방법</title>
      <link>https://ahnseungkyu.com/296</link>
      <description>&lt;pre id=&quot;code_1655783851737&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.
├── config
│&amp;nbsp;&amp;nbsp; ├── __init__.py
│&amp;nbsp;&amp;nbsp; ├── __pycache__
│&amp;nbsp;&amp;nbsp; │&amp;nbsp;&amp;nbsp; ├── __init__.cpython-39.pyc
│&amp;nbsp;&amp;nbsp; │&amp;nbsp;&amp;nbsp; ├── settings.cpython-39.pyc
│&amp;nbsp;&amp;nbsp; │&amp;nbsp;&amp;nbsp; ├── urls.cpython-39.pyc
│&amp;nbsp;&amp;nbsp; │&amp;nbsp;&amp;nbsp; ├── views.cpython-39.pyc
│&amp;nbsp;&amp;nbsp; │&amp;nbsp;&amp;nbsp; └── wsgi.cpython-39.pyc
│&amp;nbsp;&amp;nbsp; ├── asgi.py
│&amp;nbsp;&amp;nbsp; ├── settings.py
│&amp;nbsp;&amp;nbsp; ├── urls.py
│&amp;nbsp;&amp;nbsp; ├── views.py
│&amp;nbsp;&amp;nbsp; └── wsgi.py
├── db.sqlite3
├── firstapp
│&amp;nbsp;&amp;nbsp; ├── __init__.py
│&amp;nbsp;&amp;nbsp; ├── __pycache__
│&amp;nbsp;&amp;nbsp; │&amp;nbsp;&amp;nbsp; ├── __init__.cpython-39.pyc
│&amp;nbsp;&amp;nbsp; │&amp;nbsp;&amp;nbsp; ├── urls.cpython-39.pyc
│&amp;nbsp;&amp;nbsp; │&amp;nbsp;&amp;nbsp; └── views.cpython-39.pyc
│&amp;nbsp;&amp;nbsp; ├── admin.py
│&amp;nbsp;&amp;nbsp; ├── apps.py
│&amp;nbsp;&amp;nbsp; ├── migrations
│&amp;nbsp;&amp;nbsp; │&amp;nbsp;&amp;nbsp; └── __init__.py
│&amp;nbsp;&amp;nbsp; ├── models.py
│&amp;nbsp;&amp;nbsp; ├── tests.py
│&amp;nbsp;&amp;nbsp; ├── urls.py
│&amp;nbsp;&amp;nbsp; └── views.py
└── manage.py&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 django 디렉토리가 있을 때 package, module import 하는 방법이 헷갈려서 정리하는 차원이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 하위 디렉토리 config 와 firstapp 은 패키지 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 config 아래의 urls.py 와 같은 python 파일은 모듈이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;import 방법은 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;import {패키지}.{모듈}&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;import {패키지}.{모듈}.{함수}&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;from {패지키} import {모듈}&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;from {패키지}.{모듈} import {함수}&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-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>프로그래밍/Python</category>
      <category>module import</category>
      <category>Package</category>
      <category>Python</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/296</guid>
      <comments>https://ahnseungkyu.com/296#entry296comment</comments>
      <pubDate>Tue, 21 Jun 2022 13:06:44 +0900</pubDate>
    </item>
    <item>
      <title>Kubernetes Scheduler 살펴보기</title>
      <link>https://ahnseungkyu.com/294</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Pod 가 새롭게 생성되면 Scheduler 를 통해서 Pod 가 실행될 노드가 결정된다. 즉 모든 Pod 는 Scheduler 에 의해서 최적의 노드가 결정되고 실행된다.&lt;/p&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-scheduler 는 Control Plane 에 속하는 컴포넌트 중에 하나이며, 디폴트 scheduler 이다. 만약 특별한 스케줄링을 원한다며 커스텀 스케줄러를 만들어서 대체할 수 도 있다.&lt;/p&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 가 스케줄링 되기 위해서는 노드가 스케줄링 요구 사항에 맞아야 하는데 이 때, 요구사항에 맞는 노드를 피저블 노드(feasible 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;스케줄러는 피저블 노드를 찾고 적절한 로직을 통해 노드에 점수를 부여한다. 가장 최고 점수를 갖는 노드에 Pod 가 실행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스케줄링을 결정하는 데에는 하드웨어, 소프트웨어, policy contraints, affinity 와 anti-affinity spec, local data 등 여러 요구 사항들이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;kube-scheduler 가 결정하는 2-step operation&lt;/h1&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Filtering&lt;/li&gt;
&lt;li&gt;Scoring&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Filtering 단계에서는 피저블 노드를 찾는 단계이다. 예를 들면, PodFitsResources 필터는 Pod 의 request 리소스를 만족하는 리소스를 갖는 후보 노드를 추려낸다. 이 단계 이후에는 적합한 노드 리스트가 도출되는데 만약 노드 리스트의 값이 비었다면 Pod 는 스케줄링 되지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Scoring 단계에서는 필터링된 노드 리스트 중에서 Pod 가 실행될 최적의 노드를 찾는다. 스케줄러는 노드 리스트에 있는 각 노드들에 점수를 부여한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 kube-scheduler 는 최고 점수의 노드에 Pod 를 배치한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Filtering 과 Scoring 을 설정할 수 있는 방법은 2가지가 있다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Scheduling Policies (kubernetes 1.22 버전까지만 사용)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Predicates : filtering 을 조절할 수 있음&lt;/li&gt;
&lt;li&gt;Priorities: scoring 을 조절할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Scheduling Profiles (&lt;a href=&quot;https://kubernetes.io/docs/reference/scheduling/config/#profiles&quot;&gt;https://kubernetes.io/docs/reference/scheduling/config/#profiles&lt;/a&gt;)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;KubeSchedulerConfiguration 리소스 타입으로 조절할 수 있음&lt;/li&gt;
&lt;li&gt;plugins 를 통해 Filter 와 Score 를 조절 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;nodeSelector&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Node 에 label 을 설정하고 Pod 에서 nodeSelector 로 Node 지정하는 방식이다.&lt;/p&gt;
&lt;pre class=&quot;lsl&quot;&gt;&lt;code&gt;$ kubectl get nodes -L nginx
NAME          STATUS   ROLES                  AGE   VERSION   NGINX
k1-master01   Ready    control-plane,master   92d   v1.21.6
k1-node01     Ready    ingress                92d   v1.21.6
k1-node02     Ready    &amp;lt;none&amp;gt;                 92d   v1.21.6   enabled
k1-node03     Ready    &amp;lt;none&amp;gt;                 92d   v1.21.6   enabled
k1-node04     Ready    &amp;lt;none&amp;gt;                 92d   v1.21.6
k1-node05     Ready    &amp;lt;none&amp;gt;                 92d   v1.21.6&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;k1-node02 와 k1-node03 에 nginx=enabled 로 label 이 지정되어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-nodeselector
  namespace: kube-sample
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.21.0
        ports:
        - containerPort: 80
      nodeSelector:
        nginx: enabled&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;nodeSelector 를 활용하여 deployment 를 배포하면 아래와 같이 k1-node02 혹은 k1-node03 에 배포된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;$ kubectl get pods -n kube-sample -o wide
NAME                                  READY   STATUS    RESTARTS   AGE   IP             NODE        NOMINATED NODE   READINESS GATES
nginx-nodeselector-68977d7759-sf48l   1/1     Running   0          9s    10.233.113.7   k1-node02   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;Node affinity&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;nodeSelector 와 동작 방식이 유사하지만 다음과 같은 차이가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;requiredDuringSchedulingIgnoredDuringExecution: 스케줄링에서 만족하는 노드가 없으면 스케줄링 되지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;preferredDuringSchedulingIgnoredDuringExecution: 스케줄링에서 만족하는 노드를 찾고 노드가 없더라도 스케줄링은 된다. weight 필드의 값을 scoring 에 포함시킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-node-affinity
  namespace: kube-sample
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: nginx
                operator: In
                values:
                - enabled
            - matchExpressions:
              - key: kubernetes.io/os
                operator: In
                values:
                - windows
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 1
            preference:
              matchExpressions:
              - key: another-node-label-key
                operator: In
                values:
                - another-node-label-value
      containers:
      - name: nginx
        image: nginx:1.21.0
        ports:
        - containerPort: 80&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 nodeSelectorTerms 에 여러 개의 matchExpressions 가 있으면 이 중 하나만 만족해도 스케줄링은 된다. nodeSelectorTerms 에 하나의 matchExpressions 가 있고, key value 가 여러 개가 있으면 matchExpressions 내의 모든 조건을 만족해야 스케줄링이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;operator 로 쓸 수 있는 값은 &lt;code&gt;In&lt;/code&gt;, &lt;code&gt;NotIn&lt;/code&gt;, &lt;code&gt;Exists&lt;/code&gt;, &lt;code&gt;DoesNotExist&lt;/code&gt;, &lt;code&gt;Gt&lt;/code&gt;, &lt;code&gt;Lt&lt;/code&gt; 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;NotIn&lt;/code&gt; 과 &lt;code&gt;DoesNotExist&lt;/code&gt; 는 node anti-affinity 로 사용 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;$ kubectl get pods -n kube-sample -o wide
NAME                                   READY   STATUS        RESTARTS   AGE    IP              NODE        NOMINATED NODE   READINESS GATES
nginx-node-affinity-755cf7f85d-ss9q5   1/1     Running       0          5s     10.233.113.10   k1-node02   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;Pod affinity and anti-affinity&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pod 를 서로 다른 노드에 배치시키는 방법은 pod anti-affinity 를 통해서 구현할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-pod-anti-affinity
  namespace: kube-sample
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-pod-anti-affinity
  template:
    metadata:
      labels:
        app: nginx-pod-anti-affinity
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - nginx-pod-anti-affinity
            topologyKey: kubernetes.io/hostname
      containers:
      - name: nginx
        image: nginx:1.21.0
        ports:
        - containerPort: 80&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 pod label 에 pod anti affinity 를 설정하면 replicas 값 2 에 의해서 생성되는 2개의 pod 는 서로 다른 노드에 배치된다. topologyKey 는 kubernetes.io/hostname 값으로 세팅하고 특정 node lable 로 하고 싶으면 node affinity 를 추가하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-pod-anti-affinity
  namespace: kube-sample
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-pod-anti-affinity
  template:
    metadata:
      labels:
        app: nginx-pod-anti-affinity
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - nginx-pod-anti-affinity
            topologyKey: kubernetes.io/hostname
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: nginx
                operator: In
                values:
                - enabled
      containers:
      - name: nginx
        image: nginx:1.21.0
        ports:
        - containerPort: 80&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;$ kubectl get pods -n kube-sample -o wide
NAME                                       READY   STATUS    RESTARTS   AGE   IP              NODE        NOMINATED NODE   READINESS GATES
nginx-pod-anti-affinity-7cfcbcff8f-c2429   1/1     Running   0          14s   10.233.96.3     k1-node03   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
nginx-pod-anti-affinity-7cfcbcff8f-dmqqm   1/1     Running   0          14s   10.233.113.12   k1-node02   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;Taint 와 Toleration&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;노드에 taint 를 지정하면 해당 노드에 taint effect 를 줄 수 있다. 예를 들어 taint effect 에 NoSchedule 을 준다면 해당 노드에는 pod 가 스케줄링 되지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;taint effect 를 제거할 수 있는 방법은 Pod 에 toleration 을 세팅하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마스터에는 기본적으로 taint 를 지정해서 스케줄링 안되게 세팅해 놓는 것을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;$ kubectl describe node k1-master01

Name:               k1-master01
Roles:              control-plane,master
Labels:             beta.kubernetes.io/arch=amd64
                    beta.kubernetes.io/os=linux
                    kubernetes.io/arch=amd64
                    kubernetes.io/hostname=k1-master01
                    kubernetes.io/os=linux
                    node-role.kubernetes.io/control-plane=
                    node-role.kubernetes.io/master=
                    node.kubernetes.io/exclude-from-external-load-balancers=
Annotations:        kubeadm.alpha.kubernetes.io/cri-socket: /var/run/containerd/containerd.sock
                    node.alpha.kubernetes.io/ttl: 0
                    projectcalico.org/IPv4Address: 192.168.30.13/24
                    volumes.kubernetes.io/controller-managed-attach-detach: true
CreationTimestamp:  Tue, 08 Feb 2022 21:27:12 +0900
Taints:             node-role.kubernetes.io/master:NoSchedule&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막의 Taints 값은 kubectl 로 세팅할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;$ kubectl taint nodes k1-master01 node-role.kubernetes.io/master=:NoSchedule&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 master 노드에 toleration 을 활용하여 pod 를 배치해 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-toleration
  namespace: kube-sample
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-toleration
  template:
    metadata:
      labels:
        app: nginx-toleration
    spec:
      tolerations:
      - key: node-role.kubernetes.io/master
        operator: Exists
        effect: NoSchedule
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: node-role.kubernetes.io/control-plane
                operator: Exists
      containers:
      - name: nginx
        image: nginx:1.21.0
        ports:
        - containerPort: 80&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;toleration 으로 taint 효과를 없애고 node affinity 를 활용하여 control-plane, 즉 master 노드에 pod 를 배치 시켰다. 물론 master 노드에 node-role.kubernetes.io/control-plane 이라는 label 이 존재해야 한다.&lt;/p&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 effect 는 NoSchedule, NoExecute, PreferNoSchedule 이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NoSchedule 은 스케줄링을 막는 것이고, NoExecute 는 실행중인 pod 를 eviction 시킨다. PreferNoSchedule 은 가능하면 스케줄링 하지 않는다는 의미이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;operator 에는 Exists 와 Equal 이 있다. Exists 는 key 값이 존재하는 지를 판단하기 때문에 value 값이 필요 없으며, Equal 은 key 와 value 값이 지정된 값과 일치해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ kubectl get pods -n kube-sample -o wide
NAME                                       READY   STATUS    RESTARTS   AGE     IP              NODE          NOMINATED NODE   READINESS GATES
nginx-toleration-fb74cd98c-hkql8           1/1     Running   0          5m31s   10.233.117.4    k1-master01   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Kubernetes</category>
      <category>kube-scheduler</category>
      <category>kubernetes</category>
      <category>scheduler</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/294</guid>
      <comments>https://ahnseungkyu.com/294#entry294comment</comments>
      <pubDate>Fri, 13 May 2022 08:47:36 +0900</pubDate>
    </item>
    <item>
      <title>10분만에 이해하는 컨테이너 네트워크</title>
      <link>https://ahnseungkyu.com/293</link>
      <description>&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;h1&gt;Single Network Namespace&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구현하고자 하는 목표는 아래 다이어그램과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;red 네트워트 네임스페이스를 만들고 인터페이스를 만들어서 ip 를 할당하고 노드에서 ping 을 통해 통신이 가능한지 확인한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;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;924&quot; data-origin-height=&quot;580&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BxwmB/btrx9A2G74l/iRfpBmRTaOhqYUvJMRhtK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BxwmB/btrx9A2G74l/iRfpBmRTaOhqYUvJMRhtK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BxwmB/btrx9A2G74l/iRfpBmRTaOhqYUvJMRhtK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBxwmB%2Fbtrx9A2G74l%2FiRfpBmRTaOhqYUvJMRhtK1%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;924&quot; height=&quot;580&quot; data-origin-width=&quot;924&quot; data-origin-height=&quot;580&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;h3 data-ke-size=&quot;size23&quot;&gt;1. 새로운 네임스페이스 생성 (이름: red)&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ sudo ip netns add red
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. veth pair 생성&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ sudo ip link add veth1-r type veth peer veth2-r
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. veth2-r 을 red 네임스페이스로 이동&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ sudo ip link set veth2-r netns red
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. red 네임스페이스에 존재하는 veth2-r 인터페이스에 ip 주소를 세팅&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ sudo ip netns exec red ip address add 192.168.0.1 dev veth2-r
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. red 네임스페이스에 존재하는 veth2-r 인터페이스 up&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ sudo ip netns exec red ip link set dev veth2-r up
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6. 노드에 존재하는 veth1-r 인터페이스 up&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ sudo ip link set dev veth1-r up
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7. red 네임스페이스에 존재하는 loopback 인터페이스 up&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ sudo ip netns exec red ip link set lo up
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8. 노드의 라우팅 테이블 세팅&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;subnet mask 가 32 이므로 바로 해당 ip 에 대해서만 veth1-r 로 향하도록 라우팅을 세팅했다. veth1-r 은 veth2-r 과 링크가 연결되어 있으므로 192.168.0.1 을 목적지로 하는 네트워크 패킷들은 red 네임스페이스 안에 존재하는 veth2-r 인터페이스로 향하게 된다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ sudo ip route add 192.168.0.1/32 dev veth1-r
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;9. red 네임스페이스의 디폴트 라우팅을 세팅&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;red 네임스페이스 안에서 디폴트 게이트웨이를 veth2-r 인터페이스의 ip address 로 세팅&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ sudo ip netns exec red ip route add default via 192.168.0.1 dev veth2-r
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;10. 네트워크 통신 확인&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ ip netns
red (id: 0)

$ sudo ip netns exec red ip address
1: lo: &amp;lt;LOOPBACK,UP,LOWER_UP&amp;gt; mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
74: veth2-r@if75: &amp;lt;BROADCAST,MULTICAST,UP,LOWER_UP&amp;gt; mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 52:42:40:a9:86:8b brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 192.168.0.1/32 scope global veth2-r
       valid_lft forever preferred_lft forever
    inet6 fe80::5042:40ff:fea9:868b/64 scope link
       valid_lft forever preferred_lft forever

$ ping 192.168.0.1
PING 192.168.0.1 (192.168.0.1) 56(84) bytes of data.
64 bytes from 192.168.0.1: icmp_seq=1 ttl=64 time=0.057 ms
64 bytes from 192.168.0.1: icmp_seq=2 ttl=64 time=0.046 ms
64 bytes from 192.168.0.1: icmp_seq=3 ttl=64 time=0.043 ms
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;Single Network, 2 Namespaces&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 하나의 노드에 2개의 네임스페이스가 있는 경우를 살펴보자. 보통 컨테이너는 하나의 노드에 2개 이상 멀티로 띄는 경우가 많기 때문에 이 번 케이스가 대부분의 컨테이너 네트워크에 맞다고 보면 된다.&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;1197&quot; data-origin-height=&quot;609&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cys67R/btryaGuAXpx/W5GxgBKCuOZcmgL99CCipK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cys67R/btryaGuAXpx/W5GxgBKCuOZcmgL99CCipK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cys67R/btryaGuAXpx/W5GxgBKCuOZcmgL99CCipK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcys67R%2FbtryaGuAXpx%2FW5GxgBKCuOZcmgL99CCipK%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;1197&quot; height=&quot;609&quot; data-origin-width=&quot;1197&quot; data-origin-height=&quot;609&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개의 네임스페이스와 다른 점은 ip 대역을 지정하고 (일반적으로 subnet mask 24 혹은 25) 리눅스 브릿지로 이를 연결하는 것이다. 그리고 브릿지에 ip 주소를 할당한 후 네임스페이스의 네트워크에서 사용할 디폴트 게이트웨이로 지정하여, 네임스페이스 내에서는 외부로 나가는 패킷을 리죽스 브릿지로 통하게 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 네임스페이스 생성&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ sudo ip netns add red
$ sudo ip netns add blue
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. veth pair 생성&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ sudo ip link add veth1-r type veth peer name veth2-r
$ sudo ip link add veth1-b type veth peer name veth2-b
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. veth pair 를 네임스페이스로 이동&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ sudo ip link set veth2-r netns red
$ sudo ip link set veth2-b netns blue
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 네트워크 네임스페이스 내에 있는 인터페이스에 ip 주소 세팅&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ sudo ip netns exec red ip address add 192.168.0.2/24 dev veth2-r
$ sudo ip netns exec blue ip address add 192.168.0.3/24 dev veth2-b
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. 네트워크 네임스페이스 내에 있는 인터페이스를 up&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ sudo ip netns exec red ip link set dev veth2-r up
$ sudo ip netns exec blue ip link set dev veth2-b up
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6. 리눅스 브릿지 생성&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt; $ sudo ip link add name br0 type bridge
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7. 네트워크 네임스페이스 인터페이스를 브릿지에 연결&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ sudo ip link set dev veth1-r master br0
$ sudo ip link set dev veth1-b master br0
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8. 네트워크 네임스페이스 인터페이스를 up&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ sudo ip link set dev veth1-r up
$ sudo ip link set dev veth1-b up
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;9. 브릿지에 ip 주소 할당&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ sudo ip address add 192.168.0.1/24 dev br0
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;10. 브릿지 up&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ sudo ip link set dev br0 up
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;red 네임스페이스에서 blue 네임스페이스로 ping 테스트&lt;/h2&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ sudo ip netns exec red ping 192.168.0.3
PING 192.168.0.3 (192.168.0.3) 56(84) bytes of data.
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ping 은 통신이 안되고 있다. 원인이 무엇일까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 통신은 아래의 경로를 지난다.&lt;/p&gt;
&lt;pre class=&quot;xl&quot;&gt;&lt;code&gt;red 네임스페이스 -&amp;gt; root 1번 프로세스의 노드 네임스페이스 -&amp;gt; blue 네임스페이스
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, red 네임스페이스의 iptables, 노드 네임스페이스의 iptables, blue 네임스페이스의 iptables 를 모두 지난다. 그러므로 각 iptables 의 filter 체인을 모두 확인해야 한다.&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;783&quot; data-origin-height=&quot;491&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TjzzM/btrx8b98KDQ/XZq5mOp0HIQgZzWFqZTEVK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TjzzM/btrx8b98KDQ/XZq5mOp0HIQgZzWFqZTEVK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TjzzM/btrx8b98KDQ/XZq5mOp0HIQgZzWFqZTEVK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTjzzM%2Fbtrx8b98KDQ%2FXZq5mOp0HIQgZzWFqZTEVK%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;783&quot; height=&quot;491&quot; data-origin-width=&quot;783&quot; data-origin-height=&quot;491&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;red 네임스페이스의 iptables 은 밖으로 나가는 출발점 이고, 응답을 받아야 하므로 OUTPUT filter 체인과 INPUT 체인이 열려 있는지를 확인한다.&lt;/li&gt;
&lt;li&gt;노드 네임스페이스의 iptables 는 네트워크를 경유하는 곳이므로 FORWARD filter 체인이 열려있는지 확인한다. (지금의 경우에만 그렇고 서버에 접속하고 여러 작업을 하므로 INPUT, OUTPUT 이 모두 열려 있어야 한다.)&lt;/li&gt;
&lt;li&gt;blue 네임스페이스는 iptables 는 패킷을 받고 응답을 줘야 하므로 INPUT filter 체인과 OUTPUT 체인이 열려있는지 확인한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;## red 네임스페이스
$ sudo ip netns exec red iptables -S
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT

## 노드 네임스페이스
$ sudo iptables -S
-P INPUT ACCEPT
-P FORWARD DROP
-P OUTPUT ACCEPT
...

## blue 네임스페이스
$ sudo ip netns exec blue iptables -S
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;노드 네임스페스의 FOWARD filter 가 DROP 으로 되어 있다. 이를 ACCEPT 로 변경해 준다.&lt;/p&gt;
&lt;pre class=&quot;tp&quot;&gt;&lt;code&gt;$ sudo iptables -P FORWARD ACCEPT
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한가지가 더 있다. 다음과 같이 sysctl 로 forward 를 열어줘야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래의 값이 0 일 경우 이를 1로 변경해 준다.&lt;/p&gt;
&lt;pre class=&quot;stata&quot;&gt;&lt;code&gt;$ sudo sysctl -a | grep -i net.ipv4.ip_forward
net.ipv4.ip_forward = 0

$ sudo vi /etc/sysctl.d/99-sysctl.conf
net.ipv4.ip_forward=1

$ sudo sysctl -p
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 red 네임스페이스에서 blue 네임스페이스로 ping 테스트를 다시 하면 성공함을 알 수 있다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ sudo ip netns exec red ping 192.168.0.3
PING 192.168.0.3 (192.168.0.3) 56(84) bytes of data.
64 bytes from 192.168.0.3: icmp_seq=1 ttl=64 time=0.077 ms
64 bytes from 192.168.0.3: icmp_seq=2 ttl=64 time=0.063 ms
64 bytes from 192.168.0.3: icmp_seq=3 ttl=64 time=0.062 ms
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;red, blue 네임스페이스에서 외부로의 ping 테스트&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;노드 내부 간의 ping 테스트는 성공했으나 외부 통신은 여전히 실패한다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ sudo ip netns exec red ping 8.8.8.8
ping: connect: Network is unreachable
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이유는 간단하다. red 네임스페이스에서 밖으로 나가는 route 경로를 지정하지 않았기 때문이다. 디폴트 게이트웨이를 아래와 같이 각각 추가해 준다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ sudo ip netns exec red ip route add default via 192.168.0.1 dev veth2-r
$ sudo ip netns exec blue ip route add default via 192.168.0.1 dev veth2-b
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 중요한 내용 하나가 더 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;외부에서는 node 까지는 알 수 있지만 실제로 내부의 red 네임스페이스에 대해서는 알지 못한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기 때문에 네임스페이스 안에서 노드 밖으로 패킷이 나갈 때는 source address 를 node 의 address 로 변경해줘야 한다. 이를 masquerade 라고 하며 아래와 같이 노드에서 iptables 의 nat 테이블에 등록하면 된다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ sudo iptables -t nat -A POSTROUTING -s 192.168.0.0/24 ! -o br0 -j MASQUERADE
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 다시 외부 통신을 테스트 해보면 성공함을 알 수 있다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ sudo ip netns exec red ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=103 time=32.6 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=103 time=32.6 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=103 time=32.6 ms

$ sudo ip netns exec blue ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=103 time=32.5 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=103 time=32.6 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=103 time=32.5 ms
&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;참고: &lt;a href=&quot;https://www.youtube.com/watch?v=6v_BDHIgOY8&amp;amp;t=1561s&quot;&gt;https://www.youtube.com/watch?v=6v_BDHIgOY8&amp;amp;t=1561s&lt;/a&gt; (Container Networking From Scratch - Kristen Jacobs)&lt;/p&gt;</description>
      <category>Container</category>
      <category>container network</category>
      <category>docker</category>
      <category>docker network</category>
      <category>Linux Network Namespace</category>
      <category>리눅스 네트워크</category>
      <category>리눅스 네트워크 네임스페이스</category>
      <category>컨테이너 네트워크</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/293</guid>
      <comments>https://ahnseungkyu.com/293#entry293comment</comments>
      <pubDate>Fri, 1 Apr 2022 14:06:51 +0900</pubDate>
    </item>
    <item>
      <title>Python 개발 환경 구성하기</title>
      <link>https://ahnseungkyu.com/292</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Python 은 다양한 버전의 패키지 라이브러를 사용하여 개발한다. 그렇기 때문에 똑같은 패키지라도 서로 다른 버전을 사용한 프로그램이 있을 수 있어 버전 충돌이 일어날 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 각 프로그램마다 고유한 개발 환경이 필요한데 그것이 바로 Virtual Envrionment 이다. 여기서는 Mac 에 python 가상 환경을 구축하는 방법을 설명한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;1. Python 설치&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;mac 에서는 brew 로 프로그램 관리를 쉽게 할 수 있는데 brew 로 설치한 python 은 향후 다른 프로그램과 연계할 때 문제가 발생할 수 있어 수동으로 설치하기 위해 이전 brew 설치한 python 은 삭제한 후 아래와 같이 수동으로 다운 받아 설치한다.&lt;/p&gt;
&lt;pre class=&quot;python&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;(다운로드 후 설치) https://www.python.org/ftp/python/3.9.7/python-3.9.7-macos11.pkg&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;설치한 python 경로에 path 를 확인하고 없으면 추가해 준다. zsh 외에 bash shell 을 사용하면 ~/.bash_profile 을 확인하면 된다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ vi ~/.zshrc
export PATH=&quot;/Library/Frameworks/Python.framework/Versions/3.9/bin:${PATH}&quot;

$ 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;python 설치가 완료되면 아래와 같이 pip 을 설치한다.&lt;/p&gt;
&lt;pre class=&quot;dsconfig&quot;&gt;&lt;code&gt;$ wget https://bootstrap.pypa.io/get-pip.py
$ python3 get-pip.py&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;h1&gt;2. Python 가상 환경 프로그램 설치&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;python 가상 환경은 virtualenv 와 virtualenvwrapper 프로그램을 설치해서 만들 수 있다. 아래와 같이 2개의 툴을 설치한다.&lt;/p&gt;
&lt;pre class=&quot;cmake&quot;&gt;&lt;code&gt;$ sudo pip install virtualenv virtualenvwrapper&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;설치가 완료되면 ~/.zshrc 혹은 ~/.bash_profile 파일에 경로를 추가한다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ vi ~/.zshrc

alias python=&quot;/usr/local/bin/python3&quot;

export VIRTUALENVWRAPPER_PYTHON=/usr/local/bin/python3
export VIRTUALENVWRAPPER_VIRTUALENV=/Library/Frameworks/Python.framework/Versions/3.9/bin/virtualenv
export WORKON_HOME=~/.virtualenvs
. /Library/Frameworks/Python.framework/Versions/3.9/bin/virtualenvwrapper.sh
export PATH=&quot;/Library/Frameworks/Python.framework/Versions/3.9/bin:${PATH}&quot;

$ source ~/.zshrc&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;3. 가상 환경 활용&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가상 환경은 아래 명령어로 생성할 수 있다. 마지막 python 옵션은 생략 가능하며 pandas-py3.6 이라는 이름으로 생성하였다.&lt;/p&gt;
&lt;pre class=&quot;vim&quot;&gt;&lt;code&gt;$ mkvirtualenv pandas-py3.6 --python=python3

venv:(pandas-py3.6) $&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;prompt 가 &amp;ldquo;venv:...&amp;rdquo; 로 변경되어 가상환경에 들어와 있음을 알 수 있다.&lt;br /&gt;생성한 가상 환경은 아래 디렉토리에 생성되고 앞으로 pip 으로 생성한 python 패키지 파일들은 ~/.virtualenvs/pandas-py3.6 아래에 설치된다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;venv:(pandas-py3.6) $ ls -al ~/.virtualenvs

drwxr-xr-x  21 ahnsk  staff   672  1 27 10:01 .
drwxr-xr-x+ 96 ahnsk  staff  3072  2 10 13:13 ..
-rwxr-xr-x   1 ahnsk  staff   135 11 13  2017 get_env_details
-rw-r--r--   1 ahnsk  staff    96 11 13  2017 initialize
drwxr-xr-x   8 ahnsk  staff   256  1 27 10:08 pandas-py3.6
-rw-r--r--   1 ahnsk  staff    73 11 13  2017 postactivate
-rw-r--r--   1 ahnsk  staff    75 11 13  2017 postdeactivate
-rwxr-xr-x   1 ahnsk  staff    66 11 13  2017 postmkproject
-rw-r--r--   1 ahnsk  staff    73 11 13  2017 postmkvirtualenv
-rwxr-xr-x   1 ahnsk  staff   110 11 13  2017 postrmvirtualenv
-rwxr-xr-x   1 ahnsk  staff    99 11 13  2017 preactivate
-rw-r--r--   1 ahnsk  staff    76 11 13  2017 predeactivate
-rwxr-xr-x   1 ahnsk  staff    91 11 13  2017 premkproject
-rwxr-xr-x   1 ahnsk  staff   130 11 13  2017 premkvirtualenv
-rwxr-xr-x   1 ahnsk  staff   111 11 13  2017 prermvirtualenv&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;가상 환경을 벗어나려면 deactivate 명령어로 빠져 나오면 된다.&lt;/p&gt;
&lt;pre class=&quot;elixir&quot;&gt;&lt;code&gt;venv:(pandas-py3.6) $ deactivate
$ &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;가상 환경 목록을 확인하려면 lsvirtualenv 명령어로 할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;$ lsvirtualenv

pandas-py3.6
============&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;해당 가상 환경으로 들어가려면 workon 명령어로 할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;$ workon pandas-py3.6

venv:(pandas-py3.6) $  python
Python 3.9.7 (v3.9.7:1016ef3790, Aug 30 2021, 16:25:35)
[Clang 12.0.5 (clang-1205.0.22.11)] on darwin
Type &quot;help&quot;, &quot;copyright&quot;, &quot;credits&quot; or &quot;license&quot; for more information.
&amp;gt;&amp;gt;&amp;gt; &lt;/code&gt;&lt;/pre&gt;</description>
      <category>프로그래밍/Python</category>
      <category>Python</category>
      <category>virtaulenv</category>
      <category>virtaulwrapper</category>
      <category>workon</category>
      <category>가상환경</category>
      <category>파이썬</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/292</guid>
      <comments>https://ahnseungkyu.com/292#entry292comment</comments>
      <pubDate>Fri, 11 Feb 2022 08:56:56 +0900</pubDate>
    </item>
    <item>
      <title>AWS 에서 Kubernetes  Volume 때문에 Pod 가  Rescheduling 안되는 문제 해결</title>
      <link>https://ahnseungkyu.com/291</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;EKS 서비스를 이용하기 보다는 Kubernetes 를 AWS 에 직접 설치하여 활용하는 경우가 종종 있는데, 이 경우에는 세부적인 세팅들을 해줘야 할 때가 있다. 그 중에 대표적인 추가 모듈이 Pod 에서 EBS Volume 을 연결하여 사용할 수 있는 StorageClass 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;잘못된 Storage Class 를&amp;nbsp;사용하는 경우&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Storage class 의 Provisioner 를&amp;nbsp;kubernetes.io/aws-ebs 로 사용하는 경우가 있는데, 이는 처음에는 문제가 없으나 Pod eviction (pod 가 다른 노드로 옮겨지는 경우) 에서는 문제가 발생한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같은 storage class 를 적용한다.&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot; data-cke-widget-wrapper=&quot;1&quot; data-cke-filter=&quot;off&quot; data-cke-display-name=&quot;코드 스니펫&quot; data-cke-widget-id=&quot;5&quot;&gt;
&lt;pre class=&quot;yaml&quot; data-cke-widget-data=&quot;%7B%22lang%22%3A%22bash%22%2C%22code%22%3A%22---%5CnapiVersion%3A%20storage.k8s.io%2Fv1%5Cnkind%3A%20StorageClass%5Cnmetadata%3A%5Cn%20%20name%3A%20bad-storage%5Cnprovisioner%3A%20kubernetes.io%2Faws-ebs%5Cnparameters%3A%5Cn%20%20type%3A%20gp2%5Cn%20%20fsType%3A%20ext4%22%2C%22classes%22%3Anull%7D&quot; data-cke-widget-upcasted=&quot;1&quot; data-cke-widget-keep-attr=&quot;0&quot; data-widget=&quot;codeSnippet&quot;&gt;&lt;code&gt;---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: bad-storage
provisioner: kubernetes.io/aws-ebs
parameters:
  type: gp2
  fsType: ext4&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1&quot; data-origin-height=&quot;1&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkHHQd/btrsScy7Mh9/OBmW4hLNV7AMKHpChOtpqk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkHHQd/btrsScy7Mh9/OBmW4hLNV7AMKHpChOtpqk/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkHHQd/btrsScy7Mh9/OBmW4hLNV7AMKHpChOtpqk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bkHHQd/btrsScy7Mh9/OBmW4hLNV7AMKHpChOtpqk/img.gif&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;1&quot; height=&quot;1&quot; data-origin-width=&quot;1&quot; data-origin-height=&quot;1&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;1&quot; data-origin-height=&quot;1&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dxKZV8/btrsRYN5o32/xLEcFzionkdr3yeQWWUkK1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dxKZV8/btrsRYN5o32/xLEcFzionkdr3yeQWWUkK1/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dxKZV8/btrsRYN5o32/xLEcFzionkdr3yeQWWUkK1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/dxKZV8/btrsRYN5o32/xLEcFzionkdr3yeQWWUkK1/img.gif&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;15&quot; height=&quot;15&quot; data-origin-width=&quot;1&quot; data-origin-height=&quot;1&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&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 에서 위의 StorageClass 를 사용하여 volume 을 ReadWriteOnce 로 attach 한 경우에는 문제없이 정상 작동한다. 하지만 pod 가 rescheduling 되면 새로 옮겨가는 노드에서 pod 는 생성되지 않는다. 이유는 volume 이 이전 노드의 Pod에 이미 사용되고 있다는 정보 때문에 새로운 노드의 Pod 에서 volume attach 가 안되기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 해당 문제를 해결하기 위해서는 이전의 attach 정보를 삭제해 줘야 하는데 위의 storage class 로는 이를 해결할 수 없다. 그래서 다음과 같은 StroageClass 를 사용해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;올바른 Storage Class 사용하기&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. CSI Provisioner 설치&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS EBS 를 위한 CSI Driver 는 다음과 같이 설치해야 한다.&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot; data-cke-widget-wrapper=&quot;1&quot; data-cke-filter=&quot;off&quot; data-cke-display-name=&quot;코드 스니펫&quot; data-cke-widget-id=&quot;4&quot;&gt;
&lt;pre class=&quot;lsl&quot; data-cke-widget-data=&quot;%7B%22lang%22%3A%22bash%22%2C%22code%22%3A%22%24%20kubectl%20apply%20-k%20%5C%22github.com%2Fkubernetes-sigs%2Faws-ebs-csi-driver%2Fdeploy%2Fkubernetes%2Foverlays%2Fstable%2F%3Fref%3Drelease-1.5%5C%22%5Cn%5Cn%5Cn%24%20kubectl%20get%20pods%20-n%20kube-system%5Cn...%5Cnebs-csi-controller-6fd55f99c8-9j2hr%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%206%2F6%20%20%20%20%20Running%20%20%200%20%20%20%20%20%20%20%20%20%20%20%20%2013d%5Cnebs-csi-controller-6fd55f99c8-x5dkt%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%206%2F6%20%20%20%20%20Running%20%20%200%20%20%20%20%20%20%20%20%20%20%20%20%2013d%5Cnebs-csi-node-bw6jb%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%203%2F3%20%20%20%20%20Running%20%20%200%20%20%20%20%20%20%20%20%20%20%20%20%2013d%5Cnebs-csi-node-nx7gl%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%203%2F3%20%20%20%20%20Running%20%20%200%20%20%20%20%20%20%20%20%20%20%20%20%2013d%5Cnebs-csi-node-zh242%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%203%2F3%20%20%20%20%20Running%20%20%200%20%20%20%20%20%20%20%20%20%20%20%20%2013d%5Cn...%22%2C%22classes%22%3Anull%7D&quot; data-cke-widget-upcasted=&quot;1&quot; data-cke-widget-keep-attr=&quot;0&quot; data-widget=&quot;codeSnippet&quot;&gt;&lt;code&gt;$ kubectl apply -k &quot;github.com/kubernetes-sigs/aws-ebs-csi-driver/deploy/kubernetes/overlays/stable/?ref=release-1.5&quot;


$ kubectl get pods -n kube-system
...
ebs-csi-controller-6fd55f99c8-9j2hr                                       6/6     Running   0             13d
ebs-csi-controller-6fd55f99c8-x5dkt                                       6/6     Running   0             13d
ebs-csi-node-bw6jb                                                        3/3     Running   0             13d
ebs-csi-node-nx7gl                                                        3/3     Running   0             13d
ebs-csi-node-zh242                                                        3/3     Running   0             13d
...&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1&quot; data-origin-height=&quot;1&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dhutfq/btrsVKn1ctK/mgZMl17VouOICtHG5Wg090/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dhutfq/btrsVKn1ctK/mgZMl17VouOICtHG5Wg090/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dhutfq/btrsVKn1ctK/mgZMl17VouOICtHG5Wg090/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/dhutfq/btrsVKn1ctK/mgZMl17VouOICtHG5Wg090/img.gif&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;1&quot; height=&quot;1&quot; data-origin-width=&quot;1&quot; data-origin-height=&quot;1&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;1&quot; data-origin-height=&quot;1&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/P7tnU/btrsOhUXUQH/Xl4GXQtEtJyjlQX6sMgnwK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/P7tnU/btrsOhUXUQH/Xl4GXQtEtJyjlQX6sMgnwK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/P7tnU/btrsOhUXUQH/Xl4GXQtEtJyjlQX6sMgnwK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/P7tnU/btrsOhUXUQH/Xl4GXQtEtJyjlQX6sMgnwK/img.gif&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;15&quot; height=&quot;15&quot; data-origin-width=&quot;1&quot; data-origin-height=&quot;1&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kustomize 로 설치하면&amp;nbsp;ebs-csi-controller 가 HA 로 설치되고, 각 노드 마다 ebs-csi-node 가 설치된다. 이는 ceph 스토리지 용도의 CSI Driver 와도 비슷한데 volume 을 사용할 Pod 가 실행될 VM 노드에 EBS 링크를 연결하고 이를 Pod 에서 사용하기 때문에 각 노드마다 ebs-csi-node 가 설치되는 이유이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. Storage class 생성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;driver 를 설치했으면 이제 스토리지 클래스를 생성할 차례이다. 아래와 같이 생성한다.&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot; data-cke-widget-wrapper=&quot;1&quot; data-cke-filter=&quot;off&quot; data-cke-display-name=&quot;코드 스니펫&quot; data-cke-widget-id=&quot;3&quot;&gt;
&lt;pre class=&quot;yaml&quot; data-cke-widget-data=&quot;%7B%22lang%22%3A%22bash%22%2C%22code%22%3A%22%24%20vi%20standard-ebs-sc.yaml%5Cn---%5CnapiVersion%3A%20storage.k8s.io%2Fv1%5Cnkind%3A%20StorageClass%5Cnmetadata%3A%5Cn%20%20annotations%3A%20%5Cn%20%20%20%20storageclass.kubernetes.io%2Fis-default-class%3A%20%5C%22true%5C%22%5Cn%20%20name%3A%20standard%5Cnprovisioner%3A%20ebs.csi.aws.com%5CnvolumeBindingMode%3A%20WaitForFirstConsumer%5Cnparameters%3A%5Cn%20%20csi.storage.k8s.io%2Ffstype%3A%20xfs%5Cn%20%20type%3A%20io1%5Cn%20%20iopsPerGB%3A%20%5C%2250%5C%22%5Cn%20%20encrypted%3A%20%5C%22false%5C%22%5CnreclaimPolicy%3A%20Delete%5CnallowVolumeExpansion%3A%20true%5CnallowedTopologies%3A%5Cn-%20matchLabelExpressions%3A%5Cn%20%20-%20key%3A%20topology.ebs.csi.aws.com%2Fzone%5Cn%20%20%20%20values%3A%5Cn%20%20%20%20-%20ap-northeast-2a%5Cn%20%20%20%20-%20ap-northeast-2b%5Cn%20%20%20%20-%20ap-northeast-2c%5Cn%5Cn%5Cn%5Cn%24%20kubectl%20apply%20-f%20standard-ebs-sc.yaml%22%2C%22classes%22%3Anull%7D&quot; data-cke-widget-upcasted=&quot;1&quot; data-cke-widget-keep-attr=&quot;0&quot; data-widget=&quot;codeSnippet&quot;&gt;&lt;code&gt;$ vi standard-ebs-sc.yaml
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  annotations: 
    storageclass.kubernetes.io/is-default-class: &quot;true&quot;
  name: standard
provisioner: ebs.csi.aws.com
volumeBindingMode: WaitForFirstConsumer
parameters:
  csi.storage.k8s.io/fstype: xfs
  type: io1
  iopsPerGB: &quot;50&quot;
  encrypted: &quot;false&quot;
reclaimPolicy: Delete
allowVolumeExpansion: true
allowedTopologies:
- matchLabelExpressions:
  - key: topology.ebs.csi.aws.com/zone
    values:
    - ap-northeast-2a
    - ap-northeast-2b
    - ap-northeast-2c



$ kubectl apply -f standard-ebs-sc.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1&quot; data-origin-height=&quot;1&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cSdEjA/btrsUDCr9I2/hsX8iZ6Jk01Zz5aoo5CGfK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cSdEjA/btrsUDCr9I2/hsX8iZ6Jk01Zz5aoo5CGfK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cSdEjA/btrsUDCr9I2/hsX8iZ6Jk01Zz5aoo5CGfK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/cSdEjA/btrsUDCr9I2/hsX8iZ6Jk01Zz5aoo5CGfK/img.gif&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;1&quot; height=&quot;1&quot; data-origin-width=&quot;1&quot; data-origin-height=&quot;1&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;1&quot; data-origin-height=&quot;1&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zlAbg/btrsUcLSm9q/6DIIafHnYePqdkMJBYIBVk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zlAbg/btrsUcLSm9q/6DIIafHnYePqdkMJBYIBVk/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zlAbg/btrsUcLSm9q/6DIIafHnYePqdkMJBYIBVk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/zlAbg/btrsUcLSm9q/6DIIafHnYePqdkMJBYIBVk/img.gif&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;15&quot; height=&quot;15&quot; data-origin-width=&quot;1&quot; data-origin-height=&quot;1&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;annotations 의&amp;nbsp;storageclass.kubernetes.io/is-default-class&quot;:&quot;true&quot; 값은 스토리지 클래스를 디폴트로 지정하는 값이다. 스토리지 클래스는 여러가지를 사용할 수 있기 때문에 기본을 지정해 주는 것이고, 또한&amp;nbsp;ebs 가 생성될 AZ 리스트를 넣어줘야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. IAM 설정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞에서 VM 에 ebs 링크를 걸어준다고 했는데 그렇기 때문에 IAM 설정을 해야 한다. 아래와 같이 Policy 를 만들고 해당 Policy 를&amp;nbsp;&amp;nbsp;control-plane.cluster-api-provider-aws.sigs.k8s.io 과&amp;nbsp;nodes.cluster-api-provider-aws.sigs.k8s.io 에 attach 해야 한다.&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot; data-cke-widget-wrapper=&quot;1&quot; data-cke-filter=&quot;off&quot; data-cke-display-name=&quot;코드 스니펫&quot; data-cke-widget-id=&quot;2&quot;&gt;
&lt;pre class=&quot;json&quot; data-cke-widget-data=&quot;%7B%22lang%22%3A%22bash%22%2C%22code%22%3A%22%7B%5Cn%20%20%20%20%5C%22Version%5C%22%3A%20%5C%222012-10-17%5C%22%2C%5Cn%20%20%20%20%5C%22Statement%5C%22%3A%20%5B%5Cn%20%20%20%20%20%20%20%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5C%22Effect%5C%22%3A%20%5C%22Allow%5C%22%2C%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5C%22Action%5C%22%3A%20%5B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5C%22ec2%3ACreateSnapshot%5C%22%2C%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5C%22ec2%3AAttachVolume%5C%22%2C%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5C%22ec2%3ADetachVolume%5C%22%2C%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5C%22ec2%3AModifyVolume%5C%22%2C%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5C%22ec2%3ADescribeAvailabilityZones%5C%22%2C%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5C%22ec2%3ADescribeInstances%5C%22%2C%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5C%22ec2%3ADescribeSnapshots%5C%22%2C%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5C%22ec2%3ADescribeTags%5C%22%2C%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5C%22ec2%3ADescribeVolumes%5C%22%2C%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5C%22ec2%3ADescribeVolumesModifications%5C%22%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5D%2C%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5C%22Resource%5C%22%3A%20%5C%22*%5C%22%5Cn%20%20%20%20%20%20%20%20%7D%2C%5Cn%20%20%20%20%20%20%20%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5C%22Effect%5C%22%3A%20%5C%22Allow%5C%22%2C%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5C%22Action%5C%22%3A%20%5B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5C%22ec2%3ACreateTags%5C%22%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5D%2C%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5C%22Resource%5C%22%3A%20%5B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5C%22arn%3Aaws%3Aec2%3A*%3A*%3Avolume%2F*%5C%22%2C%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5C%22arn%3Aaws%3Aec2%3A*%3A*%3Asnapshot%2F*%5C%22%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5D%2C%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5C%22Condition%5C%22%3A%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5C%22StringEquals%5C%22%3A%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5C%22ec2%3ACreateAction%5C%22%3A%20%5B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5C%22CreateVolume%5C%22%2C%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5C%22CreateSnapshot%5C%22%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%7D%2C%5Cn%20%20%20%20%20%20%20%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5C%22Effect%5C%22%3A%20%5C%22Allow%5C%22%2C%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5C%22Action%5C%22%3A%20%5B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5C%22ec2%3ADeleteTags%5C%22%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5D%2C%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5C%22Resource%5C%22%3A%20%5B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5C%22arn%3Aaws%3Aec2%3A*%3A*%3Avolume%2F*%5C%22%2C%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5C%22arn%3Aaws%3Aec2%3A*%3A*%3Asnapshot%2F*%5C%22%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5D%5Cn%20%20%20%20%20%20%20%20%7D%2C%5Cn%20%20%20%20%20%20%20%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5C%22Effect%5C%22%3A%20%5C%22Allow%5C%22%2C%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5C%22Action%5C%22%3A%20%5B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5C%22ec2%3ACreateVolume%5C%22%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5D%2C%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5C%22Resource%5C%22%3A%20%5C%22*%5C%22%5Cn%20%20%20%20%20%20%20%20%7D%2C%5Cn%20%20%20%20%20%20%20%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5C%22Effect%5C%22%3A%20%5C%22Allow%5C%22%2C%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5C%22Action%5C%22%3A%20%5B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5C%22ec2%3ACreateVolume%5C%22%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5D%2C%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5C%22Resource%5C%22%3A%20%5C%22*%5C%22%5Cn%20%20%20%20%20%20%20%20%7D%2C%5Cn%20%20%20%20%20%20%20%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5C%22Effect%5C%22%3A%20%5C%22Allow%5C%22%2C%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5C%22Action%5C%22%3A%20%5B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5C%22ec2%3ACreateVolume%5C%22%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5D%2C%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5C%22Resource%5C%22%3A%20%5C%22*%5C%22%5Cn%20%20%20%20%20%20%20%20%7D%2C%5Cn%20%20%20%20%20%20%20%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5C%22Effect%5C%22%3A%20%5C%22Allow%5C%22%2C%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5C%22Action%5C%22%3A%20%5B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5C%22ec2%3ADeleteVolume%5C%22%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5D%2C%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5C%22Resource%5C%22%3A%20%5C%22*%5C%22%5Cn%20%20%20%20%20%20%20%20%7D%2C%5Cn%20%20%20%20%20%20%20%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5C%22Effect%5C%22%3A%20%5C%22Allow%5C%22%2C%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5C%22Action%5C%22%3A%20%5B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5C%22ec2%3ADeleteVolume%5C%22%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5D%2C%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5C%22Resource%5C%22%3A%20%5C%22*%5C%22%5Cn%20%20%20%20%20%20%20%20%7D%2C%5Cn%20%20%20%20%20%20%20%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5C%22Effect%5C%22%3A%20%5C%22Allow%5C%22%2C%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5C%22Action%5C%22%3A%20%5B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5C%22ec2%3ADeleteVolume%5C%22%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5D%2C%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5C%22Resource%5C%22%3A%20%5C%22*%5C%22%5Cn%20%20%20%20%20%20%20%20%7D%2C%5Cn%20%20%20%20%20%20%20%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5C%22Effect%5C%22%3A%20%5C%22Allow%5C%22%2C%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5C%22Action%5C%22%3A%20%5B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5C%22ec2%3ADeleteSnapshot%5C%22%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5D%2C%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5C%22Resource%5C%22%3A%20%5C%22*%5C%22%5Cn%20%20%20%20%20%20%20%20%7D%2C%5Cn%20%20%20%20%20%20%20%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5C%22Effect%5C%22%3A%20%5C%22Allow%5C%22%2C%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5C%22Action%5C%22%3A%20%5B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5C%22ec2%3ADeleteSnapshot%5C%22%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5D%2C%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5C%22Resource%5C%22%3A%20%5C%22*%5C%22%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%5D%5Cn%7D%22%2C%22classes%22%3Anull%7D&quot; data-cke-widget-upcasted=&quot;1&quot; data-cke-widget-keep-attr=&quot;0&quot; data-widget=&quot;codeSnippet&quot;&gt;&lt;code&gt;{
    &quot;Version&quot;: &quot;2012-10-17&quot;,
    &quot;Statement&quot;: [
        {
            &quot;Effect&quot;: &quot;Allow&quot;,
            &quot;Action&quot;: [
                &quot;ec2:CreateSnapshot&quot;,
                &quot;ec2:AttachVolume&quot;,
                &quot;ec2:DetachVolume&quot;,
                &quot;ec2:ModifyVolume&quot;,
                &quot;ec2:DescribeAvailabilityZones&quot;,
                &quot;ec2:DescribeInstances&quot;,
                &quot;ec2:DescribeSnapshots&quot;,
                &quot;ec2:DescribeTags&quot;,
                &quot;ec2:DescribeVolumes&quot;,
                &quot;ec2:DescribeVolumesModifications&quot;
            ],
            &quot;Resource&quot;: &quot;*&quot;
        },
        {
            &quot;Effect&quot;: &quot;Allow&quot;,
            &quot;Action&quot;: [
                &quot;ec2:CreateTags&quot;
            ],
            &quot;Resource&quot;: [
                &quot;arn:aws:ec2:*:*:volume/*&quot;,
                &quot;arn:aws:ec2:*:*:snapshot/*&quot;
            ],
            &quot;Condition&quot;: {
                &quot;StringEquals&quot;: {
                    &quot;ec2:CreateAction&quot;: [
                        &quot;CreateVolume&quot;,
                        &quot;CreateSnapshot&quot;
                    ]
                }
            }
        },
        {
            &quot;Effect&quot;: &quot;Allow&quot;,
            &quot;Action&quot;: [
                &quot;ec2:DeleteTags&quot;
            ],
            &quot;Resource&quot;: [
                &quot;arn:aws:ec2:*:*:volume/*&quot;,
                &quot;arn:aws:ec2:*:*:snapshot/*&quot;
            ]
        },
        {
            &quot;Effect&quot;: &quot;Allow&quot;,
            &quot;Action&quot;: [
                &quot;ec2:CreateVolume&quot;
            ],
            &quot;Resource&quot;: &quot;*&quot;
        },
        {
            &quot;Effect&quot;: &quot;Allow&quot;,
            &quot;Action&quot;: [
                &quot;ec2:CreateVolume&quot;
            ],
            &quot;Resource&quot;: &quot;*&quot;
        },
        {
            &quot;Effect&quot;: &quot;Allow&quot;,
            &quot;Action&quot;: [
                &quot;ec2:CreateVolume&quot;
            ],
            &quot;Resource&quot;: &quot;*&quot;
        },
        {
            &quot;Effect&quot;: &quot;Allow&quot;,
            &quot;Action&quot;: [
                &quot;ec2:DeleteVolume&quot;
            ],
            &quot;Resource&quot;: &quot;*&quot;
        },
        {
            &quot;Effect&quot;: &quot;Allow&quot;,
            &quot;Action&quot;: [
                &quot;ec2:DeleteVolume&quot;
            ],
            &quot;Resource&quot;: &quot;*&quot;
        },
        {
            &quot;Effect&quot;: &quot;Allow&quot;,
            &quot;Action&quot;: [
                &quot;ec2:DeleteVolume&quot;
            ],
            &quot;Resource&quot;: &quot;*&quot;
        },
        {
            &quot;Effect&quot;: &quot;Allow&quot;,
            &quot;Action&quot;: [
                &quot;ec2:DeleteSnapshot&quot;
            ],
            &quot;Resource&quot;: &quot;*&quot;
        },
        {
            &quot;Effect&quot;: &quot;Allow&quot;,
            &quot;Action&quot;: [
                &quot;ec2:DeleteSnapshot&quot;
            ],
            &quot;Resource&quot;: &quot;*&quot;
        }
    ]
}&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1&quot; data-origin-height=&quot;1&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HNRJe/btrsVKatoHS/PSaiOWUXK7Zza45gXeYKL0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HNRJe/btrsVKatoHS/PSaiOWUXK7Zza45gXeYKL0/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HNRJe/btrsVKatoHS/PSaiOWUXK7Zza45gXeYKL0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/HNRJe/btrsVKatoHS/PSaiOWUXK7Zza45gXeYKL0/img.gif&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;1&quot; height=&quot;1&quot; data-origin-width=&quot;1&quot; data-origin-height=&quot;1&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;1&quot; data-origin-height=&quot;1&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lrUTw/btrsMXibZIm/evkf9iZbfEVvrguGr8YFK0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lrUTw/btrsMXibZIm/evkf9iZbfEVvrguGr8YFK0/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lrUTw/btrsMXibZIm/evkf9iZbfEVvrguGr8YFK0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/lrUTw/btrsMXibZIm/evkf9iZbfEVvrguGr8YFK0/img.gif&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;15&quot; height=&quot;15&quot; data-origin-width=&quot;1&quot; data-origin-height=&quot;1&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 테스트&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;샘플 코드를 만들어서 잘 동작하는지 테스트 해 보자.&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot; data-cke-widget-wrapper=&quot;1&quot; data-cke-filter=&quot;off&quot; data-cke-display-name=&quot;코드 스니펫&quot; data-cke-widget-id=&quot;1&quot;&gt;
&lt;pre class=&quot;yaml&quot; data-cke-widget-data=&quot;%7B%22lang%22%3A%22bash%22%2C%22code%22%3A%22%24%20vi%20app-ebs-example.yaml%5Cn---%5CnapiVersion%3A%20v1%5Cnkind%3A%20PersistentVolumeClaim%5Cnmetadata%3A%5Cn%20%20name%3A%20app-ebs-claim%5Cnspec%3A%5Cn%20%20accessModes%3A%5Cn%20%20%20%20-%20ReadWriteOnce%5Cn%20%20storageClassName%3A%20standard%5Cn%20%20resources%3A%5Cn%20%20%20%20requests%3A%5Cn%20%20%20%20%20%20storage%3A%204Gi%5Cn---%5CnapiVersion%3A%20v1%5Cnkind%3A%20Pod%5Cnmetadata%3A%5Cn%20%20name%3A%20app%5Cnspec%3A%5Cn%20%20containers%3A%5Cn%20%20-%20name%3A%20app%5Cn%20%20%20%20image%3A%20centos%5Cn%20%20%20%20command%3A%20%5B%5C%22%2Fbin%2Fsh%5C%22%5D%5Cn%20%20%20%20args%3A%20%5B%5C%22-c%5C%22%2C%20%5C%22while%20true%3B%20do%20echo%20%24(date%20-u)%20%3E%3E%20%2Fdata%2Fout.txt%3B%20sleep%205%3B%20done%5C%22%5D%5Cn%20%20%20%20volumeMounts%3A%5Cn%20%20%20%20-%20name%3A%20persistent-storage%5Cn%20%20%20%20%20%20mountPath%3A%20%2Fdata%5Cn%20%20volumes%3A%5Cn%20%20-%20name%3A%20persistent-storage%5Cn%20%20%20%20persistentVolumeCl%5Cn%20%20%20%20%20%20claimName%3A%20app-ebs-claim%5Cn%5Cn%5Cn%5Cn%24%20kubectl%20apply%20-f%20app-ebs-example.yaml%22%2C%22classes%22%3Anull%7D&quot; data-cke-widget-upcasted=&quot;1&quot; data-cke-widget-keep-attr=&quot;0&quot; data-widget=&quot;codeSnippet&quot;&gt;&lt;code&gt;$ vi app-ebs-example.yaml
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: app-ebs-claim
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: standard
  resources:
    requests:
      storage: 4Gi
---
apiVersion: v1
kind: Pod
metadata:
  name: app
spec:
  containers:
  - name: app
    image: centos
    command: [&quot;/bin/sh&quot;]
    args: [&quot;-c&quot;, &quot;while true; do echo $(date -u) &amp;gt;&amp;gt; /data/out.txt; sleep 5; done&quot;]
    volumeMounts:
    - name: persistent-storage
      mountPath: /data
  volumes:
  - name: persistent-storage
    persistentVolumeCl
      claimName: app-ebs-claim



$ kubectl apply -f app-ebs-example.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1&quot; data-origin-height=&quot;1&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/v1gpr/btrsNxRJD43/Gts7NS9SDMok6NzcF4lhe1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/v1gpr/btrsNxRJD43/Gts7NS9SDMok6NzcF4lhe1/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/v1gpr/btrsNxRJD43/Gts7NS9SDMok6NzcF4lhe1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/v1gpr/btrsNxRJD43/Gts7NS9SDMok6NzcF4lhe1/img.gif&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;1&quot; height=&quot;1&quot; data-origin-width=&quot;1&quot; data-origin-height=&quot;1&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;1&quot; data-origin-height=&quot;1&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VFpEw/btrsTcZDhfe/OAmaOJ3ncPMnnNBWltgzIk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VFpEw/btrsTcZDhfe/OAmaOJ3ncPMnnNBWltgzIk/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VFpEw/btrsTcZDhfe/OAmaOJ3ncPMnnNBWltgzIk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/VFpEw/btrsTcZDhfe/OAmaOJ3ncPMnnNBWltgzIk/img.gif&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;15&quot; height=&quot;15&quot; data-origin-width=&quot;1&quot; data-origin-height=&quot;1&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&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 가 아래와 같이 잘 생성되는 것을 알 수 있다.&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot; data-cke-widget-wrapper=&quot;1&quot; data-cke-filter=&quot;off&quot; data-cke-display-name=&quot;코드 스니펫&quot; data-cke-widget-id=&quot;0&quot;&gt;
&lt;pre class=&quot;angelscript&quot; data-cke-widget-data=&quot;%7B%22lang%22%3A%22bash%22%2C%22code%22%3A%22%24%20kubectl%20get%20pvc%5CnNAME%20%20%20%20%20%20%20%20%20%20%20%20STATUS%20%20%20VOLUME%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20CAPACITY%20%20%20ACCESS%20MODES%20%20%20STORAGECLASS%20%20%20AGE%5Cnapp-ebs-claim%20%20%20Bound%20%20%20%20pvc-4ab38fe9-7e76-4d81-85d3-0db68da9c1e0%20%20%204Gi%20%20%20%20%20%20%20%20RWO%20%20%20%20%20%20%20%20%20%20%20%20standard%20%20%20%20%20%20%206s%5Cn%5Cn%5Cn%24%20kubectl%20get%20volumeattachments%5CnNAME%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ATTACHER%20%20%20%20%20%20%20%20%20%20PV%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20NODE%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ATTACHED%20%20%20AGE%5Cncsi-60f252627e620b1e91d7d32a7d463b406a3850f3a7d7b0c535fe209f699ba3bd%20%20%20ebs.csi.aws.com%20%20%20pvc-4ab38fe9-7e76-4d81-85d3-0db68da9c1e0%20%20%20ip-10-0-214-57.ap-northeast-2.compute.internal%20%20%20true%20%20%20%20%20%20%202m8s%5Cn%22%2C%22classes%22%3Anull%7D&quot; data-cke-widget-upcasted=&quot;1&quot; data-cke-widget-keep-attr=&quot;0&quot; data-widget=&quot;codeSnippet&quot;&gt;&lt;code&gt;$ kubectl get pvc
NAME            STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
app-ebs-claim   Bound    pvc-4ab38fe9-7e76-4d81-85d3-0db68da9c1e0   4Gi        RWO            standard       6s


$ kubectl get volumeattachments
NAME                                                                   ATTACHER          PV                                         NODE                                             ATTACHED   AGE
csi-60f252627e620b1e91d7d32a7d463b406a3850f3a7d7b0c535fe209f699ba3bd   ebs.csi.aws.com   pvc-4ab38fe9-7e76-4d81-85d3-0db68da9c1e0   ip-10-0-214-57.ap-northeast-2.compute.internal   true       2m8s
&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1&quot; data-origin-height=&quot;1&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cVvp0f/btrsMV5EWJR/WFq7O6LksCs92e9dgakO8K/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cVvp0f/btrsMV5EWJR/WFq7O6LksCs92e9dgakO8K/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cVvp0f/btrsMV5EWJR/WFq7O6LksCs92e9dgakO8K/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/cVvp0f/btrsMV5EWJR/WFq7O6LksCs92e9dgakO8K/img.gif&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;1&quot; height=&quot;1&quot; data-origin-width=&quot;1&quot; data-origin-height=&quot;1&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;1&quot; data-origin-height=&quot;1&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLo5H3/btrsRQC0TYd/57jshGiBa1kZySZ1lk340k/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLo5H3/btrsRQC0TYd/57jshGiBa1kZySZ1lk340k/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLo5H3/btrsRQC0TYd/57jshGiBa1kZySZ1lk340k/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bLo5H3/btrsRQC0TYd/57jshGiBa1kZySZ1lk340k/img.gif&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;15&quot; height=&quot;15&quot; data-origin-width=&quot;1&quot; data-origin-height=&quot;1&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 volumeattachments 를 보면 VM 에 해당 volume 이 attach 되어 링크가 걸려 있는 것을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-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>Kubernetes</category>
      <category>AWS</category>
      <category>aws csi driver</category>
      <category>EBS</category>
      <category>kubernetes</category>
      <category>storageclass</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/291</guid>
      <comments>https://ahnseungkyu.com/291#entry291comment</comments>
      <pubDate>Wed, 9 Feb 2022 10:11:40 +0900</pubDate>
    </item>
    <item>
      <title>AWS ELB 와 Ingress Controller on Kubernetes 연동하기 (나름 최선의 방법입니다)</title>
      <link>https://ahnseungkyu.com/290</link>
      <description>&lt;h2 id=&quot;-&quot; data-ke-size=&quot;size26&quot;&gt;배경&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;외부에서 Kubernetes Cluster 위에서 돌아가는 서비스에 접근하기 위해서는 Ingress Controller 를 통해서 가능하다. aws 와 같은 클라우드에서는 ELB -&amp;gt; Ingress Controller -&amp;gt; Workload 경로로 접근가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재&amp;nbsp;사용하고 있는 방법은&amp;nbsp;CrossPlane 으로 AWS ELB (Classic Type) 를 자동으로 생성하여 Ingress Controller 에 연결하고 있다. 그렇기 때문에 Ingress Controller 를 배포할 때 Service Type을 특정 NodePort 를 지정/오픈하여 연결점을 알아야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들면 아래와 같이 value 값을 override 해야 한다.&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot; data-cke-widget-wrapper=&quot;1&quot; data-cke-filter=&quot;off&quot; data-cke-display-name=&quot;코드 스니펫&quot; data-cke-widget-id=&quot;4&quot;&gt;
&lt;pre class=&quot;yaml&quot; data-cke-widget-data=&quot;%7B%22lang%22%3A%22bash%22%2C%22code%22%3A%22controller%3A%5Cn%20%20replicaCount%3A%202%5Cn%20%20service%3A%5Cn%20%20%20%20externalTrafficPolicy%3A%20Local%5Cn%20%20%20%20type%3A%20NodePort%5Cn%20%20%20%20nodePorts%3A%5Cn%20%20%20%20%20%20http%3A%2032080%5Cn%20%20%20%20%20%20https%3A%2032443%5Cn%20%20%20%20%20%20tcp%3A%5Cn%20%20%20%20%20%20%20%2010254%3A%2032081%5Cn%20%20hostPort%3A%5Cn%20%20%20%20enabled%3A%20true%5Cntcp%3A%5Cn%20%2010254%3A%20%5C%2210254%3Ahealthz%5C%22%5Cn%22%2C%22classes%22%3Anull%7D&quot; data-cke-widget-upcasted=&quot;1&quot; data-cke-widget-keep-attr=&quot;0&quot; data-widget=&quot;codeSnippet&quot;&gt;&lt;code&gt;controller:
  replicaCount: 2
  service:
    externalTrafficPolicy: Local
    type: NodePort
    nodePorts:
      http: 32080
      https: 32443
      tcp:
        10254: 32081
  hostPort:
    enabled: true
tcp:
  10254: &quot;10254:healthz&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1&quot; data-origin-height=&quot;1&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnEzd2/btrr9zngSk3/A9WSIrUxJkD7Osi4ZoAHrK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnEzd2/btrr9zngSk3/A9WSIrUxJkD7Osi4ZoAHrK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnEzd2/btrr9zngSk3/A9WSIrUxJkD7Osi4ZoAHrK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bnEzd2/btrr9zngSk3/A9WSIrUxJkD7Osi4ZoAHrK/img.gif&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;1&quot; height=&quot;1&quot; data-origin-width=&quot;1&quot; data-origin-height=&quot;1&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;1&quot; data-origin-height=&quot;1&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHZXUZ/btrr11Mptm4/hmrZ2sgYDFA2L853RqQ2j0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHZXUZ/btrr11Mptm4/hmrZ2sgYDFA2L853RqQ2j0/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHZXUZ/btrr11Mptm4/hmrZ2sgYDFA2L853RqQ2j0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bHZXUZ/btrr11Mptm4/hmrZ2sgYDFA2L853RqQ2j0/img.gif&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;15&quot; height=&quot;15&quot; data-origin-width=&quot;1&quot; data-origin-height=&quot;1&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CrossPlane 이 AWS ELB 에 대해서 Classic Type 만 지원하기 때문에 CrossPlane 을 제거하고 Network Type 으로 변경하는 것을 고민하였다. 참고로 현재의 방법은 Ingress Controller 를 실수로 삭제해도 ELB 는 그대로 남겨져 있어야 한다는 전제로 고려한 방법이다. DNS 가 ELB 와 연동되어야 하기 때문에 ELB 의 삭제 후 재생성은 DNS 전파의 시간을 필요로 하기 때문이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 AWS 에서 권장하는 NLB 로 넘어가는 것, NodePort 를 지정하지 않아도 된다는 것,&amp;nbsp;그리고 CrossPlane 으로 ELB를 관리하지 않아도 되기 때문에 운영 측면에서 더 낫다고 판단되어 방법을 찾아보게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;-&quot; data-ke-size=&quot;size26&quot;&gt;해결책&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Kubernetes 프로젝트 아래 Ingress Controller&amp;nbsp;의 annotation 을 사용하면 NLB 를 자동으로 생성할 수 있다.&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot; data-cke-widget-wrapper=&quot;1&quot; data-cke-filter=&quot;off&quot; data-cke-display-name=&quot;코드 스니펫&quot; data-cke-widget-id=&quot;3&quot;&gt;
&lt;pre class=&quot;yaml&quot; data-cke-widget-data=&quot;%7B%22lang%22%3A%22bash%22%2C%22code%22%3A%22%24%20helm%20repo%20add%20ingress-nginx%20https%3A%2F%2Fkubernetes.github.io%2Fingress-nginx%5Cn%24%20helm%20repo%20update%5Cn%5Cn%24%20helm%20search%20repo%20ingress-nginx%2Fingress-nginx%5Cn%5Cn%24%20vi%20ingress-nginx-values.yaml%5Cn---%5Cncontroller%3A%5Cn%20%20replicaCount%3A%202%5Cn%20%20affinity%3A%5Cn%20%20%20%20podAntiAffinity%3A%5Cn%20%20%20%20%20%20preferredDuringSchedulingIgnoredDuringExecution%3A%5Cn%20%20%20%20%20%20-%20weight%3A%20100%5Cn%20%20%20%20%20%20%20%20podAffinityTerm%3A%5Cn%20%20%20%20%20%20%20%20%20%20labelSelector%3A%5Cn%20%20%20%20%20%20%20%20%20%20%20%20matchExpressions%3A%5Cn%20%20%20%20%20%20%20%20%20%20%20%20-%20key%3A%20app.kubernetes.io%2Fname%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20operator%3A%20In%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20values%3A%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20-%20ingress-nginx%5Cn%20%20%20%20%20%20%20%20%20%20topologyKey%3A%20%5C%22kubernetes.io%2Fhostname%5C%22%5Cn%20%20nodeSelector%3A%5Cn%20%20%20%20app.kubernetes.io%2Fname%3A%20ingress-nginx%5Cn%20%20service%3A%5Cn%20%20%20%20annotations%3A%5Cn%23%20%20%20%20%20%20service.beta.kubernetes.io%2Faws-load-balancer-name%3A%20%5C%22ahnsk-ingress%5C%22%5Cn%20%20%20%20%20%20service.beta.kubernetes.io%2Faws-load-balancer-type%3A%20%5C%22nlb%5C%22%5Cn%20%20%20%20%20%20service.beta.kubernetes.io%2Faws-load-balancer-proxy-protocol%3A%20%5C%22*%5C%22%5Cn%23%20%20%20%20%20%20service.beta.kubernetes.io%2Faws-load-balancer-target-group-attributes%3A%20%5C%22proxy_protocol_v2.enabled%3Dtrue%2Cpreserve_client_ip.enabled%3Dtrue%2Cderegistration_delay.timeout_seconds%3D120%2Cderegistration_delay.connection_termination.enabled%3Dtrue%5C%22%5Cn%20%20%20%20externalTrafficPolicy%3A%20Local%5Cn%20%20%20%20type%3A%20LoadBalancer%5Cn%23%20%20%20%20healthCheckNodePort%3A%2032081%5Cn%20%20config%3A%5Cn%20%20%20%20enable-underscores-in-headers%3A%20%5C%22true%5C%22%5Cn%20%20%20%20use-proxy-protocol%3A%20%5C%22true%5C%22%5Cn%20%20%20%20proxy-body-size%3A%20%5C%2210m%5C%22%5Cn%22%2C%22classes%22%3Anull%7D&quot; data-cke-widget-upcasted=&quot;1&quot; data-cke-widget-keep-attr=&quot;0&quot; data-widget=&quot;codeSnippet&quot;&gt;&lt;code&gt;$ helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
$ helm repo update

$ helm search repo ingress-nginx/ingress-nginx

$ vi ingress-nginx-values.yaml
---
controller:
  replicaCount: 2
  affinity:
    podAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchExpressions:
            - key: app.kubernetes.io/name
              operator: In
              values:
              - ingress-nginx
          topologyKey: &quot;kubernetes.io/hostname&quot;
  nodeSelector:
    app.kubernetes.io/name: ingress-nginx
  service:
    annotations:
#      service.beta.kubernetes.io/aws-load-balancer-name: &quot;ahnsk-ingress&quot;
      service.beta.kubernetes.io/aws-load-balancer-type: &quot;nlb&quot;
      service.beta.kubernetes.io/aws-load-balancer-proxy-protocol: &quot;*&quot;
#      service.beta.kubernetes.io/aws-load-balancer-target-group-attributes: &quot;proxy_protocol_v2.enabled=true,preserve_client_ip.enabled=true,deregistration_delay.timeout_seconds=120,deregistration_delay.connection_termination.enabled=true&quot;
    externalTrafficPolicy: Local
    type: LoadBalancer
#    healthCheckNodePort: 32081
  config:
    enable-underscores-in-headers: &quot;true&quot;
    use-proxy-protocol: &quot;true&quot;
    proxy-body-size: &quot;10m&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1&quot; data-origin-height=&quot;1&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DMS1c/btrr3j6AJlQ/dHy5ISkxthdnfnLWzh78DK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DMS1c/btrr3j6AJlQ/dHy5ISkxthdnfnLWzh78DK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DMS1c/btrr3j6AJlQ/dHy5ISkxthdnfnLWzh78DK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/DMS1c/btrr3j6AJlQ/dHy5ISkxthdnfnLWzh78DK/img.gif&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;1&quot; height=&quot;1&quot; data-origin-width=&quot;1&quot; data-origin-height=&quot;1&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;1&quot; data-origin-height=&quot;1&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qiXB6/btrr6y91e2t/CBmkgXuE7WCjd1HMDYY0BK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qiXB6/btrr6y91e2t/CBmkgXuE7WCjd1HMDYY0BK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qiXB6/btrr6y91e2t/CBmkgXuE7WCjd1HMDYY0BK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/qiXB6/btrr6y91e2t/CBmkgXuE7WCjd1HMDYY0BK/img.gif&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;15&quot; height=&quot;15&quot; data-origin-width=&quot;1&quot; data-origin-height=&quot;1&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;nodeSelector 와&amp;nbsp;podAntiAffinity 를 사용하여 가능하면 지정노드에 분포해서 Ingress Controller 를 설치할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Service 의 annotations 을 사용하면 ELB 를 NLB type 으로 생성하여 자동으로 Ingress Controller 에 연결시켜 준다. 한가지 주의할 점은&amp;nbsp;aws-load-balancer-proxy-protocol 을 사용하면&amp;nbsp;aws-load-balancer-target-group-attributes 의&amp;nbsp;proxy_protocol_v2 를 enabled 해야 한다. 그러나 이 annotations 은 동작하지 않는다. 왜냐하면 aws 에서는 Ingress Controller (&lt;a href=&quot;https://github.com/kubernetes-sigs/aws-load-balancer-controller/tree/main/helm/aws-load-balancer-controller&quot;&gt;https://github.com/kubernetes-sigs/aws-load-balancer-controller/tree/main/helm/aws-load-balancer-controller&lt;/a&gt;)를 kubernetes-sigs 아래에 따로 만들어서 관리하기 때문이다. 즉 더 이상의 Nginx Ingress Controller 에 대한 기능 추가가 없다고 공표했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼에도 불구하고&amp;nbsp;Nginx Ingress Controller 를 선호한다. 이유는 Nginx 의 기능, 즉 config 를 원하는 대로 세팅할 수 있기 때문이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;nginx 를 사용할 때 가장 많이 경험하는 에러가 2가지 있다. 하나는 header 에 '_' 값이 포함될 때 에러가 나고 다른 하나는 body-size 로 인한 에러이다. 이 2가지 값은 기본적으로 허용해 주는 것이 좋다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 ELB, Ingress Controller 를 거치면서 real client ip 를 알고 싶어 하는 경우가 많다. nginx 의&amp;nbsp;use-proxy-protocol: &quot;true&quot; 로 client 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;이렇게 세팅한 값으로 Ingress Controller 를 배포한다.&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot; data-cke-widget-wrapper=&quot;1&quot; data-cke-filter=&quot;off&quot; data-cke-display-name=&quot;코드 스니펫&quot; data-cke-widget-id=&quot;2&quot;&gt;
&lt;pre class=&quot;routeros&quot; data-cke-widget-data=&quot;%7B%22lang%22%3A%22bash%22%2C%22code%22%3A%22%24%20kubectl%20label%20node%20ip-10-0-181-43.ap-northeast-2.compute.internal%20app.kubernetes.io%2Fname%3Dingress-nginx%5Cn%24%20kubectl%20label%20node%20ip-10-0-214-57.ap-northeast-2.compute.internal%20app.kubernetes.io%2Fname%3Dingress-nginx%5Cn%5Cn%24%20helm%20upgrade%20-i%20ingress-nginx%20ingress-nginx%2Fingress-nginx%20-n%20ingress-nginx%20--version%204.0.16%20--create-namespace%20-f%20ingress-nginx-values.yaml%5Cn%22%2C%22classes%22%3Anull%7D&quot; data-cke-widget-upcasted=&quot;1&quot; data-cke-widget-keep-attr=&quot;0&quot; data-widget=&quot;codeSnippet&quot;&gt;&lt;code&gt;$ kubectl label node ip-10-0-181-43.ap-northeast-2.compute.internal app.kubernetes.io/name=ingress-nginx
$ kubectl label node ip-10-0-214-57.ap-northeast-2.compute.internal app.kubernetes.io/name=ingress-nginx

$ helm upgrade -i ingress-nginx ingress-nginx/ingress-nginx -n ingress-nginx --version 4.0.16 --create-namespace -f ingress-nginx-values.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1&quot; data-origin-height=&quot;1&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b48H8N/btrr7qjYbTW/hp5E5b2qlFUnir2ZfpKY7K/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b48H8N/btrr7qjYbTW/hp5E5b2qlFUnir2ZfpKY7K/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b48H8N/btrr7qjYbTW/hp5E5b2qlFUnir2ZfpKY7K/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/b48H8N/btrr7qjYbTW/hp5E5b2qlFUnir2ZfpKY7K/img.gif&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;1&quot; height=&quot;1&quot; data-origin-width=&quot;1&quot; data-origin-height=&quot;1&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;1&quot; data-origin-height=&quot;1&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6zn6k/btrr4xYfVzi/q2XIFUhYkX3bG39vLDCOnK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6zn6k/btrr4xYfVzi/q2XIFUhYkX3bG39vLDCOnK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6zn6k/btrr4xYfVzi/q2XIFUhYkX3bG39vLDCOnK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/6zn6k/btrr4xYfVzi/q2XIFUhYkX3bG39vLDCOnK/img.gif&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;15&quot; height=&quot;15&quot; data-origin-width=&quot;1&quot; data-origin-height=&quot;1&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배포가 진행될 때 다음과 같이 NLB 의 Target Group 속성 중에&amp;nbsp;proxy_protocol_v2 값을 활성화 해줘야 한다. aws console 에서도 가능하지만 aws cli 를 통해서도 가능하다.&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot; data-cke-widget-wrapper=&quot;1&quot; data-cke-filter=&quot;off&quot; data-cke-display-name=&quot;코드 스니펫&quot; data-cke-widget-id=&quot;1&quot;&gt;
&lt;pre class=&quot;llvm&quot; data-cke-widget-data=&quot;%7B%22lang%22%3A%22bash%22%2C%22code%22%3A%22%24%20aws%20elbv2%20describe-target-groups%20%7C%20jq%20.'TargetGroups%5B%5D%20%7C%20select(.VpcId%20%3D%3D%20%5C%22vpc%20id%20%EA%B0%92%5C%22)%20%7C%20.TargetGroupArn'%5Cn%5Cn---%20output%20---%5Cn%5C%22arn%3Aaws%3Aelasticloadbalancing%3Aap-northeast-2%3A...%5C%22%5Cn%5C%22arn%3Aaws%3Aelasticloadbalancing%3Aap-northeast-2%3A...%5C%22%5Cn%5Cn%24%20aws%20elbv2%20modify-target-group-attributes%20--target-group-arn%20arn%3Aaws%3Aelasticloadbalancing%3Aap-northeast-2%3A...%20--attributes%20'Key%3Dproxy_protocol_v2.enabled%2CValue%3Dtrue'%5Cn%5Cn%24%20aws%20elbv2%20modify-target-group-attributes%20--target-group-arn%20arn%3Aaws%3Aelasticloadbalancing%3Aap-northeast-2%3A...%20--attributes%20'Key%3Dproxy_protocol_v2.enabled%2CValue%3Dtrue'%5Cn%22%2C%22classes%22%3Anull%7D&quot; data-cke-widget-upcasted=&quot;1&quot; data-cke-widget-keep-attr=&quot;0&quot; data-widget=&quot;codeSnippet&quot;&gt;&lt;code&gt;$ aws elbv2 describe-target-groups | jq .'TargetGroups[] | select(.VpcId == &quot;vpc id 값&quot;) | .TargetGroupArn'

--- output ---
&quot;arn:aws:elasticloadbalancing:ap-northeast-2:...&quot;
&quot;arn:aws:elasticloadbalancing:ap-northeast-2:...&quot;

$ aws elbv2 modify-target-group-attributes --target-group-arn arn:aws:elasticloadbalancing:ap-northeast-2:... --attributes 'Key=proxy_protocol_v2.enabled,Value=true'

$ aws elbv2 modify-target-group-attributes --target-group-arn arn:aws:elasticloadbalancing:ap-northeast-2:... --attributes 'Key=proxy_protocol_v2.enabled,Value=true'
&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1&quot; data-origin-height=&quot;1&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/n5TtV/btrr9galxdY/SBsBcR6EWL6450yIIVENA0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/n5TtV/btrr9galxdY/SBsBcR6EWL6450yIIVENA0/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/n5TtV/btrr9galxdY/SBsBcR6EWL6450yIIVENA0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/n5TtV/btrr9galxdY/SBsBcR6EWL6450yIIVENA0/img.gif&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;1&quot; height=&quot;1&quot; data-origin-width=&quot;1&quot; data-origin-height=&quot;1&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;1&quot; data-origin-height=&quot;1&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b50eLS/btrr3h8Nbak/PkRdknkpA6Scgii41a6zwk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b50eLS/btrr3h8Nbak/PkRdknkpA6Scgii41a6zwk/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b50eLS/btrr3h8Nbak/PkRdknkpA6Scgii41a6zwk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/b50eLS/btrr3h8Nbak/PkRdknkpA6Scgii41a6zwk/img.gif&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;15&quot; height=&quot;15&quot; data-origin-width=&quot;1&quot; data-origin-height=&quot;1&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;-&quot; data-ke-size=&quot;size26&quot;&gt;테스트&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sample application 을 배포하여 실제 호출이 잘 되는지 확인한다. 아래는 배포 후에 http header 를 출력해 본 결과이다.&lt;/p&gt;
&lt;div contenteditable=&quot;false&quot; data-cke-widget-wrapper=&quot;1&quot; data-cke-filter=&quot;off&quot; data-cke-display-name=&quot;코드 스니펫&quot; data-cke-widget-id=&quot;0&quot;&gt;
&lt;pre class=&quot;yaml&quot; data-cke-widget-data=&quot;%7B%22lang%22%3A%22bash%22%2C%22code%22%3A%22%E2%9E%9C%20~%20curl%20-L%20http%3A%2F%2Fnginx-ahnsk.taco-cat.xyz%5CnGET%20%2F%20HTTP%2F1.1%5CnHost%3A%20nginx-ahnsk.taco-cat.xyz%5CnX-Request-ID%3A%201ca37cbd4fe84f1c20e56e7ce014bd4c%5CnX-Real-IP%3A%20218.237.0.56%5CnX-Forwarded-For%3A%20218.237.0.56%5CnX-Forwarded-Host%3A%20nginx-ahnsk.taco-cat.xyz%5CnX-Forwarded-Port%3A%20443%5CnX-Forwarded-Proto%3A%20https%5CnX-Forwarded-Scheme%3A%20https%5CnX-Scheme%3A%20https%5Cnuser-agent%3A%20curl%2F7.64.1%5Cnaccept%3A%20*%2F*%5Cn%22%2C%22classes%22%3Anull%7D&quot; data-cke-widget-upcasted=&quot;1&quot; data-cke-widget-keep-attr=&quot;0&quot; data-widget=&quot;codeSnippet&quot;&gt;&lt;code&gt;➜ ~ curl -L http://nginx-ahnsk.taco-cat.xyz
GET / HTTP/1.1
Host: nginx-ahnsk.taco-cat.xyz
X-Request-ID: 1ca37cbd4fe84f1c20e56e7ce014bd4c
X-Real-IP: 218.237.0.56
X-Forwarded-For: 218.237.0.56
X-Forwarded-Host: nginx-ahnsk.taco-cat.xyz
X-Forwarded-Port: 443
X-Forwarded-Proto: https
X-Forwarded-Scheme: https
X-Scheme: https
user-agent: curl/7.64.1
accept: */*
&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1&quot; data-origin-height=&quot;1&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dBjRWY/btrsaR9d8ol/o9HvjvnaCYS5NfSzNnauOk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dBjRWY/btrsaR9d8ol/o9HvjvnaCYS5NfSzNnauOk/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dBjRWY/btrsaR9d8ol/o9HvjvnaCYS5NfSzNnauOk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/dBjRWY/btrsaR9d8ol/o9HvjvnaCYS5NfSzNnauOk/img.gif&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;1&quot; height=&quot;1&quot; data-origin-width=&quot;1&quot; data-origin-height=&quot;1&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;1&quot; data-origin-height=&quot;1&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cJIwsC/btrr2WEa0ju/VGXcngnk8FYV7dU5fhzKKK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cJIwsC/btrr2WEa0ju/VGXcngnk8FYV7dU5fhzKKK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cJIwsC/btrr2WEa0ju/VGXcngnk8FYV7dU5fhzKKK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/cJIwsC/btrr2WEa0ju/VGXcngnk8FYV7dU5fhzKKK/img.gif&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;15&quot; height=&quot;15&quot; data-origin-width=&quot;1&quot; data-origin-height=&quot;1&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&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-Real-IP 와 X-Forwared-For 에 실제 client ip 값이 출력되는 것을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;-&quot; data-ke-size=&quot;size26&quot;&gt;마치며&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Kubernetes 위에 서비스를 올린 후&amp;nbsp;사용자 접근을 오픈하기 위해서는 LB 와&amp;nbsp;Ingress Controller 를 사용해야 한다. 직접 Kubernetes 를 설치 관리하면서 Nginx 의 기능을 사용하고 싶다면 AWS Load Balancer Controller 보다는 Nginx Ingress Controller 를 활용해야 한다. 물론 IAM Account 연동 등을 위해서 혹은 EKS Cluster 를 사용한다면 AWS Load Balancer Controller 를&amp;nbsp;사용하는 것이 건강에 좋을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>Kubernetes</category>
      <category>AWS</category>
      <category>ELB</category>
      <category>kubernetes</category>
      <category>Nginx Ingress Controller</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/290</guid>
      <comments>https://ahnseungkyu.com/290#entry290comment</comments>
      <pubDate>Sun, 30 Jan 2022 17:27:36 +0900</pubDate>
    </item>
    <item>
      <title>Kubeflow 란 무엇인가? (a.k.a AI Platform)</title>
      <link>https://ahnseungkyu.com/289</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;2018년에 Kubernetes 상에서 돌아가는 ML Platform 인 Kubeflow 를 처음 알게된 후로 관심을 갖고 재미삼아 하다가 2022년에는 업무와 연관되어 일을 해야하기 때문에 중점으로 살펴보고자 한다. (최근에는 ML Platform 보다는 AI Platform 이라고 말하는 사람들이 많은 듯)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span&gt;Kubeflow 를 KubeCon 에서 만나다&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Kubeflow 개발자들을 처음 만난 것은 2019년 KubeCon in Europe (Barcelona) 이다. 초기 Kubeflow 는 Goolge 과 Arrito 가 주축이 되어 개발하고 있었는데 마침 초기 버전이 나오면서 Kubeflow 홍보를 시작하던 때 였었다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;01 KubeCon_low.jpg&quot; data-origin-width=&quot;1398&quot; data-origin-height=&quot;1860&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6KnQw/btrqzSJUMyg/MAHmDRRvO9673cClvf8gP1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6KnQw/btrqzSJUMyg/MAHmDRRvO9673cClvf8gP1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6KnQw/btrqzSJUMyg/MAHmDRRvO9673cClvf8gP1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6KnQw%2FbtrqzSJUMyg%2FMAHmDRRvO9673cClvf8gP1%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;357&quot; height=&quot;475&quot; data-filename=&quot;01 KubeCon_low.jpg&quot; data-origin-width=&quot;1398&quot; data-origin-height=&quot;1860&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Kubeflow 의 주 개발자는 화면에 보이는 구글의 Senior S/W Engineer 인 Jeremy Lewi 다. 당시 저 발표는 간단한 설명후에 데모 형태로 발표가 되었는데 Kubernetes 위에 Kubeflow 를 설치한 상태에서 Jupyter Notebook 을 띄어 Model 을 개발하고, Fairing 으로 Model Training 후 Model Serving 하는 것을 시연으로 보여주었다.&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&gt;영상은 아래를 클릭하면 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=-GYiatVNemY&quot;&gt;https://www.youtube.com/watch?v=-GYiatVNemY&lt;/a&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignLeft&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=-GYiatVNemY&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/03ns8/hyM4z185PK/kGy3pHQ8HBx3KV8IhDrBrk/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/-GYiatVNemY&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;저녁에 Arrito 가 주최하는 Kubeflow 개발자 / 사용자와의 저녁 만남이 있었는데 거기서 Jeremy 와 이야기를 해봤을 때는 전형적인 내성적이고 약간은 고지식한 개발자라는 느낌을 받았던 기억이(물론 이건 주관적인 생각). 시간이 좀 지나니 혼자 따로 앉아 있던데.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span&gt;Kubeflow 를 왜 써야 하나?&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI Platform Developer 라면 아래의 그림은 많이 봐왔을 것이다. 정 가운데에 있는 ML Code 는 데이터 사이언티스트들이 모델을 개발하는 코드인데, 이런 개발을 도와주거나 실제 서비스로 구축하기 위해서는 코드 이외에도 많은 Tool / System 들이 필요하다는 의미를 보여준다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;674&quot; data-origin-height=&quot;227&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GTj2P/btrqysLwpF7/ayjdQK0BVBNiVDd6BiAhkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GTj2P/btrqysLwpF7/ayjdQK0BVBNiVDd6BiAhkk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GTj2P/btrqysLwpF7/ayjdQK0BVBNiVDd6BiAhkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGTj2P%2FbtrqysLwpF7%2FayjdQK0BVBNiVDd6BiAhkk%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;850&quot; height=&quot;286&quot; data-origin-width=&quot;674&quot; data-origin-height=&quot;227&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;a href=&quot;https://papers.nips.cc/paper/5656-hidden-technical-debt-in-machine-learning-systems.pdf&quot;&gt;https://papers.nips.cc/paper/5656-hidden-technical-debt-in-machine-learning-systems.pdf&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 위의 동영상에서도 아래와 같이 설명하고 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;02 ML Projects.png&quot; data-origin-width=&quot;835&quot; data-origin-height=&quot;464&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1EkFJ/btrqCTnoIVv/GjylWlHiEKAWIUYpBqVCJK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1EkFJ/btrqCTnoIVv/GjylWlHiEKAWIUYpBqVCJK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1EkFJ/btrqCTnoIVv/GjylWlHiEKAWIUYpBqVCJK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1EkFJ%2FbtrqCTnoIVv%2FGjylWlHiEKAWIUYpBqVCJK%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;835&quot; height=&quot;464&quot; data-filename=&quot;02 ML Projects.png&quot; data-origin-width=&quot;835&quot; data-origin-height=&quot;464&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span&gt;간단하게 살펴보는 Kubeflow&lt;span&gt; Architecture&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;아키텍처에 대한 설명은 Kubeflow document 사이트를 참고하여 간단히 설명하고자 한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;a href=&quot;https://www.kubeflow.org/docs/started/architecture/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.kubeflow.org/docs/started/architecture/&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;576&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhlQxR/btrqytcE7dR/X8TS1HSnyJiBbzHv7bGXGK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhlQxR/btrqytcE7dR/X8TS1HSnyJiBbzHv7bGXGK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhlQxR/btrqytcE7dR/X8TS1HSnyJiBbzHv7bGXGK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhlQxR%2FbtrqytcE7dR%2FX8TS1HSnyJiBbzHv7bGXGK%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;960&quot; height=&quot;576&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;576&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;ML 개발 프로세스는 Experimental Phase (실험 단계) 와 Production Phase (운영 단계) 로 나눌 수 있으며 전체 워크플로우는 아래와 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;528&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wfzP0/btrqFj0pfNU/N8uV966PnkQQCx9PNEbr60/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wfzP0/btrqFj0pfNU/N8uV966PnkQQCx9PNEbr60/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wfzP0/btrqFj0pfNU/N8uV966PnkQQCx9PNEbr60/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwfzP0%2FbtrqFj0pfNU%2FN8uV966PnkQQCx9PNEbr60%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;960&quot; height=&quot;528&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;528&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;실험 단계&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 문제를 인식하고 데이터를 수집/분석&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. ML 알고리즘을 선택하여 모델을 코딩&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 데이터를 가지고 모델 트레이닝&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 하이퍼 파라미터 튜닝&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;운영 단계&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 데이터 변환&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. 온라인/배치 예측을 위한 모델 서빙&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 모델 성능 측정 (결과를 가지고 다시 트레이닝하거나 튜닝)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;단계에 적용되는 Kubeflow 컴포넌트는 아래와 같다.&amp;nbsp;&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;1152&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DOyzD/btrqwtKKMit/D9VqEygPh4ZqUY8bO1rZT0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DOyzD/btrqwtKKMit/D9VqEygPh4ZqUY8bO1rZT0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DOyzD/btrqwtKKMit/D9VqEygPh4ZqUY8bO1rZT0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDOyzD%2FbtrqwtKKMit%2FD9VqEygPh4ZqUY8bO1rZT0%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;960&quot; height=&quot;1152&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;1152&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Fairing: 위성발사를 생각해보면 로켓 맨 상단에 중요 내용물인 위성을 보호하기 위해서 Fairing 으로 감싸고 있다. 모델을 안전하게 다른 시스템으로 전달하는 기능으로 python library 를 제공한다.&lt;/li&gt;
&lt;li&gt;Pipelines: Argo workflow 기반으로 python library 를 제공하여 pipeline 을 구축할 수 있다. 예를 들면 데이터 전처리 등 반복되는 작업을 자동으로 수행할 수 있다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Katib: 하이퍼 파라미터 튜닝을 자동으로 해주는 기능이다. 아래 그림과 같이 하이퍼 파라미터를 바꾸면서 결과를 그래프와 표로 보여준다.&lt;br /&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BeiJR/btrqCUfwy9t/Sy8gwlkHnGKqi9jkgMy9q1/img.png&quot; width=&quot;555&quot; height=&quot;331&quot; data-image-src=&quot;https://blog.kakaocdn.net/dn/BeiJR/btrqCUfwy9t/Sy8gwlkHnGKqi9jkgMy9q1/img.png&quot; data-origin-width=&quot;567&quot; data-origin-height=&quot;338&quot; data-is-animation=&quot;false&quot; /&gt;&lt;/li&gt;
&lt;li&gt;KFServing:&amp;nbsp; Kubeflow 에서 제공해주는 Model Serving 기능이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;마치며&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 Kubeflow 의 최신 버전은 v1.4 이다. 2019년 Arrito 개발자들과 만나서 논의했을 때 (당시에 v0.3 인걸로 기억한다) v1.0 으로 올리는 것이 의미있냐고 질문을 받은 적이 있다. 고객이 오픈소스의 안정성을 의심하기 때문에 기능이 조금 미흡하더라도 v1.0 으로 올리는 것이 좋겠다는 의견을 준적이 있었는데 어느덧 버전이 v1.4 까지 나왔다.(물론 그 때 이후 한참 지나서야 v1.0 이 나왔지만)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;많은 기업에서 자체 AI Platform 을 만들어서 사용하는 것으로 알고 있는데, 제 개인적인 생각으로는 지금이라도 Kubeflow 로 바꾸는 것이 좋다는 생각이다. 그 이유는 이미 모두 알고 있을 것이다.&lt;/p&gt;</description>
      <category>Kubernetes/Kubeflow</category>
      <category>AI Platform</category>
      <category>Hyper Parameter Tuning</category>
      <category>kubernetes</category>
      <category>Kubflow</category>
      <category>ML Ops</category>
      <category>ML Platform</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/289</guid>
      <comments>https://ahnseungkyu.com/289#entry289comment</comments>
      <pubDate>Thu, 13 Jan 2022 11:17:29 +0900</pubDate>
    </item>
    <item>
      <title>Kustomize plugin을 Docker Image 로 만들기</title>
      <link>https://ahnseungkyu.com/288</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 go 실행 프로그램을 도커 이미지를 만드는 경우는 많은데 plugin 을 이미지로 만드는 경우는 드문 것 같다. 이번에는 kustomize 의 plugin 을 go 로 작성하여 plugin 이미지를 만들어 본다. (kustomize plugin 을 만드는 방법이 아니라 kustomize plugin 을 도커 이미지로 만드는 내용이다.)&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;kustomize plugin 소스 다운로드&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TACO 에서는 Kubernetes Resource yaml 파일을 kustomize 를 사용하여 만든다. 일반 kubernetes resource type (정확히는 HelmRelease type 임)이 아니라서 이를 위한 plugin 을 만들어 제공하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;github 으로 부터 소스를 다운 받는다.&lt;/p&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;$ git clone https://github.com/openinfradev/kustomize-helm-transformer.git&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2 step building Dockerfile 작성&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지 사이즈를 줄이기 위해서 2 step 으로 빌드하는 Dockerfile 을 작성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 Dockerfile2 파일의 첫번째 부분이다.&lt;/p&gt;
&lt;pre class=&quot;dockerfile&quot;&gt;&lt;code&gt;FROM golang:1.14-alpine3.13 AS builder
LABEL AUTHOR Seungkyu Ahn (seungkyua@gmail.com)

RUN apk update &amp;amp;&amp;amp; apk add build-base

ENV HOME /root
ENV GO111MODULE on
ENV GOROOT /usr/local/go
ENV GOPATH $HOME/golang

RUN mkdir -p $HOME/.config/kustomize/plugin/openinfradev.github.com/v1/helmvaluestransformer

WORKDIR $HOME
COPY . $HOME/kustomize-helm-transformer

RUN cat kustomize-helm-transformer/README.md | grep -m 1 &quot;* kustomize&quot; | sed -nre 's/^[^0-9]*(([0-9]+\.)*[0-9]+).*/\1/p' &amp;gt; .kustomize_version
RUN go get sigs.k8s.io/kustomize/kustomize/v3@v$(cat $HOME/.kustomize_version)
RUN mv $GOPATH/bin/kustomize /usr/local/bin/

WORKDIR $HOME/kustomize-helm-transformer/plugin/openinfradev.github.com/v1/helmvaluestransformer/
RUN GOOS=linux GOARCH=amd64 go build -buildmode plugin -o HelmValuesTransformer.so
RUN mv HelmValuesTransformer.so $HOME/&lt;/code&gt;&lt;/pre&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;go build 를 위해서 build-base 를 설치한다.&lt;/li&gt;
&lt;li&gt;kustomize plugin 을 위해서 $HOME/.config/kustomize/plugin 디렉토리 아래 module 명 디렉토리를 만든다.&lt;/li&gt;
&lt;li&gt;kustomize version 을 알아내기 위해서 README.md 파일을 파싱한다.&lt;/li&gt;
&lt;li&gt;go get 으로 해당 버전의 kustomize 를 다운받아 /usr/local/bin 에 설치한다.&lt;/li&gt;
&lt;li&gt;go build -buildmode plugin 으로 파일을 빌드한다. -o 옵션을 사용하면 원하는 파일명으로 만들 수 있다. go build 명령어 외에 go test 를 통해 unit test 를 수행하면서 so 파일을 생성할 수 도 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 Dockerfile2 의 두번째 부분이다.&lt;/p&gt;
&lt;pre class=&quot;dockerfile&quot;&gt;&lt;code&gt;FROM alpine:edge
LABEL AUTHOR Seungkyu Ahn (seungkyua@gmail.com)

RUN mkdir -p $HOME/.config/kustomize/plugin/openinfradev.github.com/v1/helmvaluestransformer
COPY --chown=0:0 --from=builder /root/*.so /root/.config/kustomize/plugin/openinfradev.github.com/v1/helmvaluestransformer/
COPY --chown=0:0 --from=builder /usr/local/bin/kustomize /usr/local/bin/kustomize
WORKDIR /

CMD [&quot;/usr/local/bin/kustomize&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;base 이미지를 scratch 로 할 수 도 있지만 scratch 는 shell 명령을 쓸 수 없기 때문에 alpine 이미지를 사용하였다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;kustomize plugin 을 위해서 $HOME/.config/kustomize/plugin 디렉토리 아래 module 명 디렉토리를 만든다.&lt;/li&gt;
&lt;li&gt;빌드된 kustomize plugin so 파일을 복사한다.&lt;/li&gt;
&lt;li&gt;다운받은 kustomize 파일을 복사한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;추가 확인 사항&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;kustomize 를 go get 으로 다운받으면 잘 동작하나 curl 로 바이너리만 받아서 실행하면 에러가 난다. 실제로 이 둘의 binary 사이즈에도 차이가 있는데 이는 추후 원인을 파악해 봐야 겠다.&lt;/li&gt;
&lt;li&gt;go build 에 앞서 go mod tidy 와 go mod vender 를 수행하면 이미지를 실행할 때 앞의 1번과 같은 에러가 난다. 이 부분도 추후 확인해야 할 사항이다.&lt;/li&gt;
&lt;/ol&gt;</description>
      <category>Container</category>
      <category>Docker image</category>
      <category>Go build</category>
      <category>kustomize</category>
      <category>Plugin</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/288</guid>
      <comments>https://ahnseungkyu.com/288#entry288comment</comments>
      <pubDate>Sun, 31 Oct 2021 16:14:17 +0900</pubDate>
    </item>
    <item>
      <title>Github Action 을 cli 로 manual 하게 호출하기</title>
      <link>https://ahnseungkyu.com/287</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;최근 github action 을 workflow CI/CD 로 활용하는 사례가 점점 늘어나고 있다. 이전 글인 &quot;10분만에 만드는 Docker image 저장 자동화&quot;도 github action 을 활용하여 docker registry 에 컨테이너 이미지를 빌드하고 push 하는 방법을 설명하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 github action 을 client cli 를 활용하여 원하는 시점에 manual 로 호출하는 방법을 알아보자.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 새로운 github repository 만들기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 github repository 를 만들어 clone 한다.&lt;/p&gt;
&lt;pre class=&quot;shell&quot;&gt;&lt;code&gt;$ git clone https://github.com/seungkyua/github-action-sample.git
$ cd github-action-sample&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. workflow action 파일 만들기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;github action 을 위한 .github/workflows 디렉토리를 생성하고 action 파일인 hello.yaml 파일을 만든다. 디렉토리 명이 workflow 가 아닌 workflows 이니 실수하지 않게 조심하자.&lt;/p&gt;
&lt;pre class=&quot;elixir&quot;&gt;&lt;code&gt;$ mkdir -p .github/workflow
$ touch .github/workflows/hello.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;hello.yaml 은 다음과 같다.&lt;/p&gt;
&lt;pre class=&quot;http&quot;&gt;&lt;code&gt;name: Hello

on: 
  workflow_dispatch:
    inputs:
      greeting:
        required: false
        default: 'Hello'
        type: string
      name:
        required: false
        default: 'Seungkyu'
        type: string

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
      - uses: actions/checkout@v2

      - name: Run hello.sh
        run: |
          set -xe
          chmod +x .github/workflows/hello.sh
          .github/workflows/hello.sh ${{ github.event.inputs.greeting }} ${{ github.event.inputs.name }}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;workflow 에서 parameter 를 받기 위해서는 workflow_dispatch: 를 명시적으로 선언하고 parameter 는 inputs 아래에 기술한다. inputs 아래 나오는 이름이 parameter 명이 되며 필수 여부, 기본값, 타입 등을 지정할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서는 'greeting' 과 'name' 이라는 2개의 parameter 를 받는 다고 선언하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 workflow step 인데 첫번째 actions/checkout@v2 는 현재의 github repository 소스를 다운 받는 다는 의미이다. 두번째 name: Run hello.sh 는 run: 으로 shell 을 실행하겠다는 의미이며, 앞 단계에서 소스를 다운받았으니 hello.sh 을 실행할 수 있게 되었으며, 실제로 hello.sh 을 실행하면서 parameter 를 argument 로 호출한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;parameter 는 ${{ github.event.inputs.파라미터명 }} 과 같이 활용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 간단산 hello.sh 쉡스크립트 이다.&lt;/p&gt;
&lt;pre class=&quot;bash&quot;&gt;&lt;code&gt;#!/bin/bash

if [ $# -eq 1 ]; then
  greeting=$1
elif [ $# -eq 2 ]; then
  greeting=$1
  name=$2
fi

echo &quot;[hello.sh] ${greeting} ${name}\n&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 해당 파일들을 github 에 push 한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. workflow 호출하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;github workflow client 를 다운 받는다. mac 에서는 brew 로 간단히 설치할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;mipsasm&quot;&gt;&lt;code&gt;$ brew install gh&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;github-action-sample 소스를 clone 한 디렉토리에서 gh auth login 으로 github 에 로그인 한다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$  gh auth login
? What account do you want to log into?  [Use arrows to move, type to filter]
&amp;gt; GitHub.com
  GitHub Enterprise Server&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GitHub.com 을 선택하고 엔터를 치면 아래의 내용이 나온다.&lt;/p&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;? What account do you want to log into? GitHub.com
? You're already logged into github.com. Do you want to re-authenticate? (y/N) y&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미 로그인을 했기 때문에 다시 로그인 하겠다는 의미이며 처음이면 로그인 하라는 메세지가 나온다. y 로 선택하고 로그인을 하자.&lt;/p&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;? What account do you want to log into? GitHub.com
? You're already logged into github.com. Do you want to re-authenticate? Yes
? What is your preferred protocol for Git operations?  [Use arrows to move, type to filter]
&amp;gt; HTTPS
  SSH&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTPS 를 선택한다.&lt;/p&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;? What account do you want to log into? GitHub.com
? You're already logged into github.com. Do you want to re-authenticate? Yes
? What is your preferred protocol for Git operations? HTTPS
? Authenticate Git with your GitHub credentials? (Y/n) y&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;y 로 Github credentials 로 로그인을 한다.&lt;/p&gt;
&lt;pre class=&quot;vbnet&quot;&gt;&lt;code&gt;? What account do you want to log into? GitHub.com
? You're already logged into github.com. Do you want to re-authenticate? Yes
? What is your preferred protocol for Git operations? HTTPS
? Authenticate Git with your GitHub credentials? Yes
? How would you like to authenticate GitHub CLI?  [Use arrows to move, type to filter]
  Login with a web browser
&amp;gt; Paste an authentication token&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;token 으로 로그인을 한다.&lt;/p&gt;
&lt;pre class=&quot;stata&quot;&gt;&lt;code&gt;? What account do you want to log into? GitHub.com
? You're already logged into github.com. Do you want to re-authenticate? Yes
? What is your preferred protocol for Git operations? HTTPS
? Authenticate Git with your GitHub credentials? Yes
? How would you like to authenticate GitHub CLI? Paste an authentication token
Tip: you can generate a Personal Access Token here https://github.com/settings/tokens
The minimum required scopes are 'repo', 'read:org', 'workflow'.
? Paste your authentication token: ****************************************&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정상적으로 login 이 되면 아래와 같이 표시된다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;- gh config set -h github.com git_protocol https
✓ Configured git protocol
✓ Logged in as seungkyua&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그인 후에 gh workflow list 명령어로 workflow 를 조회하면 아래와 같이 Hello 란 workflow 가 있음을 알 수 있다.&lt;/p&gt;
&lt;pre class=&quot;sqf&quot;&gt;&lt;code&gt;➜ github-action-sample git:(main) gh workflow list
Hello  active  14639329&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 실행해 본다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ gh workflow run hello.yaml -f greeting=Welcome -f name=Seungkyu&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행 중인 workflow 를 조회할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;lsl&quot;&gt;&lt;code&gt;$ gh run list --workflow=hello.yaml
STATUS  NAME            WORKFLOW  BRANCH  EVENT              ID          ELAPSED  AGE
*       Initial commit  Hello     main    workflow_dispatch  1390917347  7s       0m&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;완료된 후의 workflow 를 조회하면 STATUS 가 완료로 체크되어 있다.&lt;/p&gt;
&lt;pre class=&quot;lsl&quot;&gt;&lt;code&gt;$ gh run list --workflow=hello.yaml
STATUS  NAME            WORKFLOW  BRANCH  EVENT              ID          ELAPSED  AGE
✓       Initial commit  Hello     main    workflow_dispatch  1390917347  15s      2m&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 브라우저로 repository &lt;a href=&quot;https://github.com/seungkyua/github-action-sample&quot;&gt;https://github.com/seungkyua/github-action-sample&lt;/a&gt; 에 접속하여 Action 탭의 build 를 클릭해보면 아래의 화면 처럼 '[hello.sh] Welcome Seungkyu\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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1734&quot; data-origin-height=&quot;854&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cBlP7c/btrja9sw7mC/ELVaHxaN3rscFuLMdO4XEK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cBlP7c/btrja9sw7mC/ELVaHxaN3rscFuLMdO4XEK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cBlP7c/btrja9sw7mC/ELVaHxaN3rscFuLMdO4XEK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcBlP7c%2Fbtrja9sw7mC%2FELVaHxaN3rscFuLMdO4XEK%2Fimg.png&quot; data-origin-width=&quot;1734&quot; data-origin-height=&quot;854&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 활용법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;manual 하게 github action 을 호출하는 부분은 다른 workflow tool 과 같이 사용할 때가 많다. 예를 들면 argo workflow 에서 하나의 단계로 github action 을 필요한 시점에 호출하여 결과를 활용하는 등으로 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;github action 은 github 의 리소스를 활용하므로 CI 에서 많은 리소스가 필요할 때는 github action 을 같이 활용하는 것도 좋은 대안이 될 것이다.&lt;/p&gt;</description>
      <category>git &amp;amp; github</category>
      <category>github</category>
      <category>Github Action</category>
      <category>github client call</category>
      <category>github workflow</category>
      <category>workflow parameter</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/287</guid>
      <comments>https://ahnseungkyu.com/287#entry287comment</comments>
      <pubDate>Fri, 29 Oct 2021 10:15:23 +0900</pubDate>
    </item>
    <item>
      <title>10분만에 만드는 Docker image 저장 자동화 (feat Github Action)</title>
      <link>https://ahnseungkyu.com/286</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;애플리케이션을 개발하면서 원하는 시점에 자동으로 Docker image 를 build 하고 이를 docker hub 저장소에 push 할 수 있는 방법을 소개한다. 보통은 이를 CI 로 구축하는데 CI 시스템을 따로 구축하기에는 시간과 비용이 들고 이를 유지보수 하기에도 귀찮은 면이 있다. 만약 Github 을 사용하고 있다면 10분 만에 Github Action 으로 이를 쉽게 구현할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. Dockerfile 만들기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 먼저 해야할 일은 도커 이미지 빌드를 위한 Dockerfile 을 만드는 것이다. golang 으로 개발하고 있다면 아래와 같이 만들 수 있을 것이다. 어느 정도 최적화를 고려했지만 완전히 최적화한 부분은 아니니 자신의 환경에 맞게 변경해야 한다. Dockerfile 의 위치는 $PROJECT_HOME 디렉토리 바로 아래이다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;FROM golang:1.16.3-stretch AS builder
LABEL AUTHOR Seungkyu Ahn (seungkyua@gmail.com)

RUN mkdir -p /build
WORKDIR /build

COPY . .
RUN go mod tidy &amp;amp;&amp;amp; go mod vendor
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o bin/server ./cmd/server

RUN mkdir -p /dist
WORKDIR /dist
RUN cp /build/bin/server ./server


FROM golang:alpine3.13

RUN mkdir -p /app
WORKDIR /app

COPY --chown=0:0 --from=builder /dist /app/
EXPOSE 9111

ENTRYPOINT [&quot;/app/server&quot;]
CMD [&quot;-port&quot;, &quot;9110&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. Github Action 파일 만들기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Github Action 은 규칙에 맞게 yaml 을 파일은 정해진 위치에 넣으면 Github 에서 알아서 실행시켜 준다. Action 을 실행시키는 시점은 소스가 github 에 push 되는 순간이며, 어느 branch 에 push 되었는지, Pull Request 를 했을 때 등의 실행 조건을 정의 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$PROJECT_HOME 디렉토리에서 다음과 같이 디렉토리를 만든다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;$ mkdir -p .github/workflows&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;github action yaml 은 아래와 같다.&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;$ vi .github/workflows/deploy-image.yml

name: Build and Push Docker Image
on:
  push:
    branches:
      - main
jobs:
  build-and-push-image:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout
      uses: actions/checkout@v2

    - name: Set up Docker Buildx
      uses: docker/setup-buildx-action@v1

    - name: Login to DockerHub
      uses: docker/login-action@v1
      with:
        username: ${{ secrets.DOCKERHUB_USERNAME }}
        password: ${{ secrets.DOCKERHUB_TOKEN }}

    - name: Build and push
      id: docker_build
      uses: docker/build-push-action@v2
      with:
        push: true
        tags: seungkyua/tks-contract:latest&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음의 on 은 해당 action 이 수행될 조건을 의미한다. push - branches - main 은 main branch 에 push 가 일어나면 수행된다는 의미이다. 그렇기 때문에 요청된 PR 을 merge 하거나 main branch 에 직접 push 하면 해당 action 이 trigger 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 branch 의 push 에 대해서 동작하게 하려면 '*' 로 하면 된다.&lt;/p&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 은 pipeline 을 구성하는 부분이다. steps 처음을 보면 &quot;name: Checkout&quot; 부분에 uses: actions/checkout@v2 로 되어 있는데 이는 github action 으로 정의된 모듈이다. 실체 소스는 &lt;a href=&quot;https://github.com/actions/checkout&quot;&gt;https://github.com/actions/checkout&lt;/a&gt; 으로 접속하면 볼 수 있으며 해당 기능은 디폴트로 action 이 수행되는 github repository 의 소스 (현재 project 의 소스)를 내려받는 기능이다. 내려 받을 repository 를 바꿀려면 변경 가능하다. (action/checkout 에 접속하여 사용법을 확인하자)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;name: Set up Docker Buildx&quot; 부분은 builder driver 나 platform 등을 세팅하는 부분이다. 역시 자세한 부분은 &lt;a href=&quot;https://github.com/docker/setup-buildx-action&quot;&gt;https://github.com/docker/setup-buildx-action&lt;/a&gt; 를 확인하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;name: Login to DockerHub&quot; 는 docker hub 에 접근하기 위해서 id 와 password 를 지정하는 부분이다. 이를 위해서는 github repository 의 settings 로 들어가서 좌측 하단의 secrets &amp;gt;&amp;gt; Actions 에서 Action 용 secret 을 만들어야 한다.&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 alignLeft&quot; data-origin-width=&quot;1025&quot; data-origin-height=&quot;750&quot; data-filename=&quot;그림1.png&quot; width=&quot;818&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RfO3y/btrdZVEeb0M/kgGTRn88zxIknSJis8qDIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RfO3y/btrdZVEeb0M/kgGTRn88zxIknSJis8qDIk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RfO3y/btrdZVEeb0M/kgGTRn88zxIknSJis8qDIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRfO3y%2FbtrdZVEeb0M%2FkgGTRn88zxIknSJis8qDIk%2Fimg.png&quot; data-origin-width=&quot;1025&quot; data-origin-height=&quot;750&quot; data-filename=&quot;그림1.png&quot; width=&quot;818&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;989&quot; data-origin-height=&quot;745&quot; data-filename=&quot;그림2.png&quot; width=&quot;833&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3oH0V/btrdZVKZMnn/0K8EpDx3ZjbcAQuPMn9Zw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3oH0V/btrdZVKZMnn/0K8EpDx3ZjbcAQuPMn9Zw0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3oH0V/btrdZVKZMnn/0K8EpDx3ZjbcAQuPMn9Zw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3oH0V%2FbtrdZVKZMnn%2F0K8EpDx3ZjbcAQuPMn9Zw0%2Fimg.png&quot; data-origin-width=&quot;989&quot; data-origin-height=&quot;745&quot; data-filename=&quot;그림2.png&quot; width=&quot;833&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&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 hub 에 접속할 id 와 password 에 대한 secret 을 만들고 이를 github action 에서 ${{ secrets.DOCKERHUB_USERNAME }} 와 같이 변수로 가져다 쓰는 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 &quot;name: Build and push&quot; 부분은 docker image 를 build 하고 push 하는 부분이다. 이미지 name 과 tag 는 tags 로 지정했다. Dockerfile 의 위치 및 파일명은 file 키로 변경할 수 있다. 아무런 지정을 하지 않으면 해당 프로젝트 디렉토리에 있는 Dockerfile 을 찾는다. 자세한 내용은 &lt;a href=&quot;https://github.com/docker/build-push-action&quot;&gt;https://github.com/docker/build-push-action&lt;/a&gt; 를 참조하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최종적으로 파일들은 아래와 같이 존재하게 된다.&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 alignLeft&quot; data-origin-width=&quot;491&quot; data-origin-height=&quot;157&quot; data-filename=&quot;그림3.png&quot; width=&quot;651&quot; height=&quot;208&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qsrho/btrdT8kwhsS/KqfoWjYZTGvKUkkYKT9AB0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qsrho/btrdT8kwhsS/KqfoWjYZTGvKUkkYKT9AB0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qsrho/btrdT8kwhsS/KqfoWjYZTGvKUkkYKT9AB0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fqsrho%2FbtrdT8kwhsS%2FKqfoWjYZTGvKUkkYKT9AB0%2Fimg.png&quot; data-origin-width=&quot;491&quot; data-origin-height=&quot;157&quot; data-filename=&quot;그림3.png&quot; width=&quot;651&quot; height=&quot;208&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보너스로 한가지 더.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;main branch 로 merge 될 때 외에도 PR 을 할 때 docker image 를 build 하고 push 할 수 는 없을까? 이미지의 tag 는 latest 가 아니라 PR 을 요청한 source 의 branch 명으로 만들고 싶을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이럴 때는 새로운 파일을 만들고 github 의 내장 환경 변수를 사용하면 된다. 앞부분의 on 부분과 마지막 Build and push 부분의 tags 를 다음과 같이 수정하면 된다.&lt;/p&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;$ vi .github/workflows/deploy-image-with-branch.yml

name: Create and publish a package
on:
  pull_request:
    branches:
      - main
...
...
  - name: Build and push
      id: docker_build
      uses: docker/build-push-action@v2
      with:
        push: true
        tags: seungkyua/tks-contract:${{ github.head_ref }}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>프로그래밍/Git</category>
      <category>CI</category>
      <category>github</category>
      <category>Github Action</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/286</guid>
      <comments>https://ahnseungkyu.com/286#entry286comment</comments>
      <pubDate>Fri, 3 Sep 2021 12:19:15 +0900</pubDate>
    </item>
    <item>
      <title>Kaggle's 30 Days of ML 동영상</title>
      <link>https://ahnseungkyu.com/285</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Kaggle 을 통해서 Machine Learning 을 배우고 Kaggle Competition 에 참여하는 방법을 알 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/playlist?list=PL98nY_tJQXZnP-k3qCDd1hljVSciDV9_N&quot;&gt;https://www.youtube.com/playlist?list=PL98nY_tJQXZnP-k3qCDd1hljVSciDV9_N&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1629161265950&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Kaggle's 30 Days of ML&quot; data-og-description=&quot; &quot; data-og-host=&quot;www.youtube.com&quot; data-og-source-url=&quot;https://www.youtube.com/playlist?list=PL98nY_tJQXZnP-k3qCDd1hljVSciDV9_N&quot; data-og-url=&quot;http://www.youtube.com/playlist?list=PL98nY_tJQXZnP-k3qCDd1hljVSciDV9_N&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Olmj6/hyLgKXBjpr/BUB8x1XvOPlXlsxQbbQjdK/img.jpg?width=168&amp;amp;height=94&amp;amp;face=0_0_168_94,https://scrap.kakaocdn.net/dn/b5cYGC/hyLgzBNkua/YH7WxratGlmFMAN9QCB30K/img.jpg?width=196&amp;amp;height=110&amp;amp;face=0_0_196_110,https://scrap.kakaocdn.net/dn/bnxt2m/hyLgG1YtWM/bHYS0Ak0K8t9Pj36HMsZuK/img.jpg?width=246&amp;amp;height=138&amp;amp;face=0_0_246_138,https://scrap.kakaocdn.net/dn/BLsmT/hyLgzIxSk3/JaA1Qkbwj6pFcJsGPdwbVk/img.jpg?width=336&amp;amp;height=188&amp;amp;face=0_0_336_188&quot;&gt;&lt;a href=&quot;https://www.youtube.com/playlist?list=PL98nY_tJQXZnP-k3qCDd1hljVSciDV9_N&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.youtube.com/playlist?list=PL98nY_tJQXZnP-k3qCDd1hljVSciDV9_N&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Olmj6/hyLgKXBjpr/BUB8x1XvOPlXlsxQbbQjdK/img.jpg?width=168&amp;amp;height=94&amp;amp;face=0_0_168_94,https://scrap.kakaocdn.net/dn/b5cYGC/hyLgzBNkua/YH7WxratGlmFMAN9QCB30K/img.jpg?width=196&amp;amp;height=110&amp;amp;face=0_0_196_110,https://scrap.kakaocdn.net/dn/bnxt2m/hyLgG1YtWM/bHYS0Ak0K8t9Pj36HMsZuK/img.jpg?width=246&amp;amp;height=138&amp;amp;face=0_0_246_138,https://scrap.kakaocdn.net/dn/BLsmT/hyLgzIxSk3/JaA1Qkbwj6pFcJsGPdwbVk/img.jpg?width=336&amp;amp;height=188&amp;amp;face=0_0_336_188');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Kaggle's 30 Days of ML&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.youtube.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Machine Learning</category>
      <category>30 days</category>
      <category>kaggle</category>
      <category>Machine learning</category>
      <category>ML</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/285</guid>
      <comments>https://ahnseungkyu.com/285#entry285comment</comments>
      <pubDate>Tue, 17 Aug 2021 09:51:43 +0900</pubDate>
    </item>
    <item>
      <title>Advanced Helm chart 만들기 - chart hook편</title>
      <link>https://ahnseungkyu.com/284</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Helm chart 의 Life cycle 을 이해하면 조금 더 고급스러운 chart 를 만들 수 있다. 예를 들면 이전 chart 의 애플리케이션에서 postgresql DB를 사용하기 때문에 사용자, 데이터베이스, 테이블을 생성해야 하는 경우를 생각해 보자. 차트가 배포될 때 애플리케이션이 실행되기 이전에 해당 작업들을 할 수 있다면 chart 배포 한 번으로 모든 배포를 끝낼 수 있으니 멋진 일이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Helm 에서는 chart 가 실행되기 이전에 혹은, 실행된 이후에 작업을 정의할 수 있도록 hook 기능을 제공한다. 이러한 hook 의 종류는 아래와 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;Annotation 값&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;설 명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;pre-install&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Executes after templates are rendered, but before any resources are created in Kubernetes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;post-install&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Executes after all resources are loaded into Kubernetes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;pre-delete&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Executes on a deletion request before any resources are deleted from Kubernetes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;post-delete&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Executes on a deletion request after all of the release's resources have been deleted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;pre-upgrade&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Executes on an upgrade request after templates are rendered, but before any resources are updated&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;post-upgrade&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Executes on an upgrade request after all resources have been upgraded&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;pre-rollback&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Executes on a rollback request after templates are rendered, but before any resources are rolled back&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;post-rollback&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Executes on a rollback request after all resources have been modified&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;test&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Executes when the Helm test subcommand is invoked ( &lt;a href=&quot;https://helm.sh/docs/chart_tests/&quot;&gt;view test docs&lt;/a&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;hook 을 정의하는 것은 Annotation 으로 하며, 앞에서 설명한 시나리오의 경우에는 pre-install hook 을 사용하는 것이 적절하기 때문에 &quot;helm.sh/hook&quot;: pre-install 로 설정한다. 또한 이런 단발성 호출의 경우에는 Job 으로 설정하는 것이 좋다.&lt;/p&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;apiVersion: batch/v1
kind: Job
metadata:
...
  annotations:
    &quot;helm.sh/hook&quot;: pre-install
    &quot;helm.sh/hook-weight&quot;: &quot;1&quot;
    &quot;helm.sh/hook-delete-policy&quot;: before-hook-creation&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;hook-weight 는 낮을 수록 우선순위가 높으며, hook-delete-policy 의 before-hook-creation 은 hook 으로 실행된 리소스를 다음 hook 이 실행될 때 까지 지우지 않고 남겨둔다는 의미이다. policy 는 아래와 같이 3가지가 있다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;Annotation Value&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;before-hook-creation&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Delete the previous resource before a new hook is launched (default)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;hook-succeeded&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Delete the resource after the hook is successfully executed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code&gt;hook-failed&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;Delete the resource if the hook failed during execution&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 postgresql 을 설치하고 사용자, 데이터베이스, 테이블을 생성하는 pre-install hook 을 작성해 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. postgresql 설치&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;bitnami chart repo 에서 postgresql 을 다운받아 설치한다.&lt;/p&gt;
&lt;pre class=&quot;gams&quot;&gt;&lt;code&gt;$ helm repo add bitnami https://charts.bitnami.com/bitnami
$ helm repo update
$ helm upgrade -i postgresql bitnami/postgresql --version 10.8.0 -n decapod-db --create-namespace \
--set postgresqlPassword=password \
--set persistence.enabled=true \
--set persistence.storageClass=rbd \
--set persistence.size=10Gi&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;chart 의 value 값을 필요한 부분만 override 하였다. db user 는 postgres 이며 db password는 password 로 설치했다. 테스트 환경에서는 외부 스토리지를 제공하고 있어 10Gi 로 설정하였다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ kubectl get pods -n decapod-db
NAME                      READY   STATUS    RESTARTS   AGE
postgresql-postgresql-0   1/1     Running   0          35h


$ kubectl get svc -n decapod-db
NAME                  TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
postgresql            ClusterIP   10.233.46.14   &amp;lt;none&amp;gt;        5432/TCP   35h
postgresql-headless   ClusterIP   None           &amp;lt;none&amp;gt;        5432/TCP   35h&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. pre-install hook 만들기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;chart 가 설치될 때 한 번 실행되면 되므로 Job 타입으로 리소스를 작성한다. psql 명령을 사용할 수 있는 컨테이너 이미지를 활용하고 수행할 명령어들은 쉘 스크립트로 작성하였다.&lt;/p&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;{chart_source_home}/templates/pre-install-job.yaml

apiVersion: batch/v1
kind: Job
metadata:
  name: {{ include &quot;tks-contract.fullname&quot; . }}
  namespace: {{ .Values.namespace }}
  labels:
    {{- include &quot;tks-contract.labels&quot; . | nindent 4 }}
  annotations:
    &quot;helm.sh/hook&quot;: pre-install
    &quot;helm.sh/hook-weight&quot;: &quot;-5&quot;
    &quot;helm.sh/hook-delete-policy&quot;: before-hook-creation
spec:
  template:
    metadata:
      name: {{ include &quot;tks-contract.fullname&quot; . }}
    spec:
      restartPolicy: Never
      containers:
      - name: pre-install-job
        image: &quot;bitnami/postgresql:11.12.0-debian-10-r44&quot;
        env:
        - name: DB_ADMIN_USER
          value: {{ .Values.db.adminUser }}
        - name: PGPASSWORD
          value: {{ .Values.db.adminPassword }}
        - name: DB_NAME
          value: {{ .Values.db.dbName }}
        - name: DB_USER
          value: {{ .Values.args.dbUser }}
        - name: DB_PASSWORD
          value: {{ .Values.args.dbPassword }}
        - name: DB_URL
          value: {{ .Values.args.dbUrl }}
        - name: DB_PORT
          value: &quot;{{ .Values.args.dbPort }}&quot;
        command:
        - /bin/bash
        - -c
        - -x
        - |
          # check if ${DB_NAME} database already exists.
          psql -h ${DB_URL} -p ${DB_PORT} -U ${DB_ADMIN_USER} -lqt | cut -d \| -f 1 | grep -qw ${DB_NAME}
          if [[ $? -ne 0 ]]; then
            psql -h ${DB_URL} -p ${DB_PORT} -U ${DB_ADMIN_USER} -c &quot;CREATE DATABASE ${DB_NAME};&quot;
          fi

          # check if ${DB_USER} user already exists.
          psql -h ${DB_URL} -p ${DB_PORT} -U ${DB_ADMIN_USER} -tc '\du' | cut -d \| -f 1 | grep -qw ${DB_USER}
          if [[ $? -ne 0 ]]; then
            psql -h ${DB_URL} -p ${DB_PORT} -U ${DB_ADMIN_USER} -c &quot;create user ${DB_USER} SUPERUSER password '${DB_PASSWORD}';&quot;
          fi

          # check if contracts table in tks database already exists.
          psql -h ${DB_URL} -p ${DB_PORT} -U ${DB_ADMIN_USER} -d ${DB_NAME} -tc '\dt' | cut -d \| -f 2 | grep -qw contracts
          if [[ $? -ne 0 ]]; then
            echo &quot;&quot;&quot;
              \c ${DB_NAME};
              CREATE TABLE contracts
              (
                  contractor_name character varying(50) COLLATE pg_catalog.&quot;default&quot;,
                  id uuid primary key,
                  available_services character varying(50)[] COLLATE pg_catalog.&quot;default&quot;,
                  updated_at timestamp with time zone,
                  created_at timestamp with time zone
              );
              CREATE UNIQUE INDEX idx_contractor_name ON contracts(contractor_name);
              ALTER TABLE contracts CLUSTER ON idx_contractor_name;
              INSERT INTO contracts(
                contractor_name, id, available_services, updated_at, created_at)
                VALUES ('tester', 'edcaa975-dde4-4c4d-94f7-36bc38fe7064', ARRAY['lma'], '2021-05-01'::timestamp, '2021-05-01'::timestamp);

              CREATE TABLE resource_quota
              (
                  id uuid primary key,
                  cpu bigint,
                  memory bigint,
                  block bigint,
                  block_ssd bigint,
                  fs bigint,
                  fs_ssd bigint,
                  contract_id uuid,
                  updated_at timestamp with time zone,
                  created_at timestamp with time zone
              );
            &quot;&quot;&quot; | psql -h ${DB_URL} -p ${DB_PORT} -U ${DB_ADMIN_USER}
          fi
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;{chart_source_home}/values.yaml

args:
  port: 9110
  dbUrl: postgresql.decapod-db.svc
  dbPort: 5432
  dbUser: tksuser
  dbPassword: password

db:
  adminUser: postgres
  adminPassword: password
  dbName: tks&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;컨테이너에서 필요한 값들(db superuser admin 과 password, db url, db port 등)은 env 로 전달한다. 참고로 postgresql 은 psql 로 접속할 때 패스워드를 전달하는 아규먼트가 없다. 대신 환경 변수로 다음과 같이 설정하면 패스워드를 사용하여 접속할 수 있다. ($ export PGPASSWORD=password)&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;먼저 DB 에 해당 database 가 존재하는 조회하고 없으면 database 를 생성한다.&lt;/li&gt;
&lt;li&gt;DB User 가 존재하는지 조회하고 없으면 새로운 DB User 를 생성한다.&lt;/li&gt;
&lt;li&gt;Table 이 존재하는지 조회하고 없으면 Table 을 생성한다. Table 을 생성하기 위해 psql 로 접속 시에 해당 database 에 접속할 수 있지만 (-d database명 옵션 사용), &quot;\c database명&quot; 으로 database 를 선택할 수 있다는 것을 보여주기 위해 이 부분을 추가하였다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;chart 를 배포하면 다음과 같이 job 이 실행됨을 알 수 있다.&lt;/p&gt;
&lt;pre class=&quot;lua&quot;&gt;&lt;code&gt;$ kubectl get pods -n tks
NAME                               READY   STATUS      RESTARTS   AGE
tks-contract-h5468                 0/1     Completed   0          31h


$ kubectl logs tks-contract-h5468 -n tks
+ psql -h postgresql.decapod-db.svc -p 5432 -U postgres -lqt
+ cut -d '|' -f 1
+ grep -qw tks
+ [[ 0 -ne 0 ]]
+ psql -h postgresql.decapod-db.svc -p 5432 -U postgres -tc '\du'
+ cut -d '|' -f 1
+ grep -qw tksuser
+ [[ 0 -ne 0 ]]
+ psql -h postgresql.decapod-db.svc -p 5432 -U postgres -d tks -tc '\dt'
+ cut -d '|' -f 2
+ grep -qw contracts
+ [[ 0 -ne 0 ]]&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Kubernetes</category>
      <category>Helm chart</category>
      <category>helm hook</category>
      <category>job</category>
      <category>kubernetes</category>
      <category>pre-install</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/284</guid>
      <comments>https://ahnseungkyu.com/284#entry284comment</comments>
      <pubDate>Wed, 4 Aug 2021 10:36:04 +0900</pubDate>
    </item>
    <item>
      <title>10분만에 만드는 쿠버네티스 Helm chart</title>
      <link>https://ahnseungkyu.com/283</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;쿠버네티스에 서비스를 배포하기 위해 사용하는 대표적인 방법중에 하나가 바로 Helm chart 이다. 한마디로 말해서 Helm chart 는 쿠버네티스 용도의 패키징된 s/w 라 할 수 있다. Helm chart 문법은 go template 을 활용하였기 때문에 go template 을 안다면 조금 더 쉽게 이해할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 설명하는 내용은 사전에 쿠버네티스 클러스터가 있으며 kubectl 로 api 에 접근할 수 있는 환경이 있다는 것을 가정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 도커 이미지를 가지고 쿠버네티스에 Helm 으로 배포할 수 있는 Helm chart 를 만들어 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 Helm (v3)을 설치한다.&lt;/p&gt;
&lt;pre class=&quot;dsconfig&quot;&gt;&lt;code&gt;$ curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3
$ chmod 700 get_helm.sh
$ ./get_helm.sh

$ helm version
version.BuildInfo{Version:&quot;v3.4.0&quot;, GitCommit:&quot;7090a89efc8a18f3d8178bf47d2462450349a004&quot;, GitTreeState:&quot;clean&quot;, GoVersion:&quot;go1.14.10&quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Helm 버전은 틀릴 수 있는데 v.3.0.0 이상이면 상관없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 기본 코드 생성하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무 디렉토리로 이동해서 아래의 명령어로 기본 코드를 생성한다. (여기서 예제는 gRpc 기반의 tks-contract 이라는 프로그램을 기반으로 했다)&lt;/p&gt;
&lt;pre class=&quot;elixir&quot;&gt;&lt;code&gt;$ helm create tks-contract&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;helm create 명령어는 tks-contract 디렉토리를 만들고 아래와 같은 구조로 디렉토리와 샘플 코드를 자동으로 만들어 준다. 그 구조는 다음과 같다.&lt;/p&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;$ tree tks-contract    
tks-contract
├── Chart.yaml
├── charts
├── templates
│   ├── NOTES.txt
│   ├── _helpers.tpl
│   ├── deployment.yaml
│   ├── hpa.yaml
│   ├── ingress.yaml
│   ├── service.yaml
│   ├── serviceaccount.yaml
│   └── tests
│       └── test-connection.yaml
└── values.yaml

3 directories, 10 files&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Chart.yaml 은 chart 에 대한 기본적인 정보가 있는 파일이다. chart 명, chart 버전, chart 설명 등을 적을 수 있으며, 지금은 별로 바꿀 내용이 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;charts 디렉토리는 의존성을 관리한다. 예를 들면 DB를 이용하는 웹 애플리케이션 chart 를 만들 때 DB 가 설치되어야 한다면 여기에 chart 를 넣거다 chart repo 에 존재하는 chart 의 링크를 기술 할 수 있다. 이 것도 지금은 바꿀 내용이 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;templates 디렉토리는 가장 중요한 디렉토리다. 이 디렉토리 안에는 쿠버네티스 리소스 yaml 파일들이 (예를 들면, Deployment, Service 와 같은 리소스 정의 파일) 위치한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;values.yaml 파일은 한마디로 변수들을 정의한 파일이다. templates 디렉토리 안에 있는 yaml 파일들의 특정 변수 값을 치환하고 싶을 때 값을 선언해 놓는 곳이다. 일반적으로 key: value 형태로 기술한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. Template 작성 방법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 간단한 templates 디렉토리 안의 service.yaml 을 변경해 보자.&lt;/p&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;apiVersion: v1
kind: Service
metadata:
  name: {{ include &quot;tks-contract.fullname&quot; . }}
  namespace: {{ .Values.namespace }}
  labels:
    {{- include &quot;tks-contract.labels&quot; . | nindent 4 }}
spec:
  type: {{ .Values.service.type }}
  ports:
    - port: {{ .Values.service.port }}
      targetPort: {{ .Values.args.port }}
      protocol: TCP
  selector:
    {{- include &quot;tks-contract.selectorLabels&quot; . | nindent 4 }}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;go 템플릿을 사용하기 때문에 {{ }} 기호로 값을 치환한다는 것을 알 수 있다. 일반적으로 values.yaml 파일에 정의된 값을 치환할 수 있게 적혀있다. 가령 {{ .Values.namespace }} 는 values.yaml 파일의 namespace 를 키로 하는 값을 가져와서 치환하라는 의미이다. 실제 values.yaml 에는 아래와 같이 되어 있다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;namespace: tks
service:
  type: LoadBalancer
  port: 9110&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;values.yaml 파일의 service 아래의 type 을 키로 하는 값, 즉 LoadBalancer 라는 값을 가져오기 위해서는 {{ .Values.service.type }} 으로 적어주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막 라인의 {{- include &quot;tks-contract.selectorLabels&quot; . | nindent 4 }} 와 같이 include 는 정의된 템플릿 호출을 의미한다. 즉 tks-contract.selectorLabels 라는 정의된 템플릿을 호출했다고 할 수 있다. 템플릿 정의들은 보통 templates 디렉토리 아래 _helpers.tpl 파일에 정의하며 define 으로 선언되어 있다. _helpers.tpl 파일의 일부를 살펴보자.&lt;/p&gt;
&lt;pre class=&quot;stata&quot;&gt;&lt;code&gt;{{/*
Selector labels
*/}}
{{- define &quot;tks-contract.selectorLabels&quot; -}}
app.kubernetes.io/service: tks
app.kubernetes.io/name: {{ include &quot;tks-contract.name&quot; . }}
{{- end }}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;{{/* */}} 은 주석처리이다. 그 아래에 {{- define &quot;tks-contract.selectorLabels&quot; -}} ... {{- end }} 은 템플릿 정의이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;{{- include &quot;tks-contract.selectorLabels&quot; . | nindent 4 }} 에서 {{- 는 맨앞에 쓰였을 때 {{ }} 코드가 차지하는 영역의 줄바꿈과 공백을 없애라는 뜻이며 . 은 values.yaml 에 있는 모든 변수들을 아규먼트로 넘긴다는 뜻이다. 마지막으로 | 는 shell 에서의 파이프라인과 동일하고 nindent 4 는 결과를 프린트 할 때 공백 4개를 멀티라인으로 계속 들여쓰라는 의미이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정리해 보면 service.yaml 과 _helper.tpl 파일을 이 활용되어 아래와 같이 작동된다는 것을 알 수 있다.&lt;/p&gt;
&lt;pre class=&quot;protobuf&quot;&gt;&lt;code&gt;## service.yaml
  selector:
    {{- include &quot;tks-contract.selectorLabels&quot; . | nindent 4 }}

+

## _helpers.tpl
{{- define &quot;tks-contract.selectorLabels&quot; -}}
app.kubernetes.io/service: tks
app.kubernetes.io/name: {{ include &quot;tks-contract.name&quot; . }}
{{- end }}


================ 결과 ===============
  selector:
    app.kubernetes.io/service: tks
    app.kubernetes.io/name: tks-contract&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;app.kubernetes.io/service: tks 와 app.kubernetes.io/name: tks-contract 가 들여쓰기 4 만큼 프린트 됐다. 물론 _helpers.tpl 내의 템플릿 정의를 찾아보면 {{ include &quot;tks-contract.name&quot; . }} 의 결과 값은 tks-contract 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 NOTES.txt 에 적힌 내용은 chart 가 배포되고 나서 터미널에 프린트된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 전체 소스 작성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 원하는 값으로 수정하고 배포될 때의 최종 yaml 이 어떻게 될지 확인해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 Chart.yaml 이다.&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;$ vi tks-contract/Chart.yaml
apiVersion: v2
name: tks-contract
description: A Helm chart for tks-contract
type: application
version: 0.1.0
appVersion: 0.1.0&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;_helpers.tpl 은 selectorLabels 를 원하는 값을 넣기 위해서 49 라인만 수정하였다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;$ vi tks-contract/_helpers.tpl
...
{{/*
Selector labels
*/}}
{{- define &quot;tks-contract.selectorLabels&quot; -}}
app.kubernetes.io/service: tks
app.kubernetes.io/name: {{ include &quot;tks-contract.name&quot; . }}
{{- end }}
...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;deployment.yaml 은 container 의 args 값을 추가했다.&lt;/p&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;$ vi tks-contract/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include &quot;tks-contract.fullname&quot; . }}
  namespace: {{ .Values.namespace }}
  labels:
    {{- include &quot;tks-contract.labels&quot; . | nindent 4 }}
spec:
  {{- if not .Values.autoscaling.enabled }}
  replicas: {{ .Values.replicaCount }}
  {{- end }}
  selector:
    matchLabels:
      {{- include &quot;tks-contract.selectorLabels&quot; . | nindent 6 }}
  template:
    metadata:
      {{- with .Values.podAnnotations }}
      annotations:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      labels:
        {{- include &quot;tks-contract.selectorLabels&quot; . | nindent 8 }}
    spec:
      {{- with .Values.imagePullSecrets }}
      imagePullSecrets:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      serviceAccountName: {{ include &quot;tks-contract.serviceAccountName&quot; . }}
      securityContext:
        {{- toYaml .Values.podSecurityContext | nindent 8 }}
      containers:
        - name: {{ .Chart.Name }}
          securityContext:
            {{- toYaml .Values.securityContext | nindent 12 }}
          image: &quot;{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}&quot;
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          ports:
            - name: tks-contract
              containerPort: {{ .Values.args.port }}
              protocol: TCP
          command:
            - /app/server
          args: [
            &quot;-port&quot;, &quot;{{ .Values.args.port }}&quot;,
            &quot;-dbhost&quot;, &quot;{{ .Values.args.dbUrl }}&quot;,
            &quot;-dbport&quot;, &quot;{{ .Values.args.dbPort }}&quot;,
            &quot;-dbuser&quot;, &quot;{{ .Values.args.dbUser }}&quot;,
            &quot;-dbpassword&quot;, &quot;{{ .Values.args.dbPassword }}&quot;,
            &quot;-info-address&quot;, &quot;{{ .Values.args.tksInfoAddress }}&quot;,
            &quot;-info-port&quot;, &quot;{{ .Values.args.tksInfoPort }}&quot;
          ]
          resources:
            {{- toYaml .Values.resources | nindent 12 }}
      {{- with .Values.nodeSelector }}
      nodeSelector:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      {{- with .Values.affinity }}
      affinity:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      {{- with .Values.tolerations }}
      tolerations:
        {{- toYaml . | nindent 8 }}
      {{- end }}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조건절은 {{- if }} 혹은 {{- if not }} {{ end }} 로 사용할 수 있고 {{- with 키 }} {{ end }} 는 with 절 안에서는 구조상 해당 키 아래의 값들을 사용하겠다는 의미이다. {{- toYaml 키 }} 는 키의 값을 그대로 Yaml 로 프린트 해 준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;nodeSelector 를 예를 들어 보자.&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;## deployment.yaml
      {{- with .Values.nodeSelector }}
      nodeSelector:
        {{- toYaml . | nindent 8 }}
      {{- end }}

+

## values.yaml
nodeSelector:
  taco-tks: enabled


============ 결과 =================
      nodeSelector:
        taco-tks: enabled&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;values.yaml 에 nodeSelector 키 아래에 taco-tks: enabled 라는 값을 그대로 toYaml 로 프린트 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;service.yaml 전체는 다음과 같다.&lt;/p&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;$ vi tks-contract/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: {{ include &quot;tks-contract.fullname&quot; . }}
  namespace: {{ .Values.namespace }}
  labels:
    {{- include &quot;tks-contract.labels&quot; . | nindent 4 }}
spec:
  type: {{ .Values.service.type }}
  ports:
    - port: {{ .Values.service.port }}
      targetPort: {{ .Values.args.port }}
      protocol: TCP
  selector:
    {{- include &quot;tks-contract.selectorLabels&quot; . | nindent 4 }}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;values.yaml 에 전체 값을 넣는다.&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;$ vi tks-contract/values.yaml

replicaCount: 1

namespace: tks

image:
  repository: docker.io/seungkyu/tks-contract
  pullPolicy: Always
  tag: &quot;latests&quot;

imagePullSecrets: []
nameOverride: &quot;tks-contract&quot;
fullnameOverride: &quot;tks-contract&quot;

serviceAccount:
  create: true
  annotations: {}
  name: &quot;tks-info&quot;

args:
  port: 9110
  dbUrl: postgresql.decapod-db.svc
  dbPort: 5432
  dbUser: tksuser
  dbpassword: tkspassword
  tksInfoAddress: tks-info.tks.svc
  tksInfoPort: 9110

podAnnotations: {}

podSecurityContext: {}
  # fsGroup: 2000

securityContext: {}
  # capabilities:
  #   drop:
  #   - ALL
  # readOnlyRootFilesystem: true
  # runAsNonRoot: true
  # runAsUser: 1000

service:
  type: LoadBalancer
  port: 9110

ingress:
  enabled: false
  annotations: {}
  hosts:
    - host: chart-example.local
      paths: []
  tls: []
  #  - secretName: chart-example-tls
  #    hosts:
  #      - chart-example.local

resources: {}
  # We usually recommend not to specify default resources and to leave this as a conscious
  # choice for the user. This also increases chances charts run on environments with little
  # resources, such as Minikube. If you do want to specify resources, uncomment the following
  # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
  # limits:
  #   cpu: 100m
  #   memory: 128Mi
  # requests:
  #   cpu: 100m
  #   memory: 128Mi

autoscaling:
  enabled: false
  minReplicas: 1
  maxReplicas: 100
  targetCPUUtilizationPercentage: 80
  # targetMemoryUtilizationPercentage: 80

nodeSelector:
  taco-tks: enabled

tolerations: []

affinity: {}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 배포후 프린트될 내용은 NOTES.txt 을 수정한다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;$ vi tks-contract/templates/NOTES.txt
TKS-Contract
{{- if contains &quot;LoadBalancer&quot; .Values.service.type }}
     NOTE: It may take a few minutes for the LoadBalancer IP to be available.
           You can watch the status of by running 'kubectl get --namespace {{ .Values.namespace }} svc -w {{ include &quot;tks-contract.fullname&quot; . }}'
  export SERVICE_IP=$(kubectl get svc --namespace {{ .Values.namespace }} {{ include &quot;tks-contract.fullname&quot; . }} --template &quot;{{&quot;{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}&quot;}}&quot;)
  gRPC Call =&amp;gt; $SERVICE_IP:{{ .Values.service.port }}
{{- end }}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 결과 확인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작성된 chart 는 아래 명령어로 최종 yaml 이 어떻게 변환되어 배포되는지 dry-run 으로 확인할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;$ helm upgrade -i tks-contract ./tks-contract --dry-run --debug

---
# Source: tks-contract/templates/serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: tks-info
  labels:
    helm.sh/chart: tks-contract-0.1.0
    app.kubernetes.io/service: tks
    app.kubernetes.io/name: tks-contract
    app.kubernetes.io/version: &quot;0.1.0&quot;
    app.kubernetes.io/managed-by: Helm
---
# Source: tks-contract/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: tks-contract
  namespace: tks
  labels:
    helm.sh/chart: tks-contract-0.1.0
    app.kubernetes.io/service: tks
    app.kubernetes.io/name: tks-contract
    app.kubernetes.io/version: &quot;0.1.0&quot;
    app.kubernetes.io/managed-by: Helm
spec:
  type: LoadBalancer
  ports:
    - port: 9110
      targetPort: 9110
      protocol: TCP
  selector:
    app.kubernetes.io/service: tks
    app.kubernetes.io/name: tks-contract
---
# Source: tks-contract/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: tks-contract
  namespace: tks
  labels:
    helm.sh/chart: tks-contract-0.1.0
    app.kubernetes.io/service: tks
    app.kubernetes.io/name: tks-contract
    app.kubernetes.io/version: &quot;0.1.0&quot;
    app.kubernetes.io/managed-by: Helm
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/service: tks
      app.kubernetes.io/name: tks-contract
  template:
    metadata:
      labels:
        app.kubernetes.io/service: tks
        app.kubernetes.io/name: tks-contract
    spec:
      serviceAccountName: tks-info
      securityContext:
        {}
      containers:
        - name: tks-contract
          securityContext:
            {}
          image: &quot;docker.io/seungkyu/tks-contract:latests&quot;
          imagePullPolicy: Always
          ports:
            - name: tks-contract
              containerPort: 9110
              protocol: TCP
          command:
            - /app/server
          args: [
            &quot;-port&quot;, &quot;9110&quot;,
            &quot;-dbhost&quot;, &quot;postgresql.decapod-db.svc&quot;,
            &quot;-dbport&quot;, &quot;5432&quot;,
            &quot;-dbuser&quot;, &quot;tksuser&quot;,
            &quot;-dbpassword&quot;, &quot;&quot;,
            &quot;-info-address&quot;, &quot;tks-info.tks.svc&quot;,
            &quot;-info-port&quot;, &quot;9110&quot;
          ]
          resources:
            {}
      nodeSelector:
        taco-tks: enabled

NOTES:
TKS-Contract
     NOTE: It may take a few minutes for the LoadBalancer IP to be available.
           You can watch the status of by running 'kubectl get --namespace tks svc -w tks-contract'
  export SERVICE_IP=$(kubectl get svc --namespace tks tks-contract --template &quot;{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}&quot;)
  gRPC Call =&amp;gt; $SERVICE_IP:9110
&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Kubernetes</category>
      <category>helm</category>
      <category>Helm chart</category>
      <category>kubernetes</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/283</guid>
      <comments>https://ahnseungkyu.com/283#entry283comment</comments>
      <pubDate>Thu, 29 Jul 2021 15:40:04 +0900</pubDate>
    </item>
    <item>
      <title>Cluster API 로 AWS에 Kubernetes 설치하기(2)</title>
      <link>https://ahnseungkyu.com/282</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이전 글은 Cluster API 가 어떤 것이고 어떻게 동작하는지를 알아봤다면 이번에는 AWS 에 Cluster API를 이용하여 Kubernetes 를 쉽게 설치하는 방법을 설명한다. 사실 AWS를 어느 정도 알고있어야 (특히 VPC, Subnet, Route Table, Nat Gateway, Internet Gateway 같은 네트워크) 해당 내용들을 이해하기가 쉽기 때문에 Cluster API 로 구현되는 최종 Kubernetes Cluster 구성에 대해서 먼저 설명하겠다.&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-origin-width=&quot;1141&quot; data-origin-height=&quot;638&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/br61I3/btq9I39f1cT/OoVFqpuaKEjVkEuhZTT6fk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/br61I3/btq9I39f1cT/OoVFqpuaKEjVkEuhZTT6fk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/br61I3/btq9I39f1cT/OoVFqpuaKEjVkEuhZTT6fk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbr61I3%2Fbtq9I39f1cT%2FOoVFqpuaKEjVkEuhZTT6fk%2Fimg.png&quot; data-origin-width=&quot;1141&quot; data-origin-height=&quot;638&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 리전 (여기서는 서울)에 3개의 가용존(AZ1~3)에 Kubernetes Master 와 Node 가 설치되게 된다. 하나의 AZ에는 public subnet 과 private subnet 이 만들어지며 public subnet은 인터넷과 통하는 Internet Gateway 와 연결되어 있다. 네트워크 통신을 위해서는 Route Table 을 통해서 default gateway (0.0.0.0/0)를 설정해야 하는데 public subnet 은 Internet Gateway 를 private subnet 은 EIP 가 할당되어 있는 NAT gateway 를 설정한다.&lt;/p&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 에서는 Internet Gateway 와 연결되어 있는데 subnet 을 public subnet 으로 명명하며 public IP 가 할당되는 자원들은 모두 public subnet 에 생성한다. 그 외의 subnet 은 private subnet 이라 명명하는데, 이 때 외부 outbound 연결을 하기 위해서는 public subnet 에 NAT Gateway 를 만들어 활용한다. 보라색 점선이 Internet Gateway 와 NAT Gateway 로 default gateway 를 설정한 내용을 보여준다.&lt;/p&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 에서의 네트워크는 Subnet, Route table, Gateway (Internet 혹은 NAT) 로 구성된다.&lt;/p&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 (Control plane과 Node) instance는 private subnet에 생성되어 외부에서 직접 VM 으로 접속하는 경로를 차단한다. 필요에 따라 외부의 Inbound 를 트래픽을 가능하게 하려면 Load Balancer 를 통해서 연결한다(물론 Internal LB도 가능하다). Load Balancer 가 private subent 의 VM 에 연결되기 위해서는 public subnet 이 LB에 등록되어야 한다. 다이어그램에서 이를 표현한 것이 초록색 점선이다. LB 와 Control plane 을 연결한 것은 API Server 가 LB 에 등록되어 로드밸랜싱된다는 의미이며, 고객 서비스의 연결은 Node VM 에 연결될 수 있다. 이 때 Service 리소스의 Type 을 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;이 기능들이 가능한 이유는 Kubernetes 에 Cloud provider controller 가 내장되어 있기 때문이다. 하지만 이 기능은 deprecated 될 예정으로 버전 1.23 부터는 소스가 분리될 예정이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 한가지 일반적인 방법으로 설치하면 그림의 내용과 같이 모든 Node VM 이 AZ1 의 private subnet 에 몰려서 생성된다. 이는 가용성에 문제가 될 수 있으며 이를 해결하기 위해서는 아직은 experimental 버전인 MachinePool 기능을 사용해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 본격적으로 Cluster API 로 Kubernetes Cluster 를 설치해 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 글을 보면 Management cluster 에 Cluster API Controller 를 설치한 후 Custom Resource (CR) 를 생성하면 자동으로 Workload cluster 가 생성된다는 것을 설명하였다. 이를 잘 기억해 두고 Management cluster 는 존재한다는 가정하에 시작한다(인터넷에서 조회해보면 Kind 로 쉽게 Management cluster 를 구성하는 방법을 찾을 수 있다).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. clusterctl 설치&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;clusterctl 은 Managed cluster 에 Cluster API controller 를 설치하고 Workload cluster 를 위한 CR 생성을 도와주는 도구이다.&lt;/p&gt;
&lt;pre class=&quot;groovy&quot;&gt;&lt;code&gt;$ curl -L https://github.com/kubernetes-sigs/cluster-api/releases/download/v0.3.20/clusterctl-linux-amd64 -o clusterctl
$ chmod +x ./clusterctl
$ mv ./clusterctl /usr/local/bin/clusterctl
$ clusterctl version
=== output ===
clusterctl version: &amp;amp;version.Info{Major:&quot;0&quot;, Minor:&quot;3&quot;, GitVersion:&quot;v0.3.20&quot;, GitCommit:&quot;ea9dc4bdc2a9938325aab3817ece3e654873aaab&quot;, GitTreeState:&quot;clean&quot;, BuildDate:&quot;2021-06-30T22:10:51Z&quot;, GoVersion:&quot;go1.13.15&quot;, Compiler:&quot;gc&quot;, Platform:&quot;linux/amd64&quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. clusterawsadm 설치&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;clusterawsadm 은 aws 에 필요한 Role 과 Policy 를 자동으로 생성해 주는 도구이다.&lt;/p&gt;
&lt;pre class=&quot;groovy&quot;&gt;&lt;code&gt;$ curl -L https://github.com/kubernetes-sigs/cluster-api-provider-aws/releases/download/v0.6.6/clusterawsadm-linux-amd64 -o clusterawsadm
$ chmod +x clusterawsadm
$ mv ./clusterawsadm /usr/local/bin/clusterawsadm
$ clusterawsadm version
=== output ===
clusterawsadm version: &amp;amp;version.Info{Major:&quot;0&quot;, Minor:&quot;6&quot;, GitVersion:&quot;v0.6.6-4-d4593daa95fb96-dirty&quot;, GitCommit:&quot;d4593daa95fb961be91dc6db869f26ca4359ebc0&quot;, GitTreeState:&quot;dirty&quot;, BuildDate:&quot;2021-06-01T20:05:33Z&quot;, GoVersion:&quot;go1.13.15&quot;, AwsSdkVersion:&quot;v1.36.26&quot;, Compiler:&quot;gc&quot;, Platform:&quot;linux/amd64&quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. awscli 및 jq 설치&lt;/h3&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;$ curl -L https://awscli.amazonaws.com/awscli-exe-linux-x86_64-2.2.13.zip -o awscliv2.zip
$ unzip awscliv2.zip
$ ./aws/install
$ aws --version
=== output ===
aws-cli/2.2.13 Python/3.8.8 Linux/4.4.0-87-generic exe/x86_64.ubuntu.16 prompt/off

$ mkdir -p ~/.aws
$ vi ~/.aws/credentials
[default]
aws_access_key_id=&amp;lt;&amp;lt; access_key_id &amp;gt;&amp;gt;
aws_secret_access_key=&amp;lt;&amp;lt; secret_access_key &amp;gt;&amp;gt;

$ vi ~/.aws/config
[default]
region = ap-northeast-2&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 사전 작업&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;clusterawsadm 을 활용하여 IAM Role 과 Policy 를 생성한다.&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;## 설정이 안되어 있을 때 환경 변수로 설정한다.
$ export AWS_REGION=ap-northeast-2
$ export AWS_ACCESS_KEY_ID=&amp;lt;&amp;lt; access_key_id &amp;gt;&amp;gt;
$ export AWS_SECRET_ACCESS_KEY=&amp;lt;&amp;lt; secret_access_key &amp;gt;&amp;gt;

$ clusterawsadm bootstrap iam create-cloudformation-stack&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Workload cluster VM 에 접속할 key pair 를 Import 한다.&lt;/p&gt;
&lt;pre class=&quot;processing&quot;&gt;&lt;code&gt;$ aws ec2 import-key-pair \
  --key-name capi-seungkyu \
  --public-key-material fileb://~/.ssh/id_rsa.pub&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. Management cluster 생성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;clusterctl 생성에 필요한 환경 변수를 다음과 같이 설정한다.&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;$ clusterawsadm bootstrap credentials encode-as-profile
=== output ===
&amp;lt;&amp;lt; crendentials &amp;gt;&amp;gt;

$ vi env.sh
export AWS_REGION=ap-northeast-2
export AWS_ACCESS_KEY_ID=&amp;lt;&amp;lt; access_key_id &amp;gt;&amp;gt;
export AWS_SECRET_ACCESS_KEY=&amp;lt;&amp;lt; secret_access_key &amp;gt;&amp;gt;
export AWS_B64ENCODED_CREDENTIALS=&amp;lt;&amp;lt; crendentials &amp;gt;&amp;gt;

$ source ./env.sh&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;clusterctl init 명령어를 사용하여 Management cluster 를 생성한다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ clusterctl init --core cluster-api:v0.3.20 --infrastructure aws:v0.6.6 --bootstrap kubeadm:v0.3.20 --control-plane kubeadm:v0.3.20 -v5
=== output ===
...
Fetching providers
Installing cert-manager
Waiting for cert-manager to be available...
...
Installing Provider=&quot;cluster-api&quot; Version=&quot;v0.3.20&quot; TargetNamespace=&quot;capi-system&quot;
...
Installing Provider=&quot;bootstrap-kubeadm&quot; Version=&quot;v0.3.20&quot; TargetNamespace=&quot;capi-kubeadm-bootstrap-system&quot;
...
Installing Provider=&quot;control-plane-kubeadm&quot; Version=&quot;v0.3.20&quot; TargetNamespace=&quot;capi-kubeadm-control-plane-system&quot;
...
Installing Provider=&quot;infrastructure-aws&quot; Version=&quot;v0.6.6&quot; TargetNamespace=&quot;capa-system&quot;

Your management cluster has been initialized successfully!

You can now create your first workload cluster by running the following:

  clusterctl config cluster [name] --kubernetes-version [version] | kubectl apply -f -&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6. Workload cluster 생성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필요한 환경변수를 설정하고 clusterctl config 명령어를 이용하여 CR 파일을 생성한다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ vi env-workload.sh
export AWS_CONTROL_PLANE_MACHINE_TYPE=t3.large
export AWS_NODE_MACHINE_TYPE=t3.large
export AWS_SSH_KEY_NAME=capi-seungkyu

$ source ./env-workload.sh

$ clusterctl config cluster capi-quickstart \
  -n capi-quickstart \
  --kubernetes-version v1.20.5 \
  --control-plane-machine-count=3 \
  --worker-machine-count=3 \
  &amp;gt; capi-quickstart.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;capi-quickstart.yaml 을 확인하면 아래와 같다.&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;$ cat capi-quickstart.yaml
---
apiVersion: cluster.x-k8s.io/v1alpha3
kind: Cluster
metadata:
  name: capi-quickstart
  namespace: capi-quickstart
spec:
  clusterNetwork:
    pods:
      cidrBlocks:
      - 192.168.0.0/16
  controlPlaneRef:
    apiVersion: controlplane.cluster.x-k8s.io/v1alpha3
    kind: KubeadmControlPlane
    name: capi-quickstart-control-plane
  infrastructureRef:
    apiVersion: infrastructure.cluster.x-k8s.io/v1alpha3
    kind: AWSCluster
    name: capi-quickstart
---
apiVersion: infrastructure.cluster.x-k8s.io/v1alpha3
kind: AWSCluster
metadata:
  name: capi-quickstart
  namespace: capi-quickstart
spec:
  region: ap-northeast-2
  sshKeyName: capi-seungkyu
---
apiVersion: controlplane.cluster.x-k8s.io/v1alpha3
kind: KubeadmControlPlane
metadata:
  name: capi-quickstart-control-plane
  namespace: capi-quickstart
spec:
  infrastructureTemplate:
    apiVersion: infrastructure.cluster.x-k8s.io/v1alpha3
    kind: AWSMachineTemplate
    name: capi-quickstart-control-plane
  kubeadmConfigSpec:
    clusterConfiguration:
      apiServer:
        extraArgs:
          cloud-provider: aws
      controllerManager:
        extraArgs:
          cloud-provider: aws
    initConfiguration:
      nodeRegistration:
        kubeletExtraArgs:
          cloud-provider: aws
        name: '{{ ds.meta_data.local_hostname }}'
    joinConfiguration:
      nodeRegistration:
        kubeletExtraArgs:
          cloud-provider: aws
        name: '{{ ds.meta_data.local_hostname }}'
  replicas: 3
  version: v1.20.5
---
apiVersion: infrastructure.cluster.x-k8s.io/v1alpha3
kind: AWSMachineTemplate
metadata:
  name: capi-quickstart-control-plane
  namespace: capi-quickstart
spec:
  template:
    spec:
      iamInstanceProfile: control-plane.cluster-api-provider-aws.sigs.k8s.io
      instanceType: t3.large
      sshKeyName: capi-seungkyu
---
apiVersion: cluster.x-k8s.io/v1alpha3
kind: MachineDeployment
metadata:
  name: capi-quickstart-md-0
  namespace: capi-quickstart
spec:
  clusterName: capi-quickstart
  replicas: 3
  selector:
    matchLabels: null
  template:
    spec:
      bootstrap:
        configRef:
          apiVersion: bootstrap.cluster.x-k8s.io/v1alpha3
          kind: KubeadmConfigTemplate
          name: capi-quickstart-md-0
      clusterName: capi-quickstart
      infrastructureRef:
        apiVersion: infrastructure.cluster.x-k8s.io/v1alpha3
        kind: AWSMachineTemplate
        name: capi-quickstart-md-0
      version: v1.20.5
---
apiVersion: infrastructure.cluster.x-k8s.io/v1alpha3
kind: AWSMachineTemplate
metadata:
  name: capi-quickstart-md-0
  namespace: capi-quickstart
spec:
  template:
    spec:
      iamInstanceProfile: nodes.cluster-api-provider-aws.sigs.k8s.io
      instanceType: t3.large
      sshKeyName: capi-seungkyu
---
apiVersion: bootstrap.cluster.x-k8s.io/v1alpha3
kind: KubeadmConfigTemplate
metadata:
  name: capi-quickstart-md-0
  namespace: capi-quickstart
spec:
  template:
    spec:
      joinConfiguration:
        nodeRegistration:
          kubeletExtraArgs:
            cloud-provider: aws
          name: '{{ ds.meta_data.local_hostname }}'&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;해당 CR 은 아래 다이어그램 구조로 매칭된다.&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-origin-width=&quot;990&quot; data-origin-height=&quot;538&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JeM2Z/btq9OwIIafh/ih9ABlA2jYhGrKhbJLgNUk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JeM2Z/btq9OwIIafh/ih9ABlA2jYhGrKhbJLgNUk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JeM2Z/btq9OwIIafh/ih9ABlA2jYhGrKhbJLgNUk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJeM2Z%2Fbtq9OwIIafh%2Fih9ABlA2jYhGrKhbJLgNUk%2Fimg.png&quot; data-origin-width=&quot;990&quot; data-origin-height=&quot;538&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Cluster API 는 공통이 Abstract Class 와 같이 기본을 정의해 놓았으며, Provider 는 실제 Cloud 에 맞는 구현을 정의하였다. AWSCluster 에는 VPC, subnet, Route table 등과 같은 인프라 생성 정보를 가지고 있고 AWSMachineTemplate 은 Kubernetes Control Plane 에 대한 정보를 AWSMachineTemplate 에는 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;CR 을 배포하여 Workload cluster 를 생성한다.&lt;/p&gt;
&lt;pre class=&quot;mel&quot;&gt;&lt;code&gt;$ kubectl create ns capi-quickstart

$ kubectl apply -f capi-quickstart.yaml
=== output ===
cluster.cluster.x-k8s.io/capi-quickstart created
awscluster.infrastructure.cluster.x-k8s.io/capi-quickstart created
kubeadmcontrolplane.controlplane.cluster.x-k8s.io/capi-quickstart-control-plane created
awsmachinetemplate.infrastructure.cluster.x-k8s.io/capi-quickstart-control-plane created
machinedeployment.cluster.x-k8s.io/capi-quickstart-md-0 created
awsmachinetemplate.infrastructure.cluster.x-k8s.io/capi-quickstart-md-0 created
kubeadmconfigtemplate.bootstrap.cluster.x-k8s.io/capi-quickstart-md-0 created&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kubectl 명령어를 위해 아래와 같이 kubeconfig 를 생성한다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;$ clusterctl get kubeconfig capi-quickstart -n capi-quickstart &amp;gt; capi-quickstart.kubeconfig&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한가지 중요한 부분은 Cluster API 는 Network 모듈이나, CSI 를 설치해 주지는 않는다. 이는 추가로 설치해야 한다.&lt;/p&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;$ kubectl --kubeconfig=./capi-quickstart.kubeconfig \
  apply -f https://docs.projectcalico.org/v3.19/manifests/calico.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네트워크 모듈까지 다 설치하면 정상적으로 Kubernetes Cluster 가 설치된 것을 볼 수 있다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;$ kubectl get kubeadmcontrolplane -n capi-quickstart
=== output ===
NAME                            INITIALIZED   API SERVER AVAILABLE   VERSION   REPLICAS   READY   UPDATED   UNAVAILABLE
capi-quickstart-control-plane   true          true                   v1.20.5   3          3       3


$ kubectl --kubeconfig=mycluster.kubeconfig get nodes
=== output ===
NAME                                              STATUS   ROLES                  AGE   VERSION
ip-10-0-143-5.ap-northeast-2.compute.internal     Ready    control-plane,master   23h   v1.20.5
ip-10-0-164-198.ap-northeast-2.compute.internal   Ready    &amp;lt;none&amp;gt;                 23h   v1.20.5
ip-10-0-222-84.ap-northeast-2.compute.internal    Ready    control-plane,master   23h   v1.20.5
ip-10-0-255-19.ap-northeast-2.compute.internal    Ready    &amp;lt;none&amp;gt;                 23h   v1.20.5
ip-10-0-68-113.ap-northeast-2.compute.internal    Ready    &amp;lt;none&amp;gt;                 23h   v1.20.5
ip-10-0-80-79.ap-northeast-2.compute.internal     Ready    control-plane,master   23h   v1.20.5&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Kubernetes</category>
      <category>AWS Cloud Provider</category>
      <category>cluster api</category>
      <category>kubernetes</category>
      <category>Management Cluster</category>
      <category>Workload Cluster</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/282</guid>
      <comments>https://ahnseungkyu.com/282#entry282comment</comments>
      <pubDate>Fri, 16 Jul 2021 17:30:42 +0900</pubDate>
    </item>
    <item>
      <title>Cluster API 로 AWS에 Kubernetes 설치하기(1)</title>
      <link>https://ahnseungkyu.com/281</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;AWS 에서 Kubernetes 사용하는 방법은 Managed Service 인 EKS 서비스를 신청/설치 방법과 일반 VM 에 Kubernetes 를 설치하는 방법이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VM 에 Kubernetes 를 설치하는 방법은 VM 을 생성하고 필요한 Security Group 을 지정하고 Muti Control plane 에 ELB 를 연결하여 다중 Master 로 사용가능 하도록 세팅해야할 내용이 제법 있다. Kubernetes 자체 설치도 kubeadm 이나 kubespray 같은 툴을 사용해서 설치한다. - 역시 쉽지 않은 내용임에 분명하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Cluster API 란 ?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금 소개하는 방법은 Kubernetes Cluster Lifecycle SIG 에서 개발하고 있는 Cluster API 로 Operator Pattern 을 활용하여 Kubernetes 를 설치하는 방법이다. Cluster API 란 Management Kubernetes Cluster 에 Custom Controller 를 설치하고 Custom Resource 를 생성하면 자동으로 Cloud 에 VM 을 생성하고 Kubernetes 를 설치하는 방법이다. Controller 로 관리하기 때문에 VM 이 죽으면 다시 살려주는 장점이 있다. Kubernetes 가 설치된 VM 이 다운되었을 때 Self healing 으로 Recovering 해준다니 정말 멋진 아이디어인 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Cluster API 의 시작은 2년 정도 전부터 시작되었는데 초장기에는 PoC 정도였다면 지금은 어느 정도 안정화 되어 사용하기에 문제가 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개념을 보면 Management Kubernetes Cluster 를 설치(Kind, Minikube 등도 가능)하고 여기에 필요한 여러 Custom Controller 를 실행시킨다. 그리고 나서 Custom Resource 를 생성하면 지정된 Cloud 에 VM 을 생성하고 Workload Kubernetes Cluster (고객이 사용할 클러스터) 를 자동으로 생성해 주는 방법이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Cluster API 구성도&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1992&quot; data-origin-height=&quot;1508&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/n19aL/btq7Y6TvsNw/oGTqGSlo34743oQ4idwlk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/n19aL/btq7Y6TvsNw/oGTqGSlo34743oQ4idwlk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/n19aL/btq7Y6TvsNw/oGTqGSlo34743oQ4idwlk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fn19aL%2Fbtq7Y6TvsNw%2FoGTqGSlo34743oQ4idwlk0%2Fimg.png&quot; data-origin-width=&quot;1992&quot; data-origin-height=&quot;1508&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림에서 보면 좌측 맨 위에 Cluster API Controller 가 있다. Cluster API Controller 는 마치 java class 로 치면 Abstraction Class 의 역활과 동일하다. Cluster Pod Network, Control Plane VM 갯수, Node VM 갯수 등을 관리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 정의를 하면 Boostrap provider Controller 에서 kubeadm 으로 어떻게 Kubernetes 를 설치할 지를 관리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Infrastructure provider Controller 에서는 AWS, Azure, GCP 와 같이 Public Cloud 의 자원 생성을 관리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 Control Plane provider Controller 특별하게 Control Plane 의 설치를 관리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우측 위는 Custom Resource 를 보여주고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Cluster API Provider Controller 와 Infrastructure Provider Controller 의 상관 관계를 보면 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1078&quot; data-origin-height=&quot;590&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cGuIhv/btq7ZeRBKPk/SBnLtxJ1HKOhi2o9hWbWT0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cGuIhv/btq7ZeRBKPk/SBnLtxJ1HKOhi2o9hWbWT0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cGuIhv/btq7ZeRBKPk/SBnLtxJ1HKOhi2o9hWbWT0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcGuIhv%2Fbtq7ZeRBKPk%2FSBnLtxJ1HKOhi2o9hWbWT0%2Fimg.png&quot; data-origin-width=&quot;1078&quot; data-origin-height=&quot;590&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Cluster API 는 Infrastructure Provider 에게 이런 식으로 구현을 해야 한다고 알려주는 가이드라고 보면 된다.&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;h3 data-ke-size=&quot;size23&quot;&gt;Cluster API Controller&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Cluster API Controller 는 cluster 의 기본 정보를 관리하는 Controller 이다. 이 Controller 가 관리하는 Custom Resource 는 다음과 같이 4개가 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;clusters&lt;/li&gt;
&lt;li&gt;machinedeployments&lt;/li&gt;
&lt;li&gt;machinehealthchecks&lt;/li&gt;
&lt;li&gt;machines&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 중에서 machinehealthchecks 는 AWS Provider 에서는 사용하고 있지 않으므로 이를 제외하고 나머지 3가지만 살펴보겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;clusters CR(Custom Resource) 는 다음과 같은 정보를 가지고 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Cluster Pod Network 정보&lt;/li&gt;
&lt;li&gt;Kubernetes API url 정보&lt;/li&gt;
&lt;li&gt;Control Plane 을 생성하는 CR 정보&lt;/li&gt;
&lt;li&gt;Cloud Infrastructure 로 사용되는 CR 정보&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;  Cluster Network:
    Pods:
      Cidr Blocks:
        192.168.0.0/16
  Control Plane Endpoint:
    Host:  capi-quickstart-apiserver-479433786.ap-northeast-2.elb.amazonaws.com
    Port:  6443
  Control Plane Ref:
    API Version:  controlplane.cluster.x-k8s.io/v1alpha3
    Kind:         KubeadmControlPlane
    Name:         capi-quickstart-control-plane
    Namespace:    capi-quickstart
  Infrastructure Ref:
    API Version:  infrastructure.cluster.x-k8s.io/v1alpha3
    Kind:         AWSCluster
    Name:         capi-quickstart
    Namespace:    capi-quickstart&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;machinedeployments CR 의 정보는 &lt;u&gt;Kubernetes Worker Node 에 대한 일반적인 내용&lt;/u&gt;이며 아래의 내용을 포함한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Bootstrap 으로 사용될 Kubeadm Config Template&lt;/li&gt;
&lt;li&gt;Infrastructure Provider 에 대한 VM 정보 Template&lt;/li&gt;
&lt;li&gt;Cluster name 및 Kubernetes Version 정보&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;  Cluster Name:               capi-quickstart
  Min Ready Seconds:          0
  Progress Deadline Seconds:  600
  Replicas:                   3
  Revision History Limit:     1
  Selector:
    Match Labels:
      cluster.x-k8s.io/cluster-name:     capi-quickstart
      cluster.x-k8s.io/deployment-name:  capi-quickstart-md-0
  Strategy:
    Rolling Update:
      Max Surge:        1
      Max Unavailable:  0
    Type:               RollingUpdate
  Template:
    Metadata:
      Labels:
        cluster.x-k8s.io/cluster-name:     capi-quickstart
        cluster.x-k8s.io/deployment-name:  capi-quickstart-md-0
    Spec:
      Bootstrap:
        Config Ref:
          API Version:  bootstrap.cluster.x-k8s.io/v1alpha3
          Kind:         KubeadmConfigTemplate
          Name:         capi-quickstart-md-0
      Cluster Name:     capi-quickstart
      Infrastructure Ref:
        API Version:  infrastructure.cluster.x-k8s.io/v1alpha3
        Kind:         AWSMachineTemplate
        Name:         capi-quickstart-md-0
      Version:        v1.20.5&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;machines CR 은 Kubernetes Control Plane VM 별 정보와 Kubernetes Worker Node VM 별 정보를 갖고 있는데 둘다 아래의 정보를 동일하게 갖고 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Boostrap 으로 KubeadmConfig CR 정보&lt;/li&gt;
&lt;li&gt;Infrastructure 로서 AWSMachine CR 정보&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;  Bootstrap:
    Config Ref:
      API Version:     bootstrap.cluster.x-k8s.io/v1alpha3
      Kind:            KubeadmConfig
      Name:            capi-quickstart-md-0-7f4xk
      Namespace:       capi-quickstart
      UID:             7b095ef9-3380-45cc-950e-9bce8602f954
    Data Secret Name:  capi-quickstart-md-0-7f4xk
  Cluster Name:        capi-quickstart
  Infrastructure Ref:
    API Version:  infrastructure.cluster.x-k8s.io/v1alpha3
    Kind:         AWSMachine
    Name:         capi-quickstart-md-0-dcdcx
    Namespace:    capi-quickstart
    UID:          3383bd5b-1040-4577-a690-741c556d1076
  Provider ID:    aws:///ap-northeast-2a/i-090230ea1d12065ce
  Version:        v1.20.5&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Bootstrap Provider Controller&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Bootstrap provider controller 는 Kubernetes 를 설치하는 kubeadm 관련 정보를 가지고 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;kubeadmconfigs&lt;/li&gt;
&lt;li&gt;kubeadmconfigtemplates&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kubeadmconfigs 는 kubeadm 으로 kubernetes 를 설치할 때 사용하는 정보로서 Control Plane VM 별 정보와 Work Node VM별 정보를 갖고 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Cluster Configuration 으로 provider 정보를 갖고 있다.&lt;/li&gt;
&lt;li&gt;Join Configuration 으로 Token 정보를 갖고 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;  Cluster Configuration:
    API Server:
      Extra Args:
        Cloud - Provider:  aws
    Controller Manager:
      Extra Args:
        Cloud - Provider:  aws
    Dns:
    Etcd:
    Networking:
    Scheduler:
  Join Configuration:
    Control Plane:
      Local API Endpoint:
        Advertise Address:
        Bind Port:          0
    Discovery:
      Bootstrap Token:
        API Server Endpoint:  capi-quickstart-apiserver-479433786.ap-northeast-2.elb.amazonaws.com:6443
        Ca Cert Hashes:
          sha256:de8ef58efd55489531f681066eb77cec21a7d7f8e2a04eb41a06ad38b18d066e
        Token:                        xxxx.xxxxxxxxxxx
        Unsafe Skip CA Verification:  false
    Node Registration:
      Kubelet Extra Args:
        Cloud - Provider:  aws
      Name:                {{ ds.meta_data.local_hostname }}&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;kubeadmconfigtemplates 는 Worker Node 가 join 한 template 정보로 Node 명을 가진다.&lt;/p&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;  Template:
    Spec:
      Join Configuration:
        Node Registration:
          Kubelet Extra Args:
            Cloud - Provider:  aws
          Name:                {{ ds.meta_data.local_hostname }}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Infrastructure Provider Controller&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Infrastructure Provider Controller 는 각각의 Cloud 의 API 를 활용하여 리소스를 관리하는 Controller 로 aws 의 경우에는 아래의 정보를 가진다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;awsclustercontrolleridentities&lt;/li&gt;
&lt;li&gt;awsclusterroleidentities&lt;/li&gt;
&lt;li&gt;&lt;b&gt;awsclusters&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;awsclusterstaticidentities&lt;/li&gt;
&lt;li&gt;awsfargateprofiles&lt;/li&gt;
&lt;li&gt;awsmachinepools&lt;/li&gt;
&lt;li&gt;&lt;b&gt;awsmachines&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;awsmachinetemplates&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;awsmanagedclusters&lt;/li&gt;
&lt;li&gt;awsmanagedmachinepools&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 중에서 awsclusters, awsmachines, awsmachinetemplate 3가지만 살펴본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;awsclusters 는 aws 에 설치된 Kubernetes workload cluster 에 대한 정보를 갖고 있다.&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;  Bastion:
    Allowed CIDR Blocks:
      0.0.0.0/0
    Enabled:  false
  Control Plane Endpoint:
    Host:  capi-quickstart-apiserver-479433786.ap-northeast-2.elb.amazonaws.com
    Port:  6443
  Identity Ref:
    Kind:  AWSClusterControllerIdentity
    Name:  default
  Network Spec:
    Cni:
      Cni Ingress Rules:
        Description:  bgp (calico)
        From Port:    179
        Protocol:     tcp
        To Port:      179
        Description:  IP-in-IP (calico)
        From Port:    -1
        Protocol:     4
        To Port:      65535
    Subnets:
      Availability Zone:  ap-northeast-2a
      Cidr Block:         10.0.0.0/20
      Id:                 subnet-04e972e6bfcb98336
      Is Public:          true
      Nat Gateway Id:     nat-0d456fe6c4dd2ce3d
      Route Table Id:     rtb-0dfccca96ffc00732
      Tags:
        Name:                                                          capi-quickstart-subnet-public-ap-northeast-2a
        kubernetes.io/cluster/capi-quickstart:                         shared
        kubernetes.io/role/elb:                                        1
        sigs.k8s.io/cluster-api-provider-aws/cluster/capi-quickstart:  owned
        sigs.k8s.io/cluster-api-provider-aws/role:                     public
      Availability Zone:                                               ap-northeast-2a
      Cidr Block:                                                      10.0.64.0/18
      Id:                                                              subnet-06f2be3eedb46d622
      Is Public:                                                       false
      Route Table Id:                                                  rtb-00090ad5d1de60b20
      Tags:
        Name:                                                          capi-quickstart-subnet-private-ap-northeast-2a
        kubernetes.io/cluster/capi-quickstart:                         shared
        kubernetes.io/role/internal-elb:                               1
        sigs.k8s.io/cluster-api-provider-aws/cluster/capi-quickstart:  owned
        sigs.k8s.io/cluster-api-provider-aws/role:                     private
      Availability Zone:                                               ap-northeast-2b
      Cidr Block:                                                      10.0.16.0/20
      Id:                                                              subnet-02a9eed4c602fd3a2
      Is Public:                                                       true
      Nat Gateway Id:                                                  nat-050244cb7c9cff368
      Route Table Id:                                                  rtb-020e9366a2da25625
      Tags:
        Name:                                                          capi-quickstart-subnet-public-ap-northeast-2b
        kubernetes.io/cluster/capi-quickstart:                         shared
        kubernetes.io/role/elb:                                        1
        sigs.k8s.io/cluster-api-provider-aws/cluster/capi-quickstart:  owned
        sigs.k8s.io/cluster-api-provider-aws/role:                     public
      Availability Zone:                                               ap-northeast-2b
      Cidr Block:                                                      10.0.128.0/18
      Id:                                                              subnet-03880f2f847b3c21e
      Is Public:                                                       false
      Route Table Id:                                                  rtb-06b52ab77da5c5f2c
      Tags:
        Name:                                                          capi-quickstart-subnet-private-ap-northeast-2b
        kubernetes.io/cluster/capi-quickstart:                         shared
        kubernetes.io/role/internal-elb:                               1
        sigs.k8s.io/cluster-api-provider-aws/cluster/capi-quickstart:  owned
        sigs.k8s.io/cluster-api-provider-aws/role:                     private
      Availability Zone:                                               ap-northeast-2c
      Cidr Block:                                                      10.0.32.0/20
      Id:                                                              subnet-09ccabe6dd862df6a
      Is Public:                                                       true
      Nat Gateway Id:                                                  nat-030068539013d5c64
      Route Table Id:                                                  rtb-0973a222fc772ff76
      Tags:
        Name:                                                          capi-quickstart-subnet-public-ap-northeast-2c
        kubernetes.io/cluster/capi-quickstart:                         shared
        kubernetes.io/role/elb:                                        1
        sigs.k8s.io/cluster-api-provider-aws/cluster/capi-quickstart:  owned
        sigs.k8s.io/cluster-api-provider-aws/role:                     public
      Availability Zone:                                               ap-northeast-2c
      Cidr Block:                                                      10.0.192.0/18
      Id:                                                              subnet-0be3353fd3b6f1637
      Is Public:                                                       false
      Route Table Id:                                                  rtb-0854effe818750d33
      Tags:
        Name:                                                          capi-quickstart-subnet-private-ap-northeast-2c
        kubernetes.io/cluster/capi-quickstart:                         shared
        kubernetes.io/role/internal-elb:                               1
        sigs.k8s.io/cluster-api-provider-aws/cluster/capi-quickstart:  owned
        sigs.k8s.io/cluster-api-provider-aws/role:                     private
    Vpc:
      Availability Zone Selection:    Ordered
      Availability Zone Usage Limit:  3
      Cidr Block:                     10.0.0.0/16
      Id:                             vpc-070a545cb4b967dd7
      Internet Gateway Id:            igw-03a4ee0ca0f8d0f72
      Tags:
        Name:                                                          capi-quickstart-vpc
        sigs.k8s.io/cluster-api-provider-aws/cluster/capi-quickstart:  owned
        sigs.k8s.io/cluster-api-provider-aws/role:                     common
  Region:                                                              ap-northeast-2
  Ssh Key Name:                                                        capi-seungkyu&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;awsmachinetemplates 은 aws vm spec 에 대한 정보를 template 으로 갖고 있다. template 은 control plane 과 worker node 각 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;&lt;b&gt;control plane template&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;  Template:
    Spec:
      Iam Instance Profile:  control-plane.cluster-api-provider-aws.sigs.k8s.io
      Instance Type:         t3.large
      Ssh Key Name:          capi-seungkyu&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;worker node template&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;  Template:
    Spec:
      Iam Instance Profile:  nodes.cluster-api-provider-aws.sigs.k8s.io
      Instance Type:         t3.large
      Ssh Key Name:          capi-seungkyu&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;awsmachines 은 awsmachinetemplates 으로 연결된 control plane 과 worker node 별 aws VM 에 대한 정보를 갖는다.&lt;/p&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;contol plane vm1&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;  Ami:
  Cloud Init:
    Secure Secrets Backend:  secrets-manager
  Iam Instance Profile:      control-plane.cluster-api-provider-aws.sigs.k8s.io
  Instance ID:               i-0433d589b68e42cd0
  Instance Type:             t3.large
  Provider ID:               aws:///ap-northeast-2c/i-0433d589b68e42cd0
  Ssh Key Name:              capi-seungkyu&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Control plane Provider Controller&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Control plane provider controller 는 Kubernetes control plane 에 대한 정보를 관리하는 Controller 이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;kubeadmcontrolplanes&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kubeadmcontrolplanes 은 말그래도 control plane 의 정보를 담고 있으며 앞에서 살펴본 정보들을 활용한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Infrastructure Template 으로 AWSMachineTemplate 을 사용&lt;/li&gt;
&lt;li&gt;Kubeadm Config 로 Init Configuration 과 Join Configuration 정보&lt;/li&gt;
&lt;li&gt;Replicas 개수 정보&lt;/li&gt;
&lt;li&gt;Kubernetes version 정보&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;  Infrastructure Template:
    API Version:  infrastructure.cluster.x-k8s.io/v1alpha3
    Kind:         AWSMachineTemplate
    Name:         capi-quickstart-control-plane
    Namespace:    capi-quickstart
  Kubeadm Config Spec:
    Cluster Configuration:
      API Server:
        Extra Args:
          Cloud - Provider:  aws
      Controller Manager:
        Extra Args:
          Cloud - Provider:  aws
      Dns:
      Etcd:
      Networking:
      Scheduler:
    Init Configuration:
      Local API Endpoint:
        Advertise Address:
        Bind Port:          0
      Node Registration:
        Kubelet Extra Args:
          Cloud - Provider:  aws
        Name:                {{ ds.meta_data.local_hostname }}
    Join Configuration:
      Discovery:
      Node Registration:
        Kubelet Extra Args:
          Cloud - Provider:  aws
        Name:                {{ ds.meta_data.local_hostname }}
  Replicas:                  3
  Rollout Strategy:
    Rolling Update:
      Max Surge:  1
    Type:         RollingUpdate
  Version:        v1.20.5&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Kubernetes</category>
      <category>AWS</category>
      <category>cluster api</category>
      <category>kubernetes</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/281</guid>
      <comments>https://ahnseungkyu.com/281#entry281comment</comments>
      <pubDate>Thu, 24 Jun 2021 00:11:38 +0900</pubDate>
    </item>
    <item>
      <title>쿠알못을 위한 쿠버네티스 입문(2)</title>
      <link>https://ahnseungkyu.com/280</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=lIzAMFUKxBE&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/jxfPc/hyKCRpSYbu/ooY5qPZt7TKMuZC1g4Znd0/img.jpg?width=640&amp;amp;height=480&amp;amp;face=0_0_640_480&quot; data-video-width=&quot;640&quot; data-video-height=&quot;480&quot; data-video-origin-width=&quot;640&quot; data-video-origin-height=&quot;480&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/lIzAMFUKxBE&quot; width=&quot;640&quot; height=&quot;480&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=lIzAMFUKxBE&amp;amp;t=4s&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.youtube.com/watch?v=lIzAMFUKxBE&amp;amp;t=4s&lt;/a&gt;&lt;/p&gt;</description>
      <category>Kubernetes</category>
      <category>kubernetes</category>
      <category>입문</category>
      <category>쿠알못</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/280</guid>
      <comments>https://ahnseungkyu.com/280#entry280comment</comments>
      <pubDate>Sun, 20 Jun 2021 12:18:48 +0900</pubDate>
    </item>
    <item>
      <title>쿠알못을 위한 쿠버네티스 입문(1)</title>
      <link>https://ahnseungkyu.com/279</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=HNGEo7Kd3_k&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/Vkdx9/hyKCQqW1nl/hMq3jKbRkkJqOJFqPz87sk/img.jpg?width=480&amp;amp;height=360&amp;amp;face=0_0_480_360&quot; data-video-width=&quot;480&quot; data-video-height=&quot;360&quot; data-video-origin-width=&quot;480&quot; data-video-origin-height=&quot;360&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/HNGEo7Kd3_k&quot; width=&quot;480&quot; height=&quot;360&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=HNGEo7Kd3_k&amp;amp;t=3s&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.youtube.com/watch?v=HNGEo7Kd3_k&amp;amp;t=3s&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Kubernetes</category>
      <author>seungkyua@gmail.com</author>
      <guid isPermaLink="true">https://ahnseungkyu.com/279</guid>
      <comments>https://ahnseungkyu.com/279#entry279comment</comments>
      <pubDate>Sun, 20 Jun 2021 12:17:00 +0900</pubDate>
    </item>
  </channel>
</rss>