Kubernetes
Kubernetes λ₯Ό 곡λΆνλ©΄μ νλ λ©λͺ¨.
Kubernetes
δ»γγε§γγγοΌKubernetes ε ₯ι
History
Google μ¬λ΄μμ μ΄μ©νλ Container Cluster Manager βBorgβ μ μ°©μνμ¬ λ§λ€μ΄μ§ Open Source Software (OSS)
2014λ 6μ λ°μΉ
2015λ 7μ version 1.0.
version 1.0 μ΄ν Linux Foundation μ Could Native Computing Foundation (CNCF) λ‘ μ΄κ΄λμ΄ μ€λ¦½μ μ μ₯μμ κ°λ°
version 1.7 Production-Ready
De facto standard
2014λ 11μ Google Cloud Platform (GCP) κ° Google Container Engine (GKE, νμ Google Kuebernetes Engine) μ 곡 μμ
2017λ 2μ Microsoft Azure κ° Azure Container Service (AKS) 릴리μ¦
2017λ 11μ Amazon Web Service (AWS) κ° Amazon Elastic Container Service for Kubernetese (Amazon EKS) 릴리μ¦
Kubernetes λ‘ κ°λ₯ν μΌ
Docker λ₯Ό Product λ 벨μμ μ΄μ©νκΈ° μν΄μ κ³ λ €ν΄μΌ νλ μ λ€
볡μμ Docker Host κ΄λ¦¬
Container μ Scheduling
Rolling-Update
Scaling / Auto Scaling
Monitoring Container Live/Dead
Self Healing
Service Discovery
Load Balancing
Manage Data
Manage Workload
Manage Log
Infrastructure as Code
κ·Έ μΈ Ecosystemκ³Όμ μ°κ³μ νμ₯
μ λ¬Έμ λ€μ ν΄κ²°νκΈ° μν΄ Kubernetes κ° νμ
Kubernetes μμλ YAML νμ manifesto μ¬μ©
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: sample-deployment spec: replicas: 3 selector: matchLabels: app: sample-app template: metadata: labels: app: sample-app spec: containers: - name: nginx-container image: nginx:latest ports: - containerPort: 80 ` **Kubernets λ,**
볡μμ Docker Host λ₯Ό κ΄λ¦¬ν΄μ container cluster λ₯Ό ꡬμΆ
κ°μ container μ replica λ‘ μ€ννμ¬ λΆν λΆμ°κ³Ό μ₯μ μ λλΉ κ°λ₯
λΆνμ λ°λΌ container μ replica μλ₯Ό μ‘°μ (auto scaling) κ°λ₯
Disk I/O, Network ν΅μ λ λ±μ workload λ ssd, cpu λ±μ Docker Host specμ λ°λΌμ Container λ°°μΉκ° κ°λ₯
GCP / AWS / OpenStack λ±μμ ꡬμΆν κ²½μ°, availability zone λ±μ λΆκ° μ λ³΄λ‘ κ°λ¨ν multi region μ container λ°°μΉ κ°λ₯
κΈ°λ³Έμ μΌλ‘ CPU, Memory λ±μ μμ μν©μ λ°λΌ scaling
μμ λΆμ‘± λ±μ κ²½μ° Kubernetes cluster auto scaling μ΄μ© κ°λ₯
container process κ°μ
container process κ° λ©μΆλ©΄ self healing
HTTP/TCP, Shell Script λ±μ μ΄μ©ν Health Check λ κ°λ₯
νΉμ Container κ΅°μ λν΄ Load Balancing μ μ© κ°λ₯
κΈ°λ₯λ³λ‘ μΈλΆνλ micro service architecture μ νμν service discovery κ°λ₯
Container μ Service μ λ°μ΄ν°λ Backend μ etcd μ 보쑴
Container μμ 곡ν΅μ μΌλ‘ μ€μ μ΄λ Application μμ μ¬μ©νλ λ°μ΄ν°λ² μ΄μ€μ μνΈ λ±μ μ 보λ₯Ό Kubernetes Cluster μμ μ€μ κ΄λ¦¬ κ°λ₯
Kubernetes λ₯Ό μ§μ
Ansible : Deploy container to Kubernetes
Apache Ignite : Kubernetes μ Service Discovery κΈ°λ₯μ μ΄μ©ν μλ cluster ꡬμ±κ³Ό scaling
Fluentd : Kubernetes μμ Container Log λ₯Ό μ μ‘
Jenkins : Deploy container to Kubernetes
OpenStack : Cloud μ μ°κ³λ Kubernetes ꡬμΆ
Prometheus : Kubernetes κ°μ
Spark : job μ Kubernetes μμμ Native μ€ν (YARN λ체)
Spinnaker : Deploy container to Kubernetes
etcβ¦
Kubernetes μλ κΈ°λ₯ νμ₯μ΄ κ°λ₯νλλ‘ λμ΄ μμ΄ λ μμ μΈ κΈ°λ₯μ ꡬννλ κ²λ κ°λ₯
Kubernetes κ΅¬μΆ νκ²½ μ ν
κ°μΈ Windows / Mac μμ λ‘컬 Kubernetes νκ²½μ ꡬμΆ
κ΅¬μΆ ν΄μ μ¬μ©ν cluster ꡬμΆ
public cloud μ managed Kubernetes λ₯Ό μ΄μ©
νκ²½μ λ°λΌμ μΌλΆ μ΄μ© λΆκ°ν κΈ°λ₯λ μμΌλ κΈ°λ³Έμ μΌλ‘ μ΄λ€ νκ²½μμλ λμΌν λμμ΄ κ°λ₯νλλ‘ CNCF κ° Conformance Program μ μ 곡
Local Kubernetes
Minikube
VirtualBox νμ (xhyve, VMware Fusion λ μ΄μ© κ°λ₯)
Homebrew λ±μ μ΄μ©ν μ€μΉ κ°λ₯
Install
`$ brew update $ brew install kubectl $ brew cask install virtualbox $ brew install minikube `
Run
minikube κΈ°λ μ, νμμ λ°λΌ kubernetes λ²μ μ μ§μ κ°λ₯ --kubernetes-version
`$ minikube start βkubernetes-version v1.8.0 `
Minikube μ©μΌλ‘ VirtualBox μμ VM κ° κΈ°λλ κ²μ΄κ³ kubectl λ‘ Minikube μ ν΄λ¬μ€ν°λ₯Ό μ‘°μνλ κ²μ΄ κ°λ₯
μν νμΈ
`$ minikube status `
Minikube cluster μμ
`$ minikube delete `
Docker for Mac
DockerCon EU 17 μ Docker μ¬μμ Kubernetes support λ°ν
Kubernetes μ CLI λ±μμ Docker Swarm μ μ‘°μνλ λ±μ μ°κ³ κΈ°λ₯ κ°ν
17.12 CE Edge λ²μ λΆν° λ‘컬μ Kubernetes λ₯Ό κΈ°λνλ κ²μ΄ κ°λ₯
Kubernetes λ²μ μ§μ μ λΆκ°
Docker for Mac μ€μ μμ Enable Kubernetes μ§μ
μ΄ν kubectl λ‘ cluster μ‘°μ κ°λ₯
`$ kubectl config use-context docker-for-desktop `
kubectl μμμ Docker Host κ° nodeλ‘ μΈμ
`$ kubectl get nodes `
Kubernetes κ΄λ ¨ componentκ° container λ‘μ κΈ°λ
`$ docker ps --format 'table {{.Image}}\t{{.Command}}' | grep -v pause `
Kubernetes κ΅¬μΆ Tool
kubeadm
Kubernetes κ° κ³΅μμ μΌλ‘ μ 곡νλ κ΅¬μΆ λꡬ
μ¬κΈ°μλ Ubuntu 16.04 κΈ°μ€μΌλ‘ κΈ°λ‘ (νκ²½ λ° νμ λ²μ μ λ°λΌ μΌλΆ λ³κ²½ νμν¨)
μ€λΉ
`apt-get update && apt-get install -y apt-transport-https curl -s https://package.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - cat </etc/aptsources.list.d/kubernetes.list deb http://apt.kubernetes.io/ kubernetes-xenial main EOF apt-get update apt-get install -y kubelet=1.8.5-00 kubeadm=1.8.5-00 kubectl=1.8.5-00 docker.io sysctl net.bridge.bridge-nf-call-iptables=1 `
Master node λ₯Ό μν μ€μ
--pod-network-cidrμ cluster λ΄ network (pod network) μ©μΌλ‘ Flannelμ μ΄μ©νκΈ° μν μ€μ
`$ kubeadm init --pod-network-cidr=10.244.0.0/16 `
μ μ€μ λͺ λ ΉμΌλ‘ λ§μ§λ§μ Kubernetes node λ₯Ό μ€ννκΈ° μν λͺ λ Ήμ΄κ° μΆλ ₯λλ©° μ΄ν node μΆκ°μμ μ€ννλ€.
`$ kubeadm join --token ... 10.240.0.7:6443 --discovery-token-ca-cert-hash sha256:... `
kubectl μμ μ¬μ©ν μΈμ¦ νμΌ μ€λΉ
`$ mkdir -p $HOME/.kube $ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config $ sudo chown $(id -u):$(id -g) $HOME/.kube/config `
Flannel deamon container κΈ°λ
`$ kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/v0.9.1/Documentation/kube-flannel.yml `
Flannel μ΄ μΈμλ λ€λ₯Έ μ νμ΄ κ°λ₯ Installing a pod network add-on
Rancher
Rancher Labs μ¬
Open Source Container Platform
version 1.0 μμλ Kubernetes λ μν¬νΈ νλ νμ
version 2.0 λΆν°λ Kubernetes λ₯Ό λ©μΈμΌλ‘
Kubernetes cluster λ₯Ό λ€μν νλ«νΌμμ κ°λ₯ (AWS, OpenStack, VMware etc..)
κΈ°μ‘΄μ Kubernetes cluster λ₯Ό Rancher κ΄λ¦¬λ‘ μ ν κ°λ₯
μ€μμ§μ€μ μΈ μΈμ¦, λͺ¨λν°λ§, WebUI λ±μ κΈ°λ₯μ μ 곡
νλΆν Application Catalog
Rancher Server κΈ°λ
`docker run -d --restart=unless-stopped -p 8080:8080 rancher/server:v2.0.0-alpha10 `
μ΄ Rancher Server μμ κ° Kubernetes cluster μ κ΄λ¦¬μ cloud provider μ°κ³ λ±μ μν
etc
Techtonic (CoreOS)
Kubespray
kops
OpenStack Magnum
Public Cloud managed Kubernetes
GKE (Google Kubernetes Engine)
λ§μ νΈλ¦¬ν κΈ°λ₯μ μ 곡
GCP (Google Cloud Platform) μ Integration.
HTTP LoadBalancer (Ingress) μ¬μ© κ°λ₯
NodePool
GUI or gcloud λͺ λ Ήμ΄ μ¬μ©
cluster version κ°λ¨ update
GCE (Google Compute Engine) λ₯Ό μ¬μ©ν cluster κ΅¬μΆ κ°λ₯
Container λ₯Ό μ¬μ©νμ¬ Kubernetes λ Έλκ° μ¬μμ±λμ΄λ μλΉμ€μ μν₯μ λ―ΈμΉμ§ μκ² μ€κ³ κ°λ₯
Kubernetes cluster λ΄λΆμ node μ label μ λΆμ¬ Group ν κ°λ₯
Group ν νμ¬ Scheduling μ μ΄μ© κ°λ₯
cloud λͺ λ Ήμ΄λ‘ cluster ꡬμΆ
`$ gcloud container clusters create example-cluster `
μΈμ¦ μ 보 μ μ₯
`$ gcloud container clusters get-credentials example-cluster `
etc
Google Kubernetes Engine
AKS (Azure Container Service)
Azure Container Service
EKS (Elastic Container Service for Kubernetes)
Amazon EKS
Kubernetes κΈ°μ΄
Kubernetes λ μ€μ λ‘ Docker μ΄μΈμ container runtime μ μ΄μ©ν host λ κ΄λ¦¬ν μ μλλ‘ λμ΄ μλ€. Kubernetes = Kubernetes Master + Kubernetes Node
Kubernetes Master
Kubernetes Node
API endpoint μ 곡
container scheduling
container scaling
Docker Host μ²λΌ μ€μ λ‘ container κ° λμνλ host
Kubernetes cluster λ₯Ό μ‘°μν λ, CLI tool μΈ kubectl κ³Ό YAML νμ manifest file μ μ¬μ©νμ¬ Kubernetes Master μ resource λ±λ‘ kubectl λ λ΄λΆμ μΌλ‘λ Kubernetes Master API λ₯Ό μ¬μ© = Library, curl λ±μ μ΄μ©ν μ‘°μλ κ°λ₯
Kubernetes & Resource
resource λ₯Ό λ±λ‘νλ©΄ λΉλκΈ°λ‘ container μ€νκ³Ό load balancer μμ±λλ€. Resource μ’ λ₯μ λ°λΌ YAML manifest μ μ¬μ©λλ parameter κ° μμ΄
Kubernetes API Reference Docs
Kubernetes Resource
Workloads : container μ€νμ κ΄λ ¨
Discovery & LB : container μΈλΆ κ³΅κ° κ°μ endpointλ₯Ό μ 곡
Config & Storage : μ€μ , κΈ°λ°μ 보, Persistent volume λ±μ κ΄λ ¨
Cluster : security & quota λ±μ κ΄λ ¨
Metadata : resource μ‘°μ
Workloads
cluster μμ container λ₯Ό κΈ°λνκΈ° μν΄ μ΄μ© λ΄λΆμ μΌλ‘ μ΄μ©νλ κ²μ μ μΈν μ΄μ©μκ° μ§μ μ΄μ©νλ κ²μΌλ‘λ λ€μκ³Ό κ°μ μ’ λ₯
Pod
ReplicationController
ReplicaSet
Deployment
DaemonSet
StatefulSet
Job
CronJob
Discovery & LB
container μ service discovery, endpoint λ±μ μ 곡 λ΄λΆμ μΌλ‘ μ΄μ©νλ κ²μ μ μΈν μ΄μ©μκ° μ§μ μ΄μ©νλ κ²μΌλ‘λ λ€μκ³Ό κ°μ μ’ λ₯
Service : endpoint μ μ 곡방μμ λ°λΌ 볡μμ νμ μ΄ μ‘΄μ¬
Ingress
ClusterIP
NodePort
LoadBalancer
ExternalIP
ExternalName
Haedless
Config & Storage
μ€μ μ΄λ κΈ°λ° λ°μ΄ν° λ±μ container μ λ£κ±°λ Persistent volumeμ μ 곡
Secret
ConfigMap
PersistentVolumeClaim Secret κ³Ό ConfigMap μ key-value νμμ λ°μ΄ν° ꡬ쑰
Cluster
cluster μ λμμ μ μ
Namespace
ServiceAccount
Role
ClusterRole
RoleBinding
ClusterRoleBinding
NetworkPolicy
ResourceQuota
PersistentVolume
Node
Metadata
cluster λ΄λΆμ λ€λ₯Έ resource λμμ μ μ΄
CustomResourceDefinition
LimitRange
HorizontalPodAutoscaler
Namespace μ λ°λ₯Έ κ°μ cluster μ λΆλ¦¬
Kubernetes κ°μ cluster λΆλ¦¬ κΈ°λ₯ (μμ λΆλ¦¬λ μλ) νλμ Kubernetes cluster λ₯Ό 볡μ νμμ μ΄μ© κ°λ₯νκ² ν¨ Kubernetes cluster λ RBAC (Role-Based Access Control) μ΄ κΈ°λ³Έ μ€μ μΌλ‘ Namesapce λ₯Ό λμμΌλ‘ κΆν μ€μ μ ν μ μμ΄ λΆλ¦¬μ±μ λμ΄λ κ²μ΄ κ°λ₯
μ΄κΈ° μνμ 3κ°μ§ Namespace
default
kube-system : Kubernetes cluster μ componentμ addon κ΄λ ¨
kube-public : λͺ¨λκ° μ¬μ© κ°λ₯ν ConfigMap λ±μ λ°°μΉ
CLI tool kubectl & μΈμ¦ μ 보
kubectl μ΄ Kubernetes Master μ ν΅μ νκΈ° μν΄ μ μ μλ²μ μ 보μ μΈμ¦ μ 보 λ±μ΄ νμ. κΈ°λ³ΈμΌλ‘λ `~/.kube/config` μ κΈ°λ‘λ μ 보λ₯Ό μ΄μ© `~/.kube/config` λ YAML Manifest `~/.kube/config` example <pre>`apiVersion: v1 kind: Config preferences: {} clusters: - name: sample-cluster cluster: server: https://localhost:6443 users: - name: sample-user user: client-certificate-data: agllk5ksdgls2... client-key-data: aglk14l1t1ok15... contexts: - name: sample-context context: cluster: sample-cluster namespace: default user: sample-user current-context: sample-context `</pre>
`~/.kube/config` μλ κΈ°λ³Έμ μΌλ‘ cluster, user, context 3κ°μ§λ₯Ό μ μ cluster : μ μνκΈ° μν cluster μ 보 user : μΈμ¦ μ 보 context : cluster μ user νμ΄μ namespace μ§μ kubectl λ₯Ό μ¬μ©ν μ€μ <pre>`# ν΄λ¬μ€ν° μ μ $ kubectl config set-cluster prd-cluster --server=https://localhost:6443 # μΈμ¦μ 보 μ μ $ kubectl config set-credentials admin-user \ --client-certificate \ --client-key=./sample.key \ --embed-certs=true # context(cluster, μΈμ¦μ 보, Namespace μ μ) $ kubectl config --set-context prd-admin \ --cluster=prd-cluster \ --user=admin-user \ --namespace=default `</pre>
context λ₯Ό μ ννλ κ²μΌλ‘ 볡μμ cluster μ user λ₯Ό μ¬μ©νλ κ²μ΄ κ°λ₯
`# context μ ν $ kubectx prd-admin Switched to context "prd-admin". # namespace μ ν $ kubens kube-system Context "prd-admin" is modified. Active Namespace is "kube-system". `
## kubectl & YAML Manifest YAML Manifest λ₯Ό μ¬μ©ν container κΈ°λ
pod μμ±
`# sample-pod.yml apiVersion: vi kind: Pod metadata: name: sample-pod spec: containers: - name: nginx-container image: nginx:1.12 `
resource μμ±
`# create resource $ kubectl create -f sample-pod.yml `
resource μμ
`# delete resource $ kubectl delete -f sample-pod.yml `
resource update
`# apply μΈ set, replace, edit λ±λ μ¬μ© κ°λ₯ $ kubectl apply -f sample-pod.yml `
## kubectl μ¬μ©λ²
resource λͺ©λ‘ νλ (get)
`$ kubectl get pods # νλν λͺ©λ‘ μμΈ μΆλ ₯ $ kubectl get pods -o wide `
-o, βoutput μ΅μ μ μ¬μ©νμ¬ JSON / YAML / custom-columns / Go Template λ± λ€μν νμμΌλ‘ μΆλ ₯νλ κ²μ΄ κ°λ₯. κ·Έλ¦¬κ³ μμΈν μ 보κΉμ§ νμΈ κ°λ₯. pods λ₯Ό all λ‘ λ°κΎΈλ©΄ λͺ¨λ 리μμ€ μΌλ νλ
resource μμΈ μ 보 νμΈ (describe)
`$ kubectl describe pods sample-pod $ kubectl describe node k15l1 `
get λͺ λ Ήμ΄ λ³΄λ€ resource μ κ΄λ ¨ν μ΄λ²€νΈλ λ μμΈν μ 보λ₯Ό νμΈ κ°λ₯
λ‘κ·Έ νμΈ (logs)
`# Pod λ΄ container μ λ‘κ·Έ μΆλ ₯ $ kubectl logs sample-pod # 볡μ container κ° ν¬ν¨λ Pod μμ νΉμ container μ λ‘κ·Έ μΆλ ₯ $ kubectl logs sample-pod -c nginx-container # log follow option -f $ kubectl logs -f sample-pod # μ΅κ·Ό 1μκ°, 10건, timestamp νμ $ kubectl logs --since=1h --tail=10 --timestamp=true sample-pod `
Pod μμ νΉμ λͺ λ Ή μ€ν (exec)
`# Pod λ΄ container μμ /bin/sh $ kubectl exec -it sample-pod /bin/sh # 볡μ container κ° ν¬ν¨λ Pod μ νΉμ container μμ /bin/sh $ kubectl exec -it sample-pod -c nginx-container /bin/sh # μΈμκ° μλ λͺ λ Ήμ΄μ κ²½μ°, -- μ΄νμ κΈ°μ¬ $ kubectl exec -it sample-pod -- /bin/ls -l / `
port-forward
`# localhost:8888 λ‘ λ€μ΄μ€λ λ°μ΄ν°λ₯Ό Podμ 80 ν¬νΈλ‘ μ μ‘ $ kubectl port-forward sample-pod 8888:80 # μ΄ν localhost:8888 μ ν΅ν΄ Podμ 80 ν¬νΈλ‘ μ κ·Ό κ°λ₯ $ curl localhost:8888 `
shell completion
`# bash $ source <(kubectl completion bash) # zsh completion $ source <(kubectl completion zsh) `
## Kubernetes Workloads Resource ## Workloads Resource
cluster μμμ container λ₯Ό κΈ°λνκΈ° μν΄ μ΄μ©
8 μ’ λ₯μ resource μ‘΄μ¬
Pod
ReplicationController
ReplicaSet
Deployment
DaemonSet
StatefulSet
Job
CronJob
λλ²κ·Έ, νμΈ μ©λλ‘ μ£Όλ‘ μ΄μ©
ReplicaSet μ¬μ© μΆμ²
Pod μ scale κ΄λ¦¬
scale κ΄λ¦¬ν workload μμ κΈ°λ³Έμ μΌλ‘ μ¬μ© μΆμ²
κ° λ Έλμ 1 Pod μ© λ°°μΉ
Persistent Data λ stateful ν workload μ κ²½μ° μ¬μ©
work queue & task λ±μ container μ’ λ£κ° νμν workload μ μ¬μ©
μ κΈ°μ μΌλ‘ Jobμ μν
Pod
Kubernetes Workloads Resource μ μ΅μλ¨μ
1κ° μ΄μμ container λ‘ κ΅¬μ±
Pod λ¨μλ‘ IP Address κ° ν λΉ
λλΆλΆμ κ²½μ° νλμ Podμ νλμ container λ₯Ό ν¬ν¨νλ κ²½μ°κ° λλΆλΆ
proxy, local cache, dynamic configure, ssh λ±μ 보쑰 μν μ νλ container λ₯Ό κ°μ΄ ν¬ν¨ νλ κ²½μ°λ μλ€.
κ°μ Pod μ μν container λ€μ κ°μ IP Address
container λ€μ localhost λ‘ μλ‘ ν΅μ κ°λ₯
Network Namespace λ Pod λ΄μμ 곡μ
보쑰νλ sub container λ₯Ό side car λΌκ³ λΆλ₯΄κΈ°λ νλ€.
Pod μμ±
sample pod μ μμ±νλ pod_sample.ymlapiVersion: v1 kind: Pod metadata: name: sample-pod spec: containers: - name: nginx-container image: nginx:1.12 ports: - containerPort: 80
nginx:1.12 imageλ₯Ό μ¬μ©ν container κ° νλμ 80 ν¬νΈλ₯Ό κ°λ°©
μ€μ νμΌμ κΈ°λ°μΌλ‘ Pod μμ±
`$ kubectl apply -f ./pod_sample.yml `
κΈ°λν Pod νμΈ
`$ kubectl get pods # λ³΄λ€ μμΈν μ 보 μΆλ ₯ $ kubectl get pods --output wide `
**2 κ°μ container λ₯Ό ν¬ν¨ν Pod μμ±**
2pod_sample.yml
`apiVersion: v1 kind: Pod metadata: name: sample-2pod spec: containers: - name: nginx-container-112 image: nginx:1.12 ports: - containerPort: 80 - name: nginx-container-113 image: nginx:1.13 ports: - containerPort: 8080 `
**container λ΄λΆ μ§μ **
container μ bash λ±μ μ€ννμ¬ μ§μ
`$ kubectl exec -it sample-pod /bin/bash `
-t : λͺ¨μ λ¨λ§ μμ±
-i : νμ€μ λ ₯ pass through
ReplicaSet / ReplicationController
Pod μ replica λ₯Ό μμ±νμ¬ μ§μ ν μμ Podμ μ μ§νλ resource
μ΄μ°½κΈ° ReplicationController μμΌλ ReplicaSet μΌλ‘ νμ λ³κ²½λ¨
ReplicationController λ equality-based selector μ΄μ©. νμ§ μμ .
ReplicaSet μ set-based selector μ΄μ©. κΈ°λ³Έμ μΌλ‘ μ΄λ₯Ό μ΄μ©ν κ².
ReplicaSet μμ±
sample ReplicaSet μμ± (rs_sample.yml)
`apiVersion: apps/v1 kind: ReplicaSet metadata: name: sample-rs spec: replicas: 3 selector: matchLabels: app: sample-app template: metadata: labels: app: sample-app spec: containers: - name: nginx-container image: nginx:1.12 ports: - containerPort: 80 `
ReplicaSet μμ±
`$ kubectl apply -f ./rs_sample.yml `
ReplicaSet νμΈ
`$ kubectl get rs -o wide `
Label μ§μ νμ¬ Pod νμΈ
`$ kubectl get pod -l app=sample-app -o wide `
**Pod μ μ§ & auto healing**
auto healing = ReplicaSet μ node λ pod μ μ₯μ κ° λ°μν΄λ pod μλ₯Ό μ§μ ν μλ§νΌ μ μ§λλλ‘ λ³λμ node μ container λ₯Ό κΈ°λν΄μ£ΌκΈ°μ μ₯μ μ λλΉνμ¬ μν₯μ μ΅μνν μ μλλ‘ κ°λ₯νλ€.
Pod μμ
`$ kubectl delete pod sample-rs-7r6sr `
Pod μμ ν λ€μ Pod νμΈ νλ©΄ ReplicaSet μ΄ μλ‘ Pod μ΄ μμ±λ κ²μ νμΈ κ°λ₯
ReplicaSet μ Pod μ¦κ°μ kubectl describe rs λͺ λ Ήμ΄λ‘ μ΄λ ₯μ νμΈ κ°λ₯
Label & ReplicaSet
ReplicaSet μ Kubernetes κ° Pod μ κ°μνμ¬ μλ₯Ό μ‘°μ
κ°μνκΈ° μν Pod Label μ spec.selector μμ μ§μ
νΉμ λΌλ²¨μ΄ λΆμ Pod μ μλ₯Ό μΈλ κ²μΌλ‘ κ°μ
λΆμ‘±νλ©΄ μμ±, μ΄κ³Όνλ©΄ μμ
`selector: matchLabels: app: sample-app `
μμ±λλ Pod Label μ labels μ μ μ.
spec.template.metadata.labels μ λΆλΆμλ app:sample-app μμΌλ‘ μ€μ μ΄ λ€μ΄κ°μ Label κ° λΆμ¬λ μνλ‘ Pod μ΄ μμ±λ¨.
`labels: app: sample-app `
spec.selector μ spec.template.metadata.labels κ° μΌμΉνμ§ μμΌλ©΄ Pod μ΄ λμμ΄ μμ±λλ€κ° μλ¬κ° λ°μνκ² λ κ²β¦
ReplicaSet μ μ΄μ©νμ§ μκ³ μΈλΆμμ λ³λλ‘ λμΌν label μ μ¬μ©νλ Pod μ λμ°λ©΄ μ΄κ³Όν μλ§νΌμ Pod μ μμ νκ² λλ€. μ΄ λ, μ΄λ Pod μ΄ μ§μμ§κ² λ μ§λ μ μ μμΌλ―λ‘ μ£Όμκ° νμ
νλμ container μ 볡μ label μ λΆμ¬νλ κ²λ κ°λ₯
`labels: env: dev codename: system_a role: web-front `
**Pod scaling**
yaml config μ μμ νμ¬ kubectl apply -f FILENAME μ μ€ννμ¬ λ³κ²½λ μ€μ μ μ©
kubectl scale λͺ λ Ήμ΄λ‘ scale μ²λ¦¬
scale λͺ λ Ήμ΄λ‘ μ²λ¦¬ κ°λ₯ν λμμ
Deployment
Job
ReplicaSet
ReplicationController
`$ kubectl scale rs sample-rs --replicas 5 `
## Deployment
볡μμ ReplicaSet μ κ΄λ¦¬νμ¬ rolling update μ roll-back λ±μ μ€ν κ°λ₯
λ°©μ
μ ν λ°©μ
Kubernetes μμ κ°μ₯ μΆμ²νλ container μ κΈ°λ λ°©λ²
μλ‘μ΄ ReplicaSet μ μμ±
μλ‘μ΄ ReplicaSet μμ Replica count λ₯Ό μ¦κ°μν΄
μ€λλ ReplicaSet μμ Replica count λ₯Ό κ°μμν΄
2, 3 μ λ°λ³΅
μλ‘μ΄ ReplicaSet μμμ container κ° κΈ°λνλμ§, health checkλ₯Ό ν΅κ³Όνλμ§ νμΈνλ©΄μ
ReplicaSet μ μ΄νν λμ Pod μμ μμΈ μ§μ μ΄ κ°λ₯
Deployment μμ±
deployment_sample.yml
`apiVersion: apps/v1 kind: Deployment metadata: name: sample-deployment spec: replicas: 3 selector: matchLabels: app: sample-app template: metadata: labels: app: sample-app spec: containers: - name: nginx-container image: nginx:1.12 ports: - containerPort: 80 `
deployment μμ±
`# record μ΅μ μ μ¬μ©νμ¬ update μ μ΄λ ₯μ 보쑴 κ°λ₯ $ kubectl apply -f ./deployment_sample.yml --record `
μ΄λ ₯μ metadata.annotations.kubernetes.io/change-causeμ 보쑴
νμ¬ ReplicaSet μ Revision λ²νΈλ metadata.annotations.deployment.kubernetes.io/revisionμμ νμΈ κ°λ₯
`$ kubectl get rs -o yaml | head `
kubectl run μΌλ‘ κ±°μ κ°μ deployment λ₯Ό μμ±νλ κ²λ κ°λ₯
λ€λ§ default label run:sample-deployment κ° λΆμ¬λλ μ°¨μ΄ μ λ
`$ kubectl run sample-deployment --image nginx:1.12 --replicas 3 --port 80 `
deployment νμΈ
`$ kubectl get deployment $ kubectl get rs $ kubectl get pods `
container update
`# nginx container iamge λ²μ μ λ³κ²½ $ kubectl set image deployment sample-deployment nginx-container=nginx:1.13 `
**Deployment update condition**
Deployment μμ λ³κ²½μ΄ μμΌλ©΄ ReplicaSet μ΄ μμ±λλ€.
replica μλ λ³κ²½ μ¬ν λμμ ν¬ν¨λμ§ μλλ€
μμ±λλ Pod μ λ΄μ© λ³κ²½μ΄ λμ
spec.template μ λ³κ²½μ΄ μμΌλ©΄ ReplicaSet μ μ κ· μμ±νμ¬ rolling update μν
spec.templateμ΄νμ ꡬ쑰체 ν΄μ¬κ°μ κ³μ°νμ¬ κ·Έκ²μ μ΄μ©ν΄ label μ λΆμ΄κ³ κ΄λ¦¬λ₯Ό νλ€.
`# Deployment using hash value $ kubectl get rs sample-deployment-xxx -o yaml `
**Roll-back**
ReplicaSet μ κΈ°λ³Έμ μΌλ‘ μ΄λ ₯μΌλ‘μ ννκ° λ¨κ³ replica μλ₯Ό 0μΌλ‘ νκ³ μλ€.
λ³κ²½ μ΄λ ₯ νμΈ kubectl rollout history
`$ kubectl rollout history deployment sample-deployment `
deployment μμ± μ βrecord λ₯Ό μ¬μ©νλ©΄ CHANGE_CAUSE λΆλΆμ κ°λ μ‘΄μ¬
roll-back μ revision κ° μ§μ κ°λ₯. λ―Έμ§μ μ νλ μ revision μ¬μ©.
`# ν λ¨κ³ μ revision (default --to-revision = 0) $ kubectl rollout undo deployment sample-deployment # revision μ§μ $ kubectl rollout undo deployment sample-deployment --to-revision 1 `
roll-back κΈ°λ₯λ³΄λ€ μ΄μ YAML νμΌμ kubectl applyλ‘ μ μ©νλκ² λ νΈν μ μμ.
spec.templateμ κ°μ κ±Έλ‘ λ리면 Template Hash λ λμΌνμ¬ kubectl rollout κ³Ό λμΌν λμμ μννκ² λλ€.
Deployment Scaling
ReplicaSets μ λμΌν λ°©λ²μΌλ‘ kubectl scale or kubectl apply -fμ μ¬μ©νμ¬ scaling κ°λ₯
λ³΄λ€ κ³ κΈμ§ update λ°©λ²
recreate λΌλ λ°©μμ΄ μ‘΄μ¬
DaemonSet
ReplicaSet μ νΉμν νμ
λͺ¨λ Node μ 1 pod μ© λ°°μΉ
λͺ¨λ Node μμ λ°λμ μ€νλμ΄μΌ νλ process λ₯Ό μν΄ μ΄μ©
replica μ μ§μ λΆκ°
2 pod μ© λ°°μΉ λΆκ°
ReplicaSet μ κ° Kubernetes Node μμ μν©μ λ°λΌ Pod μ λ°°μΉνλ κ²μ΄κΈ°μ κ· λ±νκ² λ°°ν¬λλ€λ 보μ₯μ΄ μλ€.
DaemonSet μμ±
ds_sample.yml
`apiVersion: apps/v1 kind: DaemonSet metadata: name: sample-ds spec: selector: matchLabels: app: sample-app template: metadata: labels: app: sample-app spec: containers: - name: nginx-container image: nginx:1.12 ports: - containerPort: 80 `
DaemonSet μμ±
`$ kubectl apply -f ./ds_sample.yml `
νμΈ
`$ kubectl get pods -o wide `
## StatefulSet
ReplicaSet μ νΉμν νν
database μ²λΌ stateful ν workloads μ λμνκΈ° μν¨
μμ±λλ Pod λͺ μ΄ μ«μλ‘ indexing
persistent μ±
sample-statefulset-1, sample-statefulset-2, β¦
PersistentVolumeμ μ¬μ©νλ κ²½μ° κ°μ disk λ₯Ό μ΄μ©νμ¬ μ¬μμ±
Pod λͺ μ΄ λ°λμ§ μμ
StatefulSet μμ±
spec.volumeClaimTemplates μ§μ κ°λ₯
statefulset-sample.yml
persistent data μμμ μ¬μ¬μ©νμ¬ pod μ΄ λ³΅κ·νμ λ λμΌ λ°μ΄ν°λ₯Ό μ¬μ©νμ¬ container κ° μμ±λλλ‘ κ°λ₯
`apiVersion: apps/v1 kind: StatefulSet metadata: name: sample-statefulset spec: replicas: 3 selector: matchLabels: app: sample-app template: metadata: labels: app: sample-app spec: containers: - name: nginx-container image: nginx:1.12 ports: - containerPort: 80 volumeMounts: - name: www mountPath: /usr/share/nginx/html volumeClaimTemplates: - metadata: name: www spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi `
StatefulSet μμ±
`$ kubectl apply -f ./statefulset_sample.yml `
νμΈ (ReplicaSet κ³Ό κ±°μ λμΌν μ 보)
`$ kubectl get statefulset # Pod μ΄λ¦μ μ°μλ μλ‘ index κ° suffix λ κ²μ νμΈ $ kubectl get pods -o wide `
scale out μ 0, 1, 2 μ μμΌλ‘ λ§λ€μ΄μ§
scale in μ 2, 1, 0 μ μμΌλ‘ μμ
StatefulSet Scaling
ReplicaSets μ λμΌ kubectl scale or kubectl apply -f
Persistent μμ data 보쑴 νμΈ
`$ kubectl exec -it sample-statefulset-0 ls /usr/share/nginx/html/sample.html ls: cannot access /usr/share/nginx/html/sample.html: No such file or directory $ kubectl exec -it sample-statefulset-0 touch /usr/share/nginx/html/sample.html $ kubectl exec -it sample-statefulset-0 ls /usr/share/nginx/html/sample.html /usr/share/nginx/html/sample.html `
kubectl λ‘ Pod μμ λ₯Ό νλμ§ container λ΄λΆμμ Exception λ±μ΄ λ°μνλ λ±μΌλ‘ container κ° μ μ§ν΄λ file μ΄ μ¬λΌμ§μ§ μλλ€.
Pod λͺ μ΄ λ°λμ§ μμλ IP Address λ λ°λ μ μλ€.
Life Cycle
ReplicaSet κ³Ό λ€λ₯΄κ² 볡μμ Pod μ λ³λ ¬λ‘ μμ±νμ§ μκ³ 1κ°μ© μμ±νμ¬ Ready μνκ° λλ©΄ λ€μ Pod μ μμ±νλ€.
μμ μ, index κ° κ°λ₯ ν° (μ΅μ ) container λΆν° μμ
index:0 μ΄ Master κ° λλλ‘ κ΅¬μ±μ μ§€ μ μλ€.
Job
container λ₯Ό μ΄μ©νμ¬ μΌνμ± μ²λ¦¬λ₯Ό μν
λ³λ ¬ μ€νμ΄ κ°λ₯νλ©΄μ μ§μ ν νμλ§νΌ container λ₯Ό μ€ν (μ μμ’ λ£) νλ κ²μ 보μ₯
Job μ μ΄μ© κ°λ₯ν κ²½μ°μ Pod κ³Όμ μ°¨μ΄
Pod μ΄ μ μ§νλ κ²μ μ μ λ‘ λ§λ€μ΄μ Έ μλκ°?
Pod, ReplicaSets μμ μ μ§=μμμΉ λͺ»ν μλ¬
Job μ μ μ§=μ μμ’ λ£
patch λ±μ μ²λ¦¬μ μ ν©
Job μμ±
job_sample.yml : 60μ΄ sleep
ReplicaSets μ λμΌνκ² label κ³Ό selector λ₯Ό μ§μ κ°λ₯νμ§λ§ kubernetes μμ μλμΌλ‘ μΆ©λνμ§ μλλ‘ uuid λ₯Ό μλ μμ±ν¨μΌλ‘ κ΅³μ΄ μ§μ ν νμ μλ€.
`apiVersion: batch/v1 kind: Job metadata: name: sample-job spec: completions: 1 parallelism: 1 backoffLimit: 10 template: spec: containers: - name: sleep-container image: centos:latest command: ["sleep"] args: ["60"] restartPolicy: Never `
Job μμ±
`$ kubectl apply -f job_sample.yml `
Job νμΈ
`$ kubectl get jobs $ kubectl get pods `
**restartPolicy**
spec.template.spec.restartPolicy μλ OnFailure or Never μ§μ κ°λ₯
Never : μ₯μ μ μ κ· Pod μμ±
OnFailure : μ₯μ μ λμΌ Pod μ΄μ©νμ¬ Job μ¬κ° (restart count κ° μ¬λΌκ°λ€)
Parallel Job & work queue
completions : μ€ν νμ
parallelism : λ³λ ¬μ
backoffLimit : μ€ν¨ νμ© νμ. λ―Έμ§μ μ 6
1κ°μ© work queue ννλ‘ μ€νν κ²½μ° completions λ₯Ό λ―Έμ§μ
parallelismλ§ μ§μ νλ©΄ Persistent νκ² Jobμ κ³μ μ€ν
deployment λ±κ³Ό λμΌνκ² kubectl scale jobβ¦ λͺ λ ΉμΌλ‘ λμ€μ μ μ΄ νλ κ²λ κ°λ₯
CronJob
ScheduledJob -> CronJob μΌλ‘ λͺ μΉ λ³κ²½λ¨
Cron μ²λΌ scheduling λ μκ°μ Job μ μμ±
create CronJob
cronjob_sample.yml : 60μ΄ λ§λ€ 30μ΄ sleep
`apiVersion: batch/v1beta1 kind: CronJob metadata: name: sample-cronjob spec: schedule: "*/1 * * * *" concurrencyPolicy: Forbid startingDeadlineSeconds: 30 successfulJobHistoryLimit: 5 failedJobsHistoryLimit: 5 jobTemplate: spec: template: spec: containers: - name: sleep-container image: centos:latest command: ["sleep"] args: ["30"] restartPolicy: Never `
create
`$ kubectl apply -f cronjob_sample.yml `
λ³λ μ€μ μμ΄ kubectl run βschedule λ‘ create κ°λ₯
`$ kubectl run sample-cronjob --schedule = "*/1 * * *" --restart Never --image centos:latest -- sleep 30 `
νμΈ
`$ kubectl get cronjob $ kubectl get job `
**μΌμ μ μ§**
spec.suspend κ° true λ‘ μ€μ λμ΄ μμΌλ©΄ schedule λμμμ μ μΈλ¨
YAML μ λ³κ²½ν ν kubectl apply
kubectl patch λͺ λ Ήμ΄λ‘λ κ°λ₯
`$ kubectl patch cronjob sample-cronjob -p '{"spec":{"suspend":true}}' `
kubectl patchμμλ λ΄λΆμ μΌλ‘ HTTP PATCH method λ₯Ό μ¬μ©νμ¬ Kubernetes λ μμ μΈ Strategic Merge Patch κ° μνλλ€.
μ€μ λ‘ μνλλ request λ₯Ό νμΈνκ³ μΆμΌλ©΄ -v (Verbose) μ΅μ μ¬μ©
`$ kubectl -v=10 patch cronjob sample-cronjob -p '{"spec":{"suspend":true}}' `
kubectl get cronjob μμ SUSPEND νλͺ©μ΄ True λ‘ λ κ²μ νμΈ
λ€μ scheduling λμμ λ£κ³ μΆμΌλ©΄ spec.suspend λ₯Ό false λ‘ μ€μ
λμ μ€ν μ μ΄
spec.concurrencyPolicy
spec.startingDeadlineSeconds : Kubernetes Master κ° μΌμμ μΌλ‘ λμ λΆκ°ν κ²½μ° λ± Job κ°μ μκ°μ΄ λ¦μ΄μ‘μ λ Job μ κ°μ νμ©ν μ μλ μκ°(μ΄)λ₯Ό μ§μ
spec.successfulJobsHistoryLimit : 보쑴νλ μ±κ³΅ Job μ.
spec.failedJobsHistoryLimit : 보쑴νλ μ€ν¨ Job μ.
Allow (default) : λμ μ€νκ³Ό κ΄λ ¨ μ μ΄ νμ§ μμ
Forbid : μ΄μ Job μ΄ μ’ λ£λμ§ μμμΌλ©΄ μλ‘μ΄ Job μ μ€ννμ§ μμ.
Replace : μ΄μ Job μ μ·¨μνκ³ μλ‘μ΄ Job μ μ€ν
300 μ κ²½μ°, μ§μ λ μκ° λ³΄λ€ 5λΆ λ¦μ΄λ μ€ν κ°λ₯
κΈ°λ³ΈμΌλ‘ λ¦μ΄μ§ μκ°κ³Ό κ΄κ³μμ΄ Job μμ± κ°λ₯
default 3.
0 μ λ°λ‘ μμ .
default 3.
0 μ λ°λ‘ μμ
Discovery & LB resource
cluster μμ container μ μ κ·Όν μ μλ endpoint μ 곡과 label μ΄ μΌμΉνλ container λ₯Ό μ°Ύμ μ μκ² ν΄μ€
2 μ’ λ₯κ° μ‘΄μ¬
Service : Endpoint μ μ 곡방λ²μ΄ λ€λ₯Έ type μ΄ λͺκ°μ§ μ‘΄μ¬
Ingress
ClusterIP
NodePort
LoadBalancer
ExternalIP
ExternalName
Headless (None)
Cluster λ΄ Network μ Service
Kubernetes μμ cluster λ₯Ό ꡬμΆνλ©΄ Pod μ μν Internal λ€νΈμν¬κ° ꡬμ±λλ€.
Internal Network μ ꡬμ±μ CNI (Common Network Interface) λΌλ pluggable ν module μ λ°λΌ λ€λ₯΄μ§λ§, κΈ°λ³Έμ μΌλ‘λ Node λ³λ‘ μμ΄ν network segment λ₯Ό κ°μ§κ² λκ³ , Node κ°μ traffic μ VXLAN μ΄λ L2 Routing μ μ΄μ©νμ¬ μ μ‘λλ€.
Kubernetes cluster μ ν λΉλ Internal network segment λ μλμ μΌλ‘ λΆν λμ΄ node λ³λ‘ network segment λ₯Ό ν λΉνκΈ° λλ¬Έμ μμν νμ μμ΄ κ³΅ν΅μ internal network λ₯Ό μ΄μ© κ°λ₯νλ€.
μ΄λ¬ν νΉμ§μΌλ‘ κΈ°λ³Έμ μΌλ‘ container κ° ν΅μ μ΄ κ°λ₯νμ§λ§ Service κΈ°λ₯μ μ΄μ©ν¨μΌλ‘μ¨ μ»μ μ μλ μ΄μ μ΄ μλ€.
Pod μ λ°μνλ traffic μ load balancing
Service discovery & internal dns
μ 2κ°μ§ μ΄μ μ λͺ¨λ Service Type μμ μ΄μ© κ°λ₯
Pod Traffic μ load balancing
Service λ μμ ν trafficμ 볡μμ Pod μ load balancing νλ κΈ°λ₯μ μ 곡
Endpoint μ μ’ λ₯μλ cluster λ΄λΆμμ μ΄μ© κ°λ₯ν VIP (Virtual IP Address) μ μΈλΆμ load balancer μ VIP λ± λ€μν μ’ λ₯κ° μ 곡λλ€
example) deployment_sample.yml
Deployment λ‘ λ³΅μ Pod μ΄ μμ±λλ©΄ μ κ°κ° λ€λ₯Έ IP Address λ₯Ό κ°μ§κ² λλλ° μ΄λλ‘λ λΆνλΆμ°μ μ΄μ©ν μ μμ§λ§ Service κ° λ³΅μμ Pod μ λμμΌλ‘ load balancing κ°λ₯ν endpoint λ₯Ό μ 곡νλ€.
`apiVersion: apps/v1 kind: Deployment metadata: name: sample-deployment spec: replicas: 3 selector: matchLabels: app: sample-app template: metadata: labels: app: sample-app spec: containers: - name: nginx-container image: nginx:1.12 ports: - containerPort: 80 `
`$ kubectl apply -f deployment_sample.yml `
Deployment λ‘ μμ±λ Pod μ label κ³Ό pod-template-hash λΌλ²¨μ μ¬μ©νλ€.
`$ kubectl get pods sample-deployment-5d.. -o jsonpath='{.metadata.labels}' map[app:sample-app pod-template-hash:...]% `
μ μ‘ν Pod μ spec.selector λ₯Ό μ¬μ©νμ¬ μ€μ (clusterip_sample.yml)
`apiVersion: v1 kind: Service metadata: name: sample-clusterip spec: type: ClusterIP ports: - name: "http-port" protocol: "TCP" port: 8080 targetPort: 80 selector: app: sample-app `
`$ kubectl apply -f clusterip_sample.yml `
Service λ₯Ό λ§λ€λ©΄ μμΈμ 보μ Endpoint λΆλΆμ 볡μμ IP Address μ Port κ° νμλλ€. μ΄λ selector μ μ§μ λ 쑰건μ λ§€μΉλ Pod μ IP Address μ Port.
`$ kubectl describe svc sample-clusterip `
Pod μ IP λ₯Ό λΉκ΅νκΈ° μν΄ νΉμ JSON path λ₯Ό column μΌλ‘ μΆλ ₯
`$ kubectl get pods -l app=sample-app -o custom-columns="NAME:{metadata.name},IP:{status.podIP}" `
load balancing νμΈμ μ½κ² μν΄ ν μ€νΈλ‘ κ° pod μμ index.html μ λ³κ²½.
Pod μ μ΄λ¦μ νλνκ³ κ°κ°μ pod μ hostname μ νλν κ²μ index.html μ κΈ°λ‘
`for PODNAME in `kubectl get pods -l app=sample-app -o jsonpath='{.items[*].metadata.name}'`; do kubectl exec -it ${PODNAME} -- sh -c "hostname > /usr/share/nginx/html/index.html"; done `
μΌμμ μΌλ‘ Pod μ κΈ°λνμ¬ Service μ endpoint λ‘ request
`$ kubectl run --image=centos:7 --restart=Never --rm -i testpod -- curl -s http://[load balancer ip]:[port] `
**Service Discovery μ Internal DNS**
Service Discovery
Service Discovery λ°©λ²
Service κ° μ 곡
νΉμ 쑰건μ λμμ΄ λλ member λ₯Ό μ΄κ±°νκ±°λ, μ΄λ¦μΌλ‘ endpoint λ₯Ό νλ³
Service μ μνλ Pod μ μ΄κ±°νκ±°λ Service μ΄λ¦μΌλ‘ endpoint μ 보λ₯Ό λ°ν
A record λ₯Ό μ΄μ©
SRV record λ₯Ό μ΄μ©
νκ²½λ³μλ₯Ό μ΄μ©
A record λ₯Ό μ΄μ©ν Service Discovery
Service λ₯Ό λ§λ€λ©΄ DNS record κ° μλμ μΌλ‘ λ±λ‘λλ€
λ΄λΆμ μΌλ‘λ kube-dns λΌλ system componentκ° endpoint λ₯Ό λμμΌλ‘ DNS recordλ₯Ό μμ±
Service λ₯Ό μ΄μ©νμ¬ DNS λͺ μ μ¬μ©ν μ μμΌλ©΄ IP Address κ΄λ ¨ν κ΄λ¦¬λ μ€μ μ μ κ²½μ°μ§ μμλ λκΈ° λλ¬Έμ μ΄λ₯Ό μ¬μ©νλ κ²μ΄ νΈλ¦¬
`# IP λμ μ sample-clusterip λΌλ Service λͺ μ μ΄μ© κ°λ₯ $ kubectl run --image=centos:7 --restart=Never --rm -i testpod -- curl -s http://sample-clusterip:8080 `
μ€μ λ‘ kube-dns μ λ±λ‘λλ μ μ FQDN μ [Service name].[Namespace name].svc.[ClusterDomain name]
`# container λ΄λΆμμ sample-clusterip.default.svc.cluster.local λ₯Ό μ‘°ν $ kubectl run --image=centos:6 --restart=Never --rm -i testpod -- dig sample-clusterip.default.svc.cluster.local `
FQDN μμλ Service μΆ©λμ λ°©μ§νκΈ° μν΄ Namespace λ±μ΄ ν¬ν¨λμ΄ μμΌλ container λ΄λΆμ /etc/resolv.conf μ κ°λ΅ν domain μ΄ μ§μ λμ΄ μμ΄ μ€μ λ‘λ sample-clusterip.default λ sample-clusterip λ§μΌλ‘λ μ‘°νκ° κ°λ₯νλ€.
IP λ‘λ FQDN μ λ°λλ‘ μ‘°ννλ κ²λ κ°λ₯
`$ kubectl run --image=centos:6 --restart=Never --rm -i testpod -- dig -x 10.11.245.11 `
**SRV record λ₯Ό μ΄μ©ν Service Discovery**
[_Service Port name].[_Protocol].[Service name].[Namespace name].svc.[ClusterDomain name]μ νμμΌλ‘λ νμΈ κ°λ₯
`$ kubectl run --image=centos:6 --restart=Never --rm -i testpod -- dig _http-port._tcp.sample-clusterip.default.svc.cluster.local SRV `
**νκ²½λ³μλ₯Ό μ΄μ©ν Service Discovery**
Pod λ΄λΆμμλ νκ²½λ³μλ‘λ κ°μ Namespace μ μλΉμ€κ° νμΈ κ°λ₯νλλ‘ λμ΄ μλ€.
β-β κ° ν¬ν¨λ μλΉμ€ μ΄λ¦μ β_β λ‘, κ·Έλ¦¬κ³ λλ¬Έμλ‘ λ³νλλ€.
docker --links ...μ κ°μ νμμΌλ‘ νκ²½λ³μκ° λ³΄μ‘΄
container κΈ°λ νμ Service μΆκ°λ μμ μ λ°λΌ νκ²½λ³μκ° κ°±μ λλ κ²μ μλλΌμ μμ λͺ»ν μ¬κ³ κ° λ°μν κ°λ₯μ±λ μλ€.
Service λ³΄λ€ Pod μ΄ λ¨Όμ μμ±λ κ²½μ°μλ νκ²½λ³μκ° λ±λ‘λμ΄ μμ§ μκΈ°μ Pod μ μ¬μμ±ν΄μΌ νλ€.
Docker λ§μΌλ‘ μ΄μ©νλ νκ²½μμ μ΄μν λμλ νΈλ¦¬
`$ kubectl exec -it sample-deployment-... env | grep -i sample_clusterip `
**볡μ port λ₯Ό μ¬μ©νλ Service μ Service Discovery**
clusterip_multi_sample.yml
`apiVersion: v1 kind: Service metadata: name: sample-clusterip spec: type: ClusterIP ports: - name: "http-port" protocol: "TCP" port: 8080 targetPort: 80 - name: "https-port" protocol: "TCP" port: 8443 targetPort: 443 selector: app: sample-app `
## ClusterIP
κ°μ₯ κΈ°λ³Έ
Kubernetes cluster λ΄λΆμμλ§ μ κ·Ό κ°λ₯ν Internal Network μ VIP κ° ν λΉλλ€
ClusterIP λ‘μ ν΅μ μ node μμμ λμνλ system component μΈ kube-proxyκ° Podμ λμμΌλ‘ μ μ‘νλ€. (Proxy-mode μ λ°λΌ μμ΄)
Kubernetes cluster μΈλΆμμμ μ κ·Όμ΄ νμμλ κ³³μ μ΄μ©νλ€
κΈ°λ³ΈμΌλ‘λ Kubernetes API μ μ μνκΈ° μν Service κ° λ§λ€μ΄μ Έ μκ³ ClusterIP κ° λ₯Ό μ¬μ©νλ€.
`# TYPE μ ClusterIP νμΈ $ kubectl get svc `
**create ClusterIP Service**
clusterip_sample.yml
`apiVersion: v1 kind: Service metadata: name: sample-clusterip spec: type: ClusterIP ports: - name: "http-port" protocol: "TCP" port: 8080 targetPort: 80 selector: app: sample-app `
type: ClusterIP μ§μ
spec.ports[x].port μλ ClusterIPλ‘ μμ νλ Port λ²νΈ
spec.ports[x].targetPort λ μ λ¬ν container μ Port λ²νΈ
Static ClusterIP VIP μ§μ
database λ₯Ό μ΄μ©νλ λ± κΈ°λ³Έμ μΌλ‘λ Kubernetes Serviceμ λ±λ‘λ λ΄λΆ DNS recordλ₯Ό μ΄μ©νμ¬ host μ§μ νλ κ²μ μΆμ²
μλμΌλ‘ μ§μ ν κ²½μ° spec.clusterIPλ₯Ό μ§μ (clusterip_vip_sample.yml)
`apiVersion: v1 kind: Service metadata: name: sample-clusterip spec: type: ClusterIP clusterIP: 10.11.111.11 ports: - name: "http-port" protocol: "TCP" port: 8080 targetPort: 80 selector: app: sample-app `
μ΄λ―Έ ClusterIP Serviceκ° μμ±λμ΄ μλ μνμμλ ClusterIP λ₯Ό λ³κ²½ν μ μλ€.
kubectl apply λ‘λ λΆκ°λ₯
λ¨Όμ μμ±λ Service λ₯Ό μμ ν΄μΌ νλ€.
ExternalIP
νΉμ Kubernetes Node μ IP:Port λ‘ μμ ν traffic μ container λ‘ μ λ¬νλ λ°©μμΌλ‘ μΈλΆμ μ°κ²°
create ExternalIP Service
externalip_sample.yml
`apiVersion: v1 kind: Service metadata: name: sample-externalip spec: type: ClusterIP externalIPs: - 10.1.0.7 - 10.1.0.8 ports: - name: "http-port" protocol: "TCP" port: 8080 targetPort: 80 selector: app: sample-app `
type: ExternalIP κ° μλ type: ClusterIP μΈ κ²μ μ£Όμ
spec.ports[x].port λ ClusterIP λ‘ μμ νλ Port
spec.ports[x].targetPort λ μ λ¬ν container μ Port
λͺ¨λ Kubernetes Node λ₯Ό μ§μ ν νμλ μμ
ExternalIP μ μ΄μ© κ°λ₯ν IP Address λ node μ 보μμ νμΈ
GKE λ OS μμμλ global IP Addressκ° μΈμλμ΄ μμ§ μμμ μ΄μ© λΆκ°
`# IP address νμΈ $ kubectl get node -o custom-columns="NAME:{metadata.name},IP:{status.addresses[].address}" `
ExternalIP Service λ₯Ό μμ±ν΄λ container λ΄λΆμμ μ¬μ©ν ClusterIP λ μλμ μΌλ‘ ν λΉλλ€.
container μμμ DNSλ‘ ExternalIP Service νμΈ
`$ kubectl run --image=centos:6 --restart=Never --rm -i testpod -- dig sample-externalip.default.svc.cluster.local `
ExternalIP λ₯Ό μ΄μ©νλ node μ port μν
`$ ss -napt | grep 8080 `
ExternalIP λ₯Ό μ¬μ©νλ©΄ Kubernetes cluster λ°μμλ μ κ·Όμ΄ κ°λ₯νκ³ λν Pod μ λΆμ°λλ€.
NodePort
λͺ¨λ Kubernetes Node μ IP:Port μμ μμ ν traffic μ container μ μ μ‘
ExternalIP Service μ λͺ¨λ Node λ²μ λΉμ·ν λλ
Docker Swarm μ Service λ₯Ό Expose ν κ²½μ°μ λΉμ·
create NodePort Service
nodeport_sample.yml
`apiVersion: v1 kind: Service metadata: name: sample-nodeport spec: type: NodePort ports: - name: "http-port" protocol: "TCP" port: 8080 targetPort: 80 nodePort: 30080 selector: app: sample-app `
spec.ports[x].port λ ClusterIP λ‘ μμ νλ Port
spec.ports[x].targetPort λ μ λ¬ν container Port
spec.ports[x].nodePort λ λͺ¨λ Kubernetes Node μμ μμ ν Port
container μμμ ν΅μ μ μ¬μ©ν ClusterIP λ μλμ μΌλ‘ ν λΉλλ€
μ§μ νμ§ μμΌλ©΄ μλμΌλ‘ λΉμ΄μλ λ²νΈλ₯Ό μ¬μ©
Kubernetes κΈ°λ³ΈμΌλ‘λ μ΄μ©ν μ μλ λ²νΈκ° 30000~32767
볡μμ NodePort κ° λμΌ Port μ¬μ© λΆκ°
Kubernetes Master μ€μ μμ λ³κ²½ κ°λ₯
`$ kubectl get svc `
container μμμ νμΈνλ©΄ λ΄λΆ DNS κ° λ°ννλ IP Address λ External IP κ° μλ Cluster IP
`$ kubectl run --image=centos:6 --restart=Never --rm -i testpod -- dig sample-nodeport.default.svc.cluster.local `
Kubernetes Node μμμ Port μνλ₯Ό νμΈνλ©΄ nodePort μ μ§μ ν κ°μΌλ‘ Listen
`$ ss -napt | grep 30080 `
ExternalIP μ λ€λ₯΄κ² λͺ¨λ Node μ IP Address λ‘ Kubernetes Cluster μΈλΆμμ μ κ·Ό κ°λ₯νλ©° Pod μΌλ‘μ request λ λΆμ°λλ€.
GKE λ GCEμ ν λΉλ global IP Address λ‘ μ κ·Ό κ°λ₯
Node κ° ν΅μ μ λ°°μ (Node λ₯Ό 건λ load balancing λ°°μ )
NodePort μμλ Node μμ NodePort μ λλ¬ν packet μ Node λ₯Ό 건λμλ load balancing μ΄ μ΄λ£¨μ΄μ§λ€
DaemonSet λ±μ μ¬μ©νλ©΄ κ° Nodeμ 1 Pod μ΄ μ‘΄μ¬νκΈ°μ κ°μ Node μμ Pod μλ§ μ λ¬νκ³ μΆμ λ μ¬μ©
spec.externalTrafficPolicy λ₯Ό μ¬μ©νμ¬ μ€ν κ°λ₯
externalTrafficPolicy λ₯Ό Cluster μμ Local λ‘ λ³κ²½νκΈ° μν΄μ YAML μ΄μ© (nodeport_local_sample.yml)
Cluster (Default)
Local
Node μ λλ¬ν ν κ° Node μ load balancing
μ€μ λ‘λ kube-proxy μ€μ μΌλ‘ iptables μ proxy modeλ₯Ό μ¬μ©ν κ²½μ°, μμ μ Node μ μ’ λ λ§μ΄ μ λ¬λλλ‘ λλ κ²μΌλ‘ 보μ¬μ§ (iptables-save λ±μΌλ‘ statistics λΆλΆμ νμΈ)
λλ¬ν Node μ μν Pod μ μ λ¬ (no load balancing)
λ§μ½ Pod μ΄ μ‘΄μ¬νμ§ μμΌλ©΄ Response λΆκ°
λ§μΌ Pod μ΄ λ³΅μ μ‘΄μ¬νλ€λ©΄ κ· λ±νκ² λΆλ°°
`apiVersion: v1 kind: Service metadata: name: sample-nodeport-local spec: type: NodePort externalTrafficPolicy: Local ports: - name: "http-port" protocol: "TCP" port: 8080 targetPort: 80 nodePort: 30081 selector: app: sample-app `
## LoadBalancer
κ°μ₯ μ¬μ©μ±μ΄ μ’κ³ μ€μ©μ
Kubernetes Cluster μΈλΆμ LoadBalancer μ VIP λ₯Ό ν λΉ κ°λ₯
NodePort λ±μμ κ²°κ΅ Node μ ν λΉλ IP Address μ endpoint μν κΉμ§ λ΄λΉμν€λ κ²μ΄λΌ SPoF (Single Point of Failure) λ‘ Node μ₯μ μ μ½νλ€
μΈλΆμ load balancer λ₯Ό μ΄μ©νλ κ²μΌλ‘ Kubernetes Node μ₯μ μ κ°νλ€
λ¨ μΈλΆ LoadBalancer μ μ°κ³ κ°λ₯ν νκ²½μΌλ‘ GCP, AWS, Azure, OpenStack λ±μ CloudProvider μ νμ λλ€ (μ΄λ μΆνμ μ μ°¨ νλλ μ μλ€)
NodePort Service λ₯Ό λ§λ€μ΄μ Cluster μΈλΆμ Load Balancer μμ Kubernetes Node μ balancing νλ€λ λλ
create LoadBalancer Service
lb_sample.yml
`apiVersion: v1 kind: Service metadata: name: sample-lb spec: type: LoadBalancer ports: - name: "http-port" protocol: "TCP" port: 8080 targetPort: 80 nodePort: 30082 selector: app: sample-app `
spec.ports[x].port λ LoadBalancer VIP μ ClusterIP λ‘ μμ νλ Port
spec.ports[x].targetPort λ μ λ¬ν container Port
NodePort λ μλμ μΌλ‘ ν λΉλ¨μΌλ‘ spec.ports[x].nodePort μ μ§μ λ κ°λ₯
νμΈ
`$ kubectl get svc sample-lb `
EXTERNAL-IP κ° pending μνμΈ κ²½μ° LoadBalancer κ° μ€λΉλλλ° μκ°μ΄ νμν κ²½μ°
Container λ΄λΆ ν΅μ μλ Cluster IP λ₯Ό μ¬μ©νκΈ°μ ClusterIP λ μλν λΉ
NodePort λ μμ±
VIP λ Kubernetes Node μ λΆμ°λκΈ° λλ¬Έμ Kubernetes Node μ scaling μ λ³κ²½ν κ²μ΄ μλ€
Node κ° ν΅μ λ°°μ (Node λ₯Ό 건λ load balancing λ°°μ )
NodePort μ λμΌνκ² externalTrafficPolicy λ₯Ό μ΄μ© κ°λ₯
LoadBalancer VIP μ§μ
spec.LoadBalancerIP λ‘ μΈλΆμ LoadBalancer IP Address μ§μ κ°λ₯
`# lb_fixip_sample.yml apiVersion: v1 kind: Service metadata: name: sample-lb-fixip spec: type: LoadBalancer loadBalancerIP: xxx.xxx.xxx.xxx ports: - name: "http-port" protocol: "TCP" port: 8080 targetPort: 80 nodePort: 30083 selector: app: sample-app `
λ―Έμ§μ μ μλ ν λΉ
GKE λ±μ cloud provider μ κ²½μ° μ£Όμ
GKE μμλ LoadBalancer service λ₯Ό μμ±νλ©΄ GCLB κ° μμ±λλ€.
GCP LoadBalancer λ±μΌλ‘ λΉμ©μ΄ μ¦κ° λμ§ μλλ‘ μ£Όμ
IP Address μ€λ³΅μ΄ νμ©λκ±°λ deploy flow μ λ¬Έμ κ° μμΌλ©΄ κ°κΈμ Service λ₯Ό μ 리ν κ²
Service λ₯Ό λ§λ μνμμ GKE cluster λ₯Ό μμ νλ©΄ GCLB κ° κ³ΌκΈ λλ μνλ‘ λ¨μλ²λ¦¬λ―λ‘ μ£Όμ
Headless Service
Pod μ IP Address κ° λ°νλλ Service
λ³΄ν΅ Pod μ IP Address λ μμ£Ό λ³λλ μ μκΈ° λλ¬Έμ Persistent ν StatefulSet νμ νμ¬ μ¬μ© κ°λ₯
IP endpoint λ₯Ό μ 곡νλ κ²μ΄ μλ DNS Round Robin (DNS RR) μ μ¬μ©ν endpoint μ 곡
DNS RR μ μ λ¬ν Pod μ IP Address κ° cluster μμ DNS μμ λ°νλλ ννλ‘ λΆνλΆμ°μ΄ μ΄λ£¨μ΄μ§κΈ°μ client μͺ½ cache μ μ£Όμν νμκ° μλ€.
κΈ°λ³Έμ μΌλ‘ Kubernetes λ Pod μ IP Address λ₯Ό μμν νμκ° μλλ‘ λμ΄ μμ΄μ Pod μ IP Address λ₯Ό discovery νκΈ° μν΄μλ API λ₯Ό μ¬μ©ν΄μΌλ§ νλ€
Headless Service λ₯Ό μ΄μ©νμ¬ StatefulSet νμ μΌλ‘ Service κ²½μ λ‘ IP Address λ₯Ό discovery νλ κ²μ΄ κ°λ₯νλ€
create Headless Service
3κ°μ§ μ‘°κ±΄μ΄ μΆ©μ‘±λμ΄μΌ νλ€
Service μ spec.type μ΄ ClusterIP
Service μ metadata.name μ΄ StatefulSet μ spec.serviceName κ³Ό κ°μ κ²
Service μ spec.clusterIP κ° None μΌκ²
μ 쑰건λ€μ΄ μΆ©μ‘±λμ§ μμΌλ©΄ κ·Έλ₯ Service λ‘λ§ λμνκ³ Pod μ΄λ¦μ μ»λ λ±μ΄ λΆκ°λ₯νλ€.
`# headless_sample.yml apiVersion: v1 kind: Service metadata: name: sample-svc spec: type: ClusterIP clusterIP: None ports: - name: "http-port" protocol: "TCP" port: 80 targetPort: 80 selector: app: sample-app `
**Headless Service λ₯Ό μ΄μ©ν Pod μ΄λ¦ μ‘°ν**
λ³΄ν΅ Service λ₯Ό λ§λ€λ©΄ 볡μ Pod μ λμνλ endpoint κ° λ§λ€μ΄μ Έ ν΄λΉ endpoint. μ λμνμ¬ μ΄λ¦μ μ‘°ννλ κ²μ΄ κ°λ₯νμ§λ§ κ°κ°μ Pod μ μ΄λ¦ μ‘°νλ λΆκ°λ₯νλ€
λ³΄ν΅ Service μ μ΄λ¦ μ‘°νλ [Service name].[Namespace name].svc.[domain name] λ‘ μ‘°νκ° κ°λ₯νλλ‘ λμ΄ μμ§λ§ Headless Service λ‘ κ·Έλλ‘ μ‘°ννλ©΄ DNS Round Robin μΌλ‘ Pod μ€μ IP κ° λ°νλκΈ°μ λΆν λΆμ°μλ μ ν©νμ§ μλ€
StatefulSet μ κ²½μ°μλ§, [Pod name].[Service name].[Namespace name].svc.[domain name] νμμΌλ‘ Pod μ΄λ¦ μ‘°νκ° κ°λ₯νλ€
container μ resolv.conf λ±μ search λ‘ entry κ° λ€μ΄κ° μλ€λ©΄ [Pod name].[Service name] νΉμ [Pod name].[Service name].[Namespace] λ±μΌλ‘ μ‘°ν κ°λ₯
ReplicaSet λ±μ Resource μμλ κ°λ₯
ExternalName
λ€λ₯Έ Service λ€κ³Ό λ€λ₯΄κ² Service μ΄λ¦ μ‘°νμ λμνμ¬ CNAME μ λ°ννλ Service
μ£Όλ‘ λ€λ₯Έ μ΄λ¦μ μ€μ νκ³ μΆκ±°λ cluster μμμ endpoint λ₯Ό μ ννκΈ° μ½κ² νκ³ μΆμ λ μ¬μ©
create ExternalName service
`# externalname_sample.yml apiVersion: v1 kind: Service metadata: name: sample-externalname namespace: default spec: type: ExternalName externalName: external.example.com `
`$ kubectl get svc `
EXTERNAL-IP λΆλΆμ CNAME μ©μ DNS κ° νμλλ€
container λ΄λΆμμ [Service name] μ΄λ [Service name].[Namespace name].svc.[domain name] μΌλ‘ μ‘°ννλ©΄ CNAME κ° λμμ€λ κ²μ νμΈ κ°λ₯
`$ dig sample-externalname.default.svc.cluster.local CNAME `
**Loosely Coupled with External Service**
Cluster λ΄λΆμμλ Pod λ‘μ ν΅μ μ Service μ΄λ¦ μ‘°νλ₯Ό μ¬μ©νλ κ²μΌλ‘ μλΉμ€ κ°μ Loosely Coupled λ₯Ό κ°μ§λ κ²μ΄ κ°λ₯νμ§λ§, SaaS λ IaaS λ±μ μΈλΆ μλΉμ€λ₯Ό μ΄μ©νλ κ²½μ°μλ νμκ° μλ€.
Application λ±μμ μΈλΆ endpointλ₯Ό μ€μ νλ©΄ μ νν λ Application μͺ½ μ€μ λ³κ²½μ΄ νμν΄μ§λλ° ExternalNameμ μ΄μ©νμ¬ DNS μ μ νμ ExternalName Service μ λ³κ²½λ§μΌλ‘ κ°λ₯νμ¬ Kubernetes μμμ κ°λ₯ν΄μ§κ³ μΈλΆμ Kubernetes Cluster μ¬μ΄μ Loosely Coupled μνλ μ μ§ κ°λ₯νλ€.
μΈλΆ μλΉμ€μ λ΄λΆ μλΉμ€ κ°μ μ ν
ExternalName μ΄μ©μΌλ‘ μΈλΆ μλΉμ€μμ Loosely Coupled ν보νκ³ μΈλΆ μλΉμ€μ Kubernetes μμ Cluster λ΄λΆ μλΉμ€μ μ νλ μ μ°νκ² κ°λ₯νλ€
Ingress
L7 LoadBalancer λ₯Ό μ 곡νλ Resource
Kubernetes μ Network Policy resource μ Ingress/Egress μ€μ νλͺ©κ³Ό κ΄λ ¨ μμ
Ingress μ’ λ₯
μμ§ Beta Service μΌ κ°λ₯μ±
ν¬κ² ꡬλΆνμ¬ 2κ°μ§
Cluster μΈλΆμ Load Balancerλ₯Ό μ΄μ©ν Ingress
Cluster λ΄λΆμ Ingress μ©μ Pod μ μμ±νμ¬ μ΄μ©νλ Ingress
GKE
Nginx Ingress
Nghttpx Ingress
Cluster μΈλΆμ Load Balancer λ₯Ό μ΄μ©ν Ingress
GKE κ°μ Cluster μΈλΆμ Load Balancerλ₯Ό μ΄μ©ν Ingress μ κ²½μ°, Ingress rosource λ₯Ό λ§λλ κ²λ§μΌλ‘ LoadBalancer μ VIP κ° λ§λ€μ΄μ Έ μ΄μ©νλ κ²μ΄ κ°λ₯
GCPμ GCLB (Google Cloud Load Balancer) μμ μμ ν trafficμ GCLB μμ HTTPS μ’ λ¨μ΄λ path base routing λ±μ μννμ¬ NodePortμ trafficμ μ μ‘νλ κ²μΌλ‘ λμ Pod μ λλ¬
Cluster λ΄λΆμ Ingress μ©μ Pod μ μμ±νμ¬ μ΄μ©νλ Ingress
L7 μν μ ν Podμ Cluster λ΄λΆμ μμ±νλ ννλ‘ μ€ν
Cluster μΈλΆμμ μ κ·Ό κ°λ₯νλλ‘ λ³λ Ingress μ© Podμ LoadBalancer Serviceλ₯Ό μμ±νλ λ±μ μ€λΉκ° νμνλ€
Ingress μ©μ Pod μ΄ HTTPS μ’ λ¨μ΄λ path base routing λ±μ L7 μν μ νκΈ° μν΄ Pod μ replica μμ auto scale λ±λ κ³ λ €ν νμκ° μλ€.
LBμ μΌλ¨ Nginx Pod μ μ μ‘νμ¬ Nginx κ° L7 μν μ νμ¬ μ²λ¦¬ν ν λμ Pod μ μ μ‘νλ€.
NodePort κ²½μ νμ§ μκ³ μ§μ Pod IP λ‘ μ μ‘
create Ingress resource
μ¬μ μ€λΉκ° νμ
μ¬μ μ λ§λ€μ΄μ§ Serviceλ₯Ό Back-endλ‘μ νμ©νμ¬ μ μ‘μ νλ νν
Back-end λ‘ μ΄μ©ν Service λ NodePort λ₯Ό μ§μ
`# sample-ingress-apps apiVersion: apps/v1 kind: Deployment metadata: name: sample-ingress-apps spec: replicas: 1 selector: matchLabels: ingress-app: sample template: metadata: labels: ingress-app: sample spec: containers: - name: nginx-container image: zembutsu/docker-sample-nginx:1.0 ports: - containerPort: 80 `
`# ingress service sample apiVersion: v1 kind: Service metadata: name: svc1 spec: type: NodePort ports: - name: "http-port" protocol: "TCP" port: 8888 targetPort: 80 selector: ingress-app: sample `
Ingress λ‘ HTTPS λ₯Ό μ΄μ©νλ κ²½μ°μλ μΈμ¦μλ μ¬μ μ Secret μΌλ‘ λ±λ‘ν΄λ νμκ° μλ€.
Secret μ μΈμ¦μμ μ 보λ₯Ό λ°νμΌλ‘ YAML νμΌμ μ§μ λ§λ€κ±°λ μΈμ¦μ νμΌμ μ§μ νμ¬ λ§λ λ€.
`# μΈμ¦μ μμ± $ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /tmp/tls.key -out /tmp/tls.crt -subj "/CN=sample.example.com" # Secret μμ± (μΈμ¦μ νμΌμ μ§μ νλ κ²½μ°) $ kubectl create secret tls tls-sample --key /tmp/tls.key --cert /tmp/tls.crt `
Ingress resource λ L7 Load Balancer μ΄κΈ°μ νΉμ host λͺ μ λν΄ request path > Service back-end μ pair λ‘ μ μ‘ rule μ μ€μ νλ€.
νλμ IP Address λ‘ λ³΅μμ Host λͺ μ κ°μ§λ κ²μ΄ κ°λ₯νλ€.
spec.rules[].http.paths[].backend.servicePort μ μ€μ νλ Port λ Service μ spec.ports[].port λ₯Ό μ§μ
`# ingress_sample.yml apiVersion: extensions/v1beta1 kind: Ingress metadata: name: sample-ingress annotations: ingress.kubernetes.io/rewrite-target: / spec: rules: - host: sample.example.com http: paths: - path: /path1 backend: serviceName: svc1 servicePort: 8888 backend: serviceName: svc1 servicePort: 8888 tls: - hosts: - sample.example.com secretName: tls-sample `
**Ingress resource & Ingress Controller**
Ingress resource = YAML file μ λ±λ‘λ API resource
Ingress Controller = Ingress resource κ° Kubernetes μ λ±λ‘λμμ λ, μ΄λ ν μ²λ¦¬λ₯Ό μννλ κ²
GCP μ GCLB λ₯Ό μ‘°μνμ¬ L7 LoadBalancer μ€μ μ νλ κ²μ΄λ,
Nginx μ Config λ₯Ό λ³κ²½νμ¬ reload νλ λ±
GKE μ κ²½μ°
GKE μ κ²½μ°, κΈ°λ³ΈμΌλ‘ GKE μ© Ingress Controller κ° deploy λμ΄ μμ΄ λ±ν μμν νμ μμ΄ Ingress resource λ§λ€ μλμΌλ‘ IP endpoint κ° λ§λ€μ΄μ§λ€.
Nginx Ingress μ κ²½μ°
Nginx Ingress λ₯Ό μ΄μ©νλ κ²½μ°μλ Nginx Ingress Controller λ₯Ό μμ±ν΄μΌ νλ€.
Ingress Controller μμ²΄κ° L7 μν μ νλ Pod μ΄ λκΈ°λ νκΈ°μ Controller λΌλ μ΄λ¦μ΄μ§λ§ μ€μ μ²λ¦¬λ μννλ€.
GKE μ κ°μ΄ cluster μΈλΆμμλ μ κ·Όμ νμ©νκΈ° μν΄μλ Nginx Ingress Controller μΌλ‘μ LoadBalancer Service (NodePort λ±λ κ°λ₯) λ₯Ό μμ±ν νμκ° μλ€.
κ°λ³μ μΌλ‘ Service λ₯Ό λ§λλ κ²μ΄κΈ°μ kubectl get ingress λ±μΌλ‘ endpoint IP Address λ₯Ό νμΈ λΆκ° νκΈ°μ μ£Όμκ° νμνλ€.
rule μ λ§€μΉλμ§ μμ κ²½μ°μ default λ‘ μ μ‘ν κ³³μ μμ±ν νμκ° μμΌλ μ£Όμ
μ€μ λ‘λ RBAC, resource μ ν, health check κ°κ²© λ± μΈμΈν μ€μ ν΄ λ¬μΌ ν μ μλ€.
nginx ingress μΆμ² μ€μ
`# Nginx ingressλ₯Ό μ΄μ©νλ YAML sample apiVersion: apps/v1 kind: Deployment metadata: name: default-http-backend labels: app: default-http-backend spec: replicas: 1 selector: matchLabels: app: default-http-backend template: metadata: labels: app: default-http-backend spec: containers: - name: default-http-backend image: gcr.io/google_containers/defaultbackend:1.4 livenessProbe: httpGet: path: /healthz port: 8080 scheme: HTTP ports: - containerPort: 8080 --- apiVersion: v1 kind: Service metadata: name: default-http-backend labels: app: default-http-backend spec: ports: - port: 80 targetPort: 8080 selector: app: default-http-backend --- apiVersion: apps/v1 kind: Deployment metadata: name: nginx-ingress-controller spec: replicas: 1 selector: matchLabels: app: ingress-nginx template: metadata: labels: app: ingress-nginx spec: containers: - name: nginx-ingress-controller image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.14.0 args: - /nginx-ingress-controller - --default-backend-service=$(POD_NAMESPACE)/default-http-backend env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace ports: - name: http containerPort: 80 - name: https containerPort: 443 livenessProbe: httpGet: path: /healthz port: 10254 scheme: HTTP readinessProbe: httpGet: path: /healthz port: 10254 scheme: HTTP --- apiVersion: v1 kind: Service metadata: name: ingress-endpoint labels: app: ingress-nginx spec: type: LoadBalancer ports: - port: 80 targetPort: 8080 selector: app: ingress-nginx `
default back-end pod μ΄λ L7 μ²λ¦¬ν Nginx Ingress Controller Pod μ replica μκ° κ³ μ μ΄λ©΄ traffic μ΄ λμμ λ κ°λΉνμ§ λͺ»ν κ°λ₯μ±λ μμΌλ Pod auto scaling μ μννλ Horizontal Pod Autoscaler (HPA) μ μ΄μ©λ κ²ν ν΄μΌ ν μ μμ
deploy ν Ingress Controller λ cluster μμ λͺ¨λ Ingress resource λ₯Ό λ΄ λ²λ¦¬κΈ°μ μΆ©λν κ°λ₯μ±μ΄ μλ€.
μμΈ μ¬μ
Ingress Class λ₯Ό μ΄μ©νμ¬ μ²λ¦¬νλ λμ Ingress resource λ₯Ό λΆλ¦¬νλ κ²μ΄ κ°λ₯
Ingress resource μ Ingress Class Annotation μ λΆμ¬νμ¬ Nginx Ingress Controller μ λμμΌλ‘ νλ Ingress Classλ₯Ό μ€μ νλ κ²μΌλ‘ λμ λΆλ¦¬ κ°λ₯
Nginx Ingress Controller μ κΈ°λ μ --ingress-class μ΅μ λΆμ¬
Ingress resource Annotation
/nginx-ingress-controller --ingress-class=system_a ...
kubernetes.io/ingress.class: "system_a"
μ 리
Kubernetes Service & Ingress
Service
Ingress
L4 Load Balancing
Cluster λ΄λΆ DNS λ‘ lookup
label μ μ΄μ©ν Pod Service Discovery
L7 Load Balancing
HTTPS μ’ λ¨
path base routing
Kubernetes Service
ClusterIP : Kubernetes Cluster λ΄λΆ νμ μΌλ‘ ν΅μ κ°λ₯ν VIP
ExternalIP : νΉμ Kubernetes Node μ IP
NodePort : λͺ¨λ Kubernetes Node μ λͺ¨λ IP (0.0.0.0)
LoadBalancer : Cluster μΈλΆμ μ 곡λλ Load Balancerμ VIP
ExternalName : CNAME μ μ¬μ©ν Loosely Coupled
Headless : Pod μ IP λ₯Ό μ¬μ©ν DNS Round Robin
Kubernetes Ingress
Cluster μΈλΆμ Load Balancer λ₯Ό μ΄μ©ν Ingress : GKE
Cluster λ΄λΆμ Ingress μ© Pod μ μ΄μ©ν Ingress : Nginx Ingress, Nghttpx Ingress
Kubernetes Config & Storage resource
container μ λν μ€μ νμΌ, μνΈ λ±μ κΈ°λ° μ 보λ Persistent Volume λ±μ κ΄ν resource
3 μ’ λ₯
Secret
ConfigMap
PersistentVolumeClaim
νκ²½λ³μ μ΄μ©
Kubernetes μμλ κ°λ³ containerμ λν μ€μ μ λ΄μ©μ νκ²½λ³μλ νμΌμ΄ ν¬ν¨λ μμμ mount ν΄μ λκΈ°λ κ²μ΄ μΌλ°μ μ΄λ€
νκ²½λ³μλ₯Ό λκΈ°λ €λ©΄ pod template μ env νΉμ envFrom μ μ§μ
5κ°μ μ 보 sourceλ‘λΆν° νκ²½λ³μλ₯Ό μ¬λ κ²μ΄ κ°λ₯
μ μ μ€μ
Pod μ 보
Container μ 보
Secret resource μ κΈ°λ° μ 보
ConfigMap resource μ Key-Value κ°
μ μ μ€μ
spec.containers[].env μ μ μ κ°μ μ μ
`apiVersion: v1 kind: Pod metadata: name: sample-env labels: app: sample-app spec: containers: - name: nginx-container image: nginx:1.12 env: - name: MAX_CONNECTION value: "100" `
Pod μ 보
Pod μ΄ μν Node λ, Pod μ IP Address, κΈ°λμκ° λ±μ Pod μ κ΄λ ¨λ μ 보λ fieldRefλ₯Ό μ¬μ©νμ¬ μ°Έμ‘°ν μ μλ€.
μ°Έμ‘° κ°λ₯ν κ°μ kubectl get pods -o yaml λ±μΌλ‘ νμΈν μ μλ€.
λ±λ‘ν YAML file μ μ 보μ λ³λλ‘ IP, host μ λ λ±λ μΆκ°λμλ€.
`# λμ μ€μΈ Pod μ μ 보 νμΈ $ kubectl get pod nginx-pod -o yaml ... spec: nodeName: gke-k8s-... ... `
`# env-pod-sample.yml # set Kubernetes Node's name to env K8S_NODE apiVersion: v1 kind: Pod metadata: name: sample-env-pod labels: app: sample-app spec: containers: - name: nginx-container image: nginx:1.12 env: - name: K8S_NODE valueFrom: fieldRef: fieldPath: spec.nodeName `
**Container μ 보**
Container μ κ΄λ ¨ν μ 보λ resourceFieldRefλ₯Ό μ¬μ©νμ¬ μ°Έμ‘°ν μ μλ€.
Pod μλ 볡μ container μ μ λ³΄κ° ν¬ν¨λμ΄ μμ΄μ κ° containerμ μ€μ κ°λ₯ν κ°μ λν΄μλ fieldRefλ‘λ μ°Έμ‘°ν μ μλ κ²μ μ£Όμ.
μ°Έμ‘° κ°λ₯ν κ°μ κ΄ν΄μ kubectl get pods -o yaml λ±μ€λ‘ νμΈ κ°λ₯
`# env-container-sample.yml #set CPU Requests/Limits to ENV apiVersion: v1 kind: Pod metadata: name: sample-env-container labels: app: sample-app spec: containers: - name: nginx-container image: nginx:1.12 env: - name: CPU_REQUEST valueFrom: resourceFieldRef: containerName: nginx-container resource: requests.cpu - name: CPU_LIMIT valueFrom: resourceFieldRef: containerName: nginx-container resource: limits.cpu `
**Secret resource κΈ°λ° μ 보**
κΈ°λ° μ 보λ λ³λ Secret resource λ₯Ό λ§λ€μ΄ νκ²½λ³μλ‘ μ°Έμ‘° μν€λ κ²μ μΆμ²
ConfigMap resource μμ Key-Value κ°
λ¨μν Key-Value κ°μ΄λ μ€μ νμΌ λ±μ ConfigMap μΌλ‘ κ΄λ¦¬νλ κ²μ΄ κ°λ₯
μΌκ΄ λ³κ²½μ΄λ μ€λ³΅μ΄ λ§μ΄ λ§μ κ²½μ° ConfigMap μ μ¬μ©νλ κ²μ΄ μ μ©ν μ μμ
νκ²½λ³μ μ΄μ© μ μ£Όμμ
`# env fail sample apiVersion: v1 kind: Pod metadata: name: sample-fail-env labels: app: sample-app spec: containers: - name: nginx-container image: nginx:1.12 command: ["echo"] args: ["${TESTENV}", "${HOSTNAME}"] env: - name: TESTENV value: "100" `
command λ args μ νκ²½λ³μλ₯Ό μ΄μ©νκΈ° μν΄μ ${} κ° μλ $()λ₯Ό μ¬μ©ν΄μΌ νλ€
command λ args μμ μ°Έμ‘°κ°λ₯ν νκ²½ λ³μλ ν΄λΉ Pod template λ΄λΆμμ μ μλ νκ²½ λ³μμ μ νλλ€. (μ μμ μμλ TESTENV κ°λ§ μ°Έμ‘° κ°λ₯)
OS λ±μμλ§ μ°Έμ‘°ν μ μλ νκ²½ λ³μλ₯Ό μ΄μ©νκΈ° μν΄μλ script λ±μ μ΄μ©νμ¬ μ€ννλλ‘ ν΄μΌ νλ€.
Secret
DataBase λ±μ μ¬μ©ν λ νμν μ μ , μνΈ λ±μ μΈμ¦μ νμν κ²½μ° μ΄μ©ν μ μλ λ°©μ
μ μ λͺ κ³Ό μνΈλ₯Ό λ³λ resource λ‘ μ μν΄λκ³ Pod μμ μ΄λ₯Ό λΆλ¬λ€μ¬ μ¬μ©νκΈ° μν resource
Secretμ΄ μ μλ YAML Manifestλ₯Ό μνΈννλ ::kubesec:: μ΄λ OSS μ‘΄μ¬
gpg, Google Cloud KMS, AWS KMS λ±μ μ΄μ©νμ¬ κ°λ¨νκ² data.* λΆλΆλ§ μνΈνν μ μμ΄ μΈλΆλ‘ 곡κ°λμ΄λ λ¬Έμ μμ§κ° μ λ€.
Docker build μ Container Image μ 첨λΆ
νκ²½λ³μλ μ€ν μΈμ λ±μ ν¬ν¨μμΌ Container Image λ₯Ό build.
κΈ°λ° μ 보λ₯Ό ν¬ν¨νκ³ μλ λ§νΌ ν΄λΉ Image λ₯Ό μΈλΆμ 곡κ°νκ±°λ λ°°ν¬νκΈ° κ³€λνλ©° μΈμ¦ μ λ³΄κ° λ³κ²½λλ€λ©΄ Image λ₯Ό λ€μ build ν΄μΌ νλ λ± λΆνΈ
Pod μ΄λ Deployment YAML Manifest μ 첨λΆ
μ΄ μμ YAML μ΄ μΈλΆμ μλ €μ Έμλ μλκ³ λ³΅μ Application μμ λμΌν μ 보λ₯Ό μ¬μ©νκ² λλ€λ©΄ μ¬κΈ°μ κΈ° νΌμ§κ² λλ κ²μ΄λΌ μ΄ μμ λ¬Έμ
Secret λΆλ₯
Generic (type: Opaque)
TLS (type: kubernetes.io/tls)
Docker Registry (type: kubernetes.io/dockerconfigjson)
Service Account (type: kubernetes.io/service-account-token)
Generic (type: Opaque)
λ³΄ν΅ μ¬μ©νλ μνΈ λ±μ μ΄μ©
μμ± λ°©λ²
file μ μ΄μ© (--from-file)
yaml
kubectl μ΄μ©νμ΄ μ§μ μμ± (--from-literal)
envfile
Secret μμλ 볡μμ Key-Value κ°μ΄ 보쑴λλ€.
db-auth λΌλ μ΄λ¦μ Secret μλ username, password λΌλ Keyκ° μκ³ κ·Έμ ν΄λΉνλ Value κ°μ΄ μ‘΄μ¬ν μ μλ€.
볡μμ DBλ₯Ό μ¬μ©νλ κ²½μ°, Secret μ΄λ¦μ΄ κ²ΉμΉμ§ μκ² μ μνκ±°λ μμ€ν λ³λ‘ Namespaceλ₯Ό λΆν νλ λ±μ μμ μ΄ νμ
from File
--from-file μ΅μ μ μ¬μ©νμ¬ νμΌμ μ§μ νμ¬ μ¬μ©νλ€
νμΌλͺ μ΄ κ³§ Key κ° λκΈ°μ νμΌλͺ μ ν¬ν¨λ νμ₯μ λ±μ μ κ±°νλκ² μ’μ μ μλ€.
νμ₯μλ₯Ό μ κ±°νκΈ° μ«λ€λ©΄, --from-file=username=username.txt μ²λΌ μ¬μ©ν μλ μλ€.
νμΌμ κ°νλ¬Έμ(\n)κ° λ€μ΄κ°μ§ μλλ‘ echo -n μ μ¬μ©νλ λ±μΌλ‘ μ£Όμν΄μΌ νλ€.
`# source νμΌ μμ± $ echo -n "user" > ./username $ echo -n "password" > ./password # Secret μμ± $ kubectl create secret generic sample-db-auth --from-file=./username --from-file=./password # json νμμΌλ‘ base64 νμμΌλ‘ encode λ Secret data λΆλΆμ νμΈ $ kubectl get secret sample-db-auth -o json | jq .data # base64 νμμΌλ‘ encode λ λ΄μ©μ νλ¬ΈμΌλ‘ νμΈ $ kubectl get secret sample-db-auth -o json | jq -r .data.username | base64 -d `
from yaml
`apiVersion: v1 kind: Secret metadata: name: sample-db-auth type: Opaque data: username: dXNlcgo= password: cGFzc3dvcmQK `
using kubectl (--from-literal)
βfrom-literal μ΅μ μ¬μ©
`$ kubectl create secret generic sample-db-auth --from-literal=username=user --from-literal=password=password `
from envfile
μΌκ΄μ μΌλ‘ μ²λ¦¬ν λ μ΄μ©κ°λ₯νλ©° Docker μμ βenv-file μ΅μ μ μ¬μ©νμ¬ containerλ₯Ό μ¬μ©νκ³ μμλ€λ©΄ κ·Έλλ‘ Secret μ μ΄μνλ κ²λ κ°λ₯νλ€.
`username=user password=password $ kubectl create secret generic sample-db-auth --from-env-file ./env_secret `
TLS (type: kubernetes.io/tls)
Ingress λ±μμ μ°Έμ‘° κ°λ₯ν TLS μ© Secret
μ£Όλ‘ μΈμ¦μ λ±μ μ΄μ©νκΈ° μν΄ μ¬μ©νλ©° μΌλ°μ μΌλ‘ νμΌμ μ΄μ©νμ¬ μ΄μ©νλ€.
--key μ βcert λ‘ λΉλ°ν€μ μΈμ¦μλ₯Ό μ§μ νλ€.
`# create certificate $ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /tmp/tls.key -out /tmp/tls.crt - subj "/CN=sample1.example.com" # create TLS Secret $ kubectl create secret tls tls-sample --key /tmp/tls.key --cert /tmp/tls.crt `
Docker Registry (type: kubernetes.io/dockerconfigjson)
Docker Registry μΈμ¦ μ 보μ©
using kubectl
kubectl μ μ΄μ©ν κ²½μ° Registry μλ²μ μΈμ¦μ 보λ₯Ό μΈμλ‘ μ§μ νλ€.
`$ kubectl create secret docker-registry sample-registry-auth \ --docker-server=REGISTRY_SERVER \ --docker-username=REGISTRY_USER \ --docker-password=REGISTRY_USER_PASSWORD \ --docker-email=REGISTRY_USER_EMAIL # get $ kubectl get secret -o json sample-registry-auth | jq .data `
Secret μ μ΄μ©ν image νλ
μΈμ¦μ΄ νμν Docker Registry λ Docker Hub μ Private repository μ Image λ₯Ό κ°μ Έμ€κΈ° μν΄μ Secret μ μ¬μ μ λ§λ€μ΄λκ³ Pod μ spec.imagePullSecrets μ docker-registry νμ μ Secret μ μ§μ νλ€.
`# secret-pull_sample.yml apiVersion: v1 kind: Pod metadata: name: sample-pod spec: containers: - name: secret-image-container image: REGISTRY_NAME/secret-image:latest imagePullSecrets: - name: sample-registry-auth `
Service Account
μλμΌλ‘ λ§λλ κ²μ μλμ§λ§ Pod μ Service Account μ Token μ mount νκΈ° μν¨
Secret μ΄μ©
Secret μ containerμμ μ΄μ©ν κ²½μ°, ν¬κ² λλ μ 2κ°μ§ ν¨ν΄
νκ²½λ³μ
VolumeμΌλ‘ mount
Secret μ νΉμ Key νμ
Secret μ λͺ¨λ Key
Secretμ νΉμ Key νμ
Secret μ λͺ¨λ ν€
νκ²½λ³μ
νκ²½λ³μλ‘ λκΈΈ κ²½μ°, νΉμ Keyλ§μ λκΈ° λκ°, Secret μ 체λ₯Ό λκΈ°λκ°.
νΉμ key λ§μ λκΈΈ κ²½μ°, spec.containers[].env μ valueFrom.secretKeyRef λ₯Ό μ¬μ©νμ¬ λκΈΈ ν€λ₯Ό μ§μ
`# secret_single_env_sample.yml apiVersion: v1 kind: Pod metadata: name: sample-secret-single-env spec: containers: - name: secret-container image: nginx:1.12 env: - name: DB_USERNAME valueFrom: secretKeyRef: name: sample-db-auth key: username `
env λ‘ 1κ°μ© μ μκ° κ°λ₯νμ¬ νκ²½λ³μ λͺ μ μ§μ κ°λ₯νλ€.
Secret μ 체λ₯Ό λκΈΈ κ²½μ°
`# secret_multi_env_sample.yml apiVersion: v1 kind: Pod metadata: name: sample-secret-multi-env spec: containers: - name: secret-container image: nginx:1.12 envFrom: - secretRef: name: sample-db-auth `
Key λ₯Ό μΌμΌμ΄ μ§μ νμ§ μμλ λμ΄ κ°κ²°νμ§λ§ Secret μ μ μ₯λμ΄ μλ κ°μ Pod Template λ‘λ νμ νκΈ° νλ€λ€. **Volume Mount**
νΉμ Key λ§μ λκΈΈ κ²½μ°, spec.volumes[] μ secret.item[] μ μ¬μ©νμ¬ μ§μ νλ€.
`# secret_single_volume_sample.yml apiVersion: v1 kind: Pod metadata: name: sample-secret-single-volume spec: containers: - name: secret-container image: nginx:1.12 volumeMounts: - name: config-volume mountPath: /config volumes: - name: config-volume secret: secretName: sample-db-auth items: - key: username path: username.txt `
mount ν νμΌμ 1κ°μ© μ μν μ μμ΄ νμΌλͺ μ μ§μ κ°λ₯νλ€. <pre>`$ kubectl exec -it sample-secret-single-volume cat /config/username.txt `</pre>
Secret μ 체λ₯Ό λ³μλ‘ λκΈΈ κ²½μ°
`# secret_multi_volume_sample.yml apiVersion: v1 kind: Pod metadata: name: sample-secret-multi-volume spec: containers: - name: secret-container image: nginx:1.12 volumeMounts: - name: config-volume mountPath: /config volumes: - name: config-volume secret: secretName: sample-db-auth `
`$ kubectl exec -it sample-secret-multi-volume ls /config `
**λμ Secret κ°±μ ** Volume Mount μΌλ‘ Secret μ μ΄μ©ν κ²½μ° μΌμ κΈ°κ° μ£ΌκΈ° (kubelet μ Sync Loop μ νμ΄λ°) λ‘ kube-apiserver μ λ³κ²½μ νμΈν΄μ λ³κ²½μ΄ μμ κ²½μ° κ°±μ νλ€. κΈ°λ³Έμ μΌλ‘ SyncLoopμ κ°κ²©μ 60μ΄λ‘ μ€μ λμ΄ μμΌλ kuebelet μ μ΅μ `βsync-frequency` λ‘ λ³κ²½ κ°λ₯νλ€. (μ΄λ νκ²½λ³μλ₯Ό μ΄μνλ κ²½μ°μλ μ΄μ© λΆκ° νλ€.) μ΄ κ²½μ° Volume μ λ§μ΄νΈ λ νμΌμ κ°μ΄ λ°λμ΄λ Pod μ΄ μ¬μμ± λλ κ²μ΄ μλμ΄μ λκΈ°λ κ²μ κ±±μ ν νμλ μλ€. Secret μμ μμ λ κ² μμ κ°μ΄ μμ λλ€. ## ConfigMap ConfigMap μ μ€μ μ 보 λ±μ Key-Value λ‘ λ³΄μ‘΄ν μ μλ λ°μ΄ν°λ₯Ό μ μ₯νκΈ° μν resource. Key-Value λΌκ³ ν΄λ nginx.conf λ httpd.conf μ κ°μ μ€μ νμΌ κ·Έ μ체λ 보쑴κ°λ₯νλ€. **create ConfigMap** Generic type Secret κ³Ό κ±°μ λμΌν λ°©λ².
3κ°μ§ λ°©λ²
νμΌμ μ¬μ© (βfrom-file)
yaml νμΌμ μ¬μ©
kubectlλ‘ μ§μ μμ± (βfrom-literal)
ConfigMap μλ 볡μμ Key-Value κ°μ΄ λ€μ΄κ°λ€. nginx.conf μ 체λ₯Ό ConfigMap μμ λ£κ±°λ nginx.conf μ μ€μ parameterλ§ λ£μ΄λ λλ€.
νμΌμ μ¬μ©
νμΌμ μ¬μ©ν κ²½μ°. βfrom-file μ μ§μ νλ€. λ³΄ν΅ νμΌλͺ μ΄ κ·Έλλ‘ Key λ‘ μ¬μ©λλ©° Keyλͺ μ λ³κ²½νκ³ μΆμ κ²½μ°, βfrom-file=nginx.conf=sample-nginx.conf μ κ°μ νμμΌλ‘ μ§μ νλ€.
`# create ConfigMap $ kubectl create configmap sample-configmap --from-file=./nginx.conf # νμΈ $ kubectl get configmap sample-configmap -o json | jq .data # describe $ kubectl describe configmap sample-configmap `
YAML νμΌμ μ¬μ©
Value κ°μ΄ κΈΈ κ²½μ°, Key: | μ²λΌ μ μ
`apiVersion: v1 kind: ConfigMap metadata: name: sample-configmap data: thread: "16" connection.max: "100" connection.min: "10" sample.properties: | property.1=value-1 property.2=value-2 property.3=value-3 nginx.conf: | user nginx; worker_processes auto; error_log /var/log/nginx/error.log; pid /run/nginx.pid; ... `
kubectl μ μ¬μ© (βfrom-literal)
`$ kubectl create configmap web-config \ --from-literal=connection.max=100 \ --from-literal=connection.min=10 `
ConfigMap μ΄μ©
νκ²½λ³μ
Volume mount
νΉμ Key
λͺ¨λ Key
νΉμ Key
λͺ¨λ Key
νκ²½λ³μ
νΉμ Keyλ§ λκΈΈ κ²½μ°, spec.containers[].env μ valueFrom.configMapKeyRef λ₯Ό μ¬μ©
`# configmap_single_env_sample.yml apiVersion: v1 kind: Pod metadata: name: sample-configmap-single-env spec: containers: - name: configmap-container image: nginx:1.12 env: - name: CONNECTION_MAX valueFrom: configMapKeyRef: name: sample-configmap key: connection.max `
env νκ°μ© μ μκ° κ°λ₯ν΄μ νκ²½λ³μλͺ μ μ§μ κ°λ₯
λͺ¨λ Keyλ₯Ό λκΈΈ κ²½μ°, νκ°μ© μ μν νμκ° μμ΄ YAML μ΄ κ°λ΅ν΄μ§μ§λ§ YAML λ§μΌλ‘λ μ΄λ€ κ°μ΄ μλμ§ νλ¨νκΈ΄ νλ€λ€
`# configmap_multi_env_sample.yml apiVersion: v1 kind: Pod metadata: name: sample-configmap-multi-env spec: containers: - name: configmap-container imgae: nginx:1.12 envFrom: - configMapRef: name: sample-configmap `
νκ²½λ³μλ₯Ό μ΄μ©νλ κ²½μ°, λ€μκ³Ό κ°μ ν¨ν΄μ ννν μ μμ΄ μ λ¬λμ§ μλλ€.
. μ΄ ν¬ν¨λλ κ²½μ°
κ°νμ΄ ν¬ν¨λλ κ²½μ°. (Key. | λ‘ μ μλ κ²½μ°)
Volume Mount
νΉμ Key λ§ λκΈΈ κ²½μ°, spec.volumes[] μ configMap.items[] λ₯Ό μ¬μ©νλ€.
`# configmap_single_volume_sample.yml apiVersion: v1 kind: Pod metadata: name: sample-configmap-single-volume spec: containers: - name: configmap-container image: nginx:1.12 volumeMounts: - name: config-volume mountPath: /config volumes: - name: config-volume configMap: name: sample-configmap items: - key: nginx.conf path: nginx-sample.conf `
mount ν νμΌμ νλμ© μ μνλ―λ‘ νμΌλͺ μ μ§μ κ°λ₯νλ€. <pre>`$ kubectl exec -it sample-configmap-single-volume cat /config/nginx-sample.conf `</pre>
λͺ¨λ Key λ₯Ό λκΈΈ κ²½μ°, YAML μ΄ κ°κ²°ν΄μ§μ§λ§ YAML λ§μΌλ‘λ μ΄λ€ κ°μ΄ μλμ§ νλ¨νκΈ° νλ€λ€.
`# configmap_multi_volume_sample.yml apiVersion: v1 kind: Pod metadata: name: sample-configmap-multi-volume spec: containers: - name: configmap-container image: nginx:1.12 volumeMounts: - name: config-volume mountPath: /config volumes: - name: config-volume configMap: name: sample-configmap `
`$ kubectl exec -it sample-configmap-multi-volume ls /config `
**λμ ConfigMap κ°±μ ** volume mount λ₯Ό μ΄μ©νλ κ²½μ°, μΌμ μκ° μ£ΌκΈ° (kubelet μ Sync Loop νμ΄λ°)λ‘ kube-apiserver μ λ³κ²½μ νμΈν΄μ, λ³κ²½μ΄ μμΌλ©΄ κ°±μ νλ€. SyncLoop μ κΈ°λ³Έκ°μ 60μ΄λ‘ μ€μ λμ΄ μμΌλ μ΄λ₯Ό λ³κ²½νκ³ μΆμ κ²½μ°, kubelet μ `βsync-frequency` λ₯Ό μ¬μ©νμ¬ μ€μ νλ€. (νκ²½ λ³μμ κ²½μ° λμ κ°±μ μ΄ λΆκ°) ## Volume κ³Ό PersistentVolume, PersistentVolumeClaim μ μ°¨μ΄ Volume μ κΈ°μ‘΄μ Volume (host μμ, NFS, Ceph, GCP Volume) λ±μ YAML Manifest μ μ§μ μ§μ νμ¬ μ΄μ© κ°λ₯νκ² νλ κ²μ΄λ€. κ·Έλμ μ΄μ©μκ° μ κ·λ‘ Volume μ μμ±νκ±°λ, κΈ°μ‘΄μ Volume μ μμ νλ λ±μ μ‘°μμ΄ λΆκ°λ₯νλ€. κ·Έλ¦¬κ³ YAML Manifest λ‘ Volume resource λ₯Ό λ§λλ λ±μ μ²λ¦¬λ λΆκ°λ₯νλ€. PersistentVolumeμ μΈλΆμ Persistent ν Volumeμ μ 곡νλ μμ€ν κ³Ό μ°κ³νμ¬ μ κ· Volume μ λ§λ€κ±°λ κΈ°μ‘΄μ Volume μ μμ νλ κ²μ΄ κ°λ₯νλ€. ꡬ체μ μΌλ‘λ YAML Manifest λ±μ ν΅ν΄ Persistent Volume resource λ₯Ό λ³λ λ§λλ νμμ΄λ€. PersistentVolume μ plug-in μμλ Volume μ μμ±κ³Ό μμ μ κ°μ life cycle μ μ²λ¦¬νλ κ²μ΄ κ°λ₯νμ§λ§ Volume μ plug-in μ κ²½μ°, μ΄λ―Έ μλ Volume μ μ¬μ©νλ κ²λ§ κ°λ₯νλ€. PersistentVolumeClaim μ PersistentVolume resource μμ assign νκΈ° μν resource. PersistentVolumeμ clusterμ volume μ λ±λ‘νκΈ°λ§ νλκ±°λΌ, μ€μ λ‘ Pod μμ μ΄μ©νκΈ° μν΄μλ PersistentVolumeClaim μ μ μν΄μΌ νλ€. Dynamic Provisioning κΈ°λ₯μ μ΄μ©ν κ²½μ°, PersistentVolumeClaimμ μ΄μ©νλ μμ μ Persistent Volume μ λμ μΌλ‘ μμ±νλ κ²μ΄ κ°λ₯ν΄μ μμκ° λ°λκ° λ μ μλ€. ## Volume [Volume Plug-in](https://kubernetes.io/docs/concepts/storage/volumes/) PersistentVolumeκ³Ό λ¬λ¦¬ Pod μ λν΄ μ μ μΌλ‘ μμμ μ§μ νκΈ° μν ννκ° λκΈ° λλ¬Έμ μΆ©λ(κ²½μ)μ μ£Όμ **EmptyDir**
Pod μ μΌμμ μΈ λμ€ν¬ μμμΌλ‘ μ΄μ© κ°λ₯
Pod μ΄ Terminate λλ©΄ μμ λ¨
`# emptydir-sample.yml apiVersion: v1 kind: Pod metadata: name: sample-emptydir spec: containers: - image: nginx:1.12 name: nginx-container volumeMounts: - mountPath: /cache name: cache-volume volumes: - name: cache-volume emptyDir: {} `
**HostPath**
Kubernetes Node μμ μμμ container μ mapping νκΈ° μν plug-in.
type
Directory
DirectoryOrCreate
File
Socket
BlockDevice
`# hostpath-sample.yml apiVersion: v1 kind: Pod metadata: name: sample-hostpath spec: containers: - image: nginx:1.12 name: nginx-container volumeMounts: - mountPath: /srv name: hostpath-sample volumes: - name: hostpath-sample hostPath: path: /data type: DirectoryOrCreate `
## PersistentVolume (PV)
Volume μ΄ Pod μ μμ ν¬ν¨λμλ€λ©΄ PersistentVolumeμ resource λ‘ λ³λλ‘ μμ±
μλ°ν λ§νλ©΄ Config&Storage resource λ³΄λ€ Cluster resource.
PersistentVolume μ’ λ₯
κΈ°λ³Έμ μΌλ‘ network λ₯Ό μ΄μ©ν΄ disk attach νλ€.
Persistent Volumes - Kubernetes
GCE Persistent Disk
AWS Elastic Block Store
NFS
iSCSI
Ceph
OpenStack Cinder
GlusterFS
create PersistentVolume
label
μ©λ
access mode
reclaim policy
mount option
storage class
setting for each PersistentVolume
`# pv_sample.yml apiVersion: v1 kind: PersistentVolume metadata: name: sample-pv labels: type: nfs envrionment: stg spec: capacity: storage: 10G accessModes: - ReadWriteMany persistentVolumeReclaimPolicy: Retain storageClassName: slow mountOptions: - hard nfs: server: xxx.xxx.xxx.xxx path: /nfs/sample `
`$ kubectl get pv `
**Label** Dynamic Provisioining μ μ¬μ©νμ§ μκ³ PersistentVolumeμ μ¬μ©νλ κ²½μ°, μ’ λ₯κ° μ μ μκ² λκΈ° μ¬μ°λ type, environment, speed λ±μ label μ λΆμ΄λκ±Έ μΆμ²νλ€. Label μ λΆμ΄λ©΄ PersistentVolumeClaim μμ Volume μ Label μ μ§μ κ°λ₯νμ¬ scheduling μ μ λνκ² μνν μ μλ€. **μ©λ** Dynamic Provisioning μ μ΄μ©ν μ μμ κ²½μ°, 무μμ μ©λμ ν¬κ² μ‘μμ μ λλ€. μꡬν μ©λκ³Ό κ°μ₯ κ°κΉμ΄ μ©λμ κ°μ§ storage κ° μ¬μ©λκΈ° λλ¬Έ. **access mode**
ReadWriteOnce (RWO) : λ¨μΌ node μμ Read / Write
ReadOnlyMany (ROX) : λ¨μΌ node μμ Write, 볡μ λ Έλμμ Read
ReadWriteMany (RWX) : 볡μ node μμ Read / Write
Persistent Volumes - Kubernetes
Reclaim Policy
Persistent Volume μ¬μ©μ΄ λλ ν μ²λ¦¬λ°©λ²
Retain
Recycle
Delete
data λ₯Ό μμ νμ§ μκ³ λ³΄μ‘΄
λ€λ₯Έ PersistentVolumeClaim μΌλ‘ μ¬ mount λλ μΌμ μλ€
data μμ (rm -rf ./*), μ¬μ΄μ©κ°λ₯ν μνλ‘
λ€λ₯Έ PersistentVolumeClaim μμ μ¬ mount κ°λ₯
PersistentVolume μμ
μ£Όλ‘ μΈλΆ volume μ μ¬μ©ν λ μ¬μ©
Mount Options
PersistentVolume μ μ’ λ₯μ λ°λΌ μμ΄. νμΈ.
Storage Class
Dynamic Provisioning μ κ²½μ° μ¬μ©μκ° PersistentVolumeClaim μ μ¬μ©νμ¬ PersistentVolume μ μꡬν λ μνλ λμ€ν¬λ₯Ό μ§μ νκΈ° μν΄ μ¬μ©.
Storage Class μ ν = μΈλΆ Volume μ’ λ₯ μ ν
`#storageclass_sample.yml apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: sample-storageclass parameters: availability: test-zone-la type: scaleio provisioner: kubernetes.io/cinder `
PersistentVolume plug-in λ³ μ€μ
μ€μ λ‘λ μ’ λ₯μ λ°λΌ μ κ°κ°μ΄λΌ νμΈ νμ
PersistentVolumeClaim (PVC)
PersistemtVolumeClaim μ μ§μ λ 쑰건μ κ°μ§κ³ μꡬνμ¬ Scheduler λ νμ¬ λ³΄μ νκ³ μλ PersistentVolume μμ μ ν©ν Volume μ ν λΉ
PersistentVolumeClaim μ€μ
label selector
capacity
access mode
Storage Class
PVC μμ μꡬνλ μ©λμ΄ PV μ©λλ³΄λ€ μμΌλ©΄ ν λΉλλ€. 8κΈ°κ°λ₯Ό μꡬ νλλ° λ± λ§λκ² μκ³ κ·Έ λ³΄λ€ ν° 20 κΈ°κ°κ° μμΌλ©΄ 20κΈ°κ° λ₯Ό ν λΉ.
NFS μ κ²½μ° Quota κ° κ±Έλ € μμ§ μμ PV μ μ©λμ΄ μ¬μ€μ 무μλλ€.
create PersistentVolumeClaim
`# pvc_sample.yml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: sample-pvc spec: selector: matchLabels: type: "nfs" matchExpressions: - {key: environment, operator: In, values: [stg]} accessModes: - ReadWriteOnce resources: requests: storage: 4Gi `
`$ kubectl get pvc $ kubectl get pv `
PVC κ° PV ν보μ μ€ν¨νλ©΄ pending μνκ° μ μ§λλ€.
Retain Policy λ₯Ό μ¬μ©νκ³ μμ κ²½μ°, Pod μ΄ μ’ λ£λλ©΄ Bound μνμμ Released μνλ‘ λ°λλ€. μ΄ Released μνκ° λ PV λ PVC κ° μ¬ν λΉνμ§ μλλ€.
use in Pod
spec.volumes μ persistentVolumeClaim.claimName μ μ¬μ©
`# pvc_pod_sample.yml apiVersion: v1 kind: Pod metadata: name: sample-pvc-pod spec: containers: - name: nginx-container image: nginx ports: - containerPort: 80 name: "http" volumeMounts: - mountPath: "/usr/share/nginx/html" name: nginx-pvc volumes: - name: nginx-pvc persistentVolumeClaim: className: sample-pvc `
Dynamic Provisioning
λμ μΌλ‘ PV λ₯Ό λ§λ€κΈ° λλ¬Έμ μ©λμ ν¨μ¨μ μΌλ‘ μ¬μ©νλ κ²μ΄ κ°λ₯νκ³ μ¬μ μ PV λ₯Ό λ§λ€μ΄ λ νμκ° μλ€.
λ§μ Provisioner κ° ReadWriteOnce λ°μ μ§μνμ§ μλ κ²½μ°κ° λ§λ€.
`# Storage Class # storageclass_sample.yml apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: sample-storageclass parameters: type: pd-standard provisioner: kubernetes.io/gce-pd reclaimPolicy: Delete `
`# PVC # pvc_provisioner_sample.yml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: sample-pvc-provisioner annotations: volume.beta.kubernetes.io/storage-class: sample-storageclass spec: accessModes: - ReadWriteOnce resources: requests: storage: 3Gi `
`# Pod # pvc_provisioner_pod_sample.yml apiVersion: v1 kind: Pod metadata: name: sample-pvc-provisioner-pod spec: containers: - name: nginx-container image: nginx prots: - containerPort: 80 name: "http" volumeMounts: - mountPath: "/usr/share/nginx/html" name: nginx-pvc volumes: - name: nginx-pvc persistentVolumeClaim: claimName: sample-pvc-provisioner `
`$ kubectl get pv `
PersistentVolumeClaim in StatefulSet
StatefulSet μμλ PersistentVolumeClaim μ μ΄μ©ν κ²½μ°κ° λ§κ³ spec.volumeClaimTemplate μ μ΄μ©νλ©΄ λ³λλ‘ PVC λ₯Ό μ μν νμ μλ€.
`apiVersion: apps/v1beta1 kind: StatefulSet metadata: ... spec: template: spec: containers: - name: sample-pvct image: nginx:1.12 volumeMounts: - name: pvc-template-volume mountPath: /tmp volumeClaimTemplates: - matadata: name: pvc-template-volume spec: accessModes: - ReadWriteOnce resources: requests: storage: 10Gi storageClassName: "sample-storageclass"










