Text
Markdown test
head 1
head 2
head 3
head 4
head 5
head 6
item1
item2
item3
item1
item2
item3
google link
underline
::highlight::
-strike-
bold, /italic/, underline, ::highlight::,-strike-
[[Tips & Tricks]]
test
test
test
test
0 notes
Text
Whatโs the difference between docker compose and Kubernetes?
Whatโs the difference between docker compose and kubernetes? - Stack Overflow
Docker
Docker is the container technology that allows you to containerize your applications. Docker is the core for using the other technologies.
Docker Compose
Allows configuring and starting multiple docker containers. This is mostly used as a helper when you want to start multiple docker containers and donโt want to start each one separately using docker run โฆ . Docker compose is used for starting containers on the same host.
To short
::docker-compose:: is a tool that takes a YAML file which describes your multi-container application and helps you create, start/stop, remove all those containers without having to type multiple docker ... commands for each container.
from the docs
Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your applicationโs services. Then, with a single command, you create and start all the services from your configuration.
Compose has commands for managing the whole lifecycle of your application: * Start, stop, and rebuild services * View the status of running services * Stream the log output of running services * Run a one-off command on a service
Docker Swarm
Docker swarm is for running and connecting containers on multiple hosts. Docker swarm is a container cluster management and orchestration tool. It manages containers running on multiple hosts and does things like scaling, starting a new container when one crashes, networking containersโฆ
Docker swarm is docker in production. It is the native docker orchestration tool that is embedded in the Docker Engine.
The docker swarm file named stack file is very similar to a docker compose file.
Kubernetes
A container orchestration tool developed by Google. Kubernetes goal is very similar as that for Docker swarm.
To short
::Kubernetes:: is a platform for managing containerized workloads and services, that facilitates both declarative configuration and automation.
from Introduction to Kubernetes
Introduction to Kubernetes Kubernetes is a container orchestrator like Docker Swarm, Mesos Marathon, Amazon ECS, Hashicorp Nomad. Container orchestrators are the tools which group hosts together to form a cluster, and help us make sure applications: * are fault-tolerant, * can scale, and do this on-demand * use resources optimally * can discover other applications automatically, and communicate with each other * are accessible from the external world * can update/rollback without any downtime.
The kind of problems Kubernetes tries to solve:
12-factor apps
Automatic bin packing
self-healing mechanisms,
Horizontal scaling,
Service discovery and Load balancing,
Automated rollouts and rollbacks,
Blue-Green deployments / Canary deployments
Secrets and configuration management,
Storage orchestration
Docker Cloud
A paid enterprise docker service that allows you to build and run containers on cloud servers or local servers. It provides a Web UI and a central control panel to run and manage containers while providing all the docker features in a user friendly Web interface.
Update:
Docker - Docker Cloud Migration Notification and FAQs
The services on Docker Cloud that provide application, node, and swarm cluster management will be shutting down on May 21โฆ automated builds and registry storage services, will not be affected and will continue to be available
docker #docker-compose #kubernetes #docker-swarm
0 notes
Text
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"
0 notes
Text
Django 2 with Apache and WSGI
Django 2 with Apache and WSGI
Django ์์ Apache (with WSGI, Web Server Gateway Interface) ๋ฅผ ๋ถ์ฌ์ ์๋น์ค๋ฅผ ํ๊ธฐ ์ํด ํ์ํ ์์
์ ๋ฆฌ ๊ฒ์์ผ๋ก ๋์ค๋ ์ ์ฌ ์ ๋ณด๋ค์ ๋๋ถ๋ถ ์์ ๋ฒ์ ๊ธฐ์ค์ด๋ผ๋๊ฐ Python 2 ๊ธฐ์ค์ผ๋ก ๋์ด ์์ด Python 3 ์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ์ ๋ํ ์ ๋ณด๊ฐ ๋ง์ด ์์ด์ ์ ๋ฆฌ
ํด๋น ์ค์ ๋ค์ How to Serve Django Applications with Apache and mod_wsgi on Debian 8 ์ ๋๋ถ๋ถ ์ฐธ์กฐํ๋ค. ์ ๋ฌธ์์์๋ Apache ์ค์ ์ 000-default.conf ์ ์ค์ ํ์ฌ ๋ณ๋์ ์ฌ์ดํธ ํ์ฑํ๊ฐ ํ์์์ง๋ง ๊ธฐ๋ณธ ์ค์ ์ด๋ผ Apache ๋ก ์ฌ๋ฌ ์ฌ์ดํธ๋ฅผ ์ด์ํ๊ณ ์๋ค๋ฉด ๋ณ๋์ ์ค์ ์ ์์ฑํ๋ ๊ฒ์ด ๋ง์ ๊ฒ์ด๋ค. ์น์ ํ๊ฒ ํ๋ํ๋ ์ค๋ช
์ ํด์ฃผ๊ณ ์์ด์ ์ฐธ๊ณ ํ๊ธฐ ์ข์ ๋ฌธ์์ด๋ค.
Environment
OS: Ubuntu
Apache: 2.4
Django: 2.1.7 (virtualenv ์ฌ์ฉ)
Prepare Packages
Python 2 ์ ๊ฒฝ์ฐ,
libapache2-mod-wsgi : Apache WSGI ๋ชจ๋. ๋๋ถ๋ถ์ ์๋ด๋ ํด๋น ๋ชจ๋์ ์ฌ์ฉํ๋๋ก ๋์ด ์๋๋ฐ ์ด ๋ชจ๋์ Python2 ์์๋ง ์ด์ฉ๊ฐ๋ฅ
Python 3 ์ ๊ฒฝ์ฐ,
libapache2-mod-wsgi-py3 : Apache WSGI ๋ชจ๋. Python 3 ๊ณผ ์ฌ์ฉํ๊ธฐ ์ํด ํ์.
์ ๋ชจ๋๋ค๋ง ์ ๋๋ก ์ค์นํ๋ฉด ์ดํ๋ ์ด๋ฏธ ์๋ ๋ง์ ์ ๋ณด๋ค๊ณผ ๊ฑฐ์ ๋์ผ. ์ ๋ ๋ชจ๋์ ๋์์ ์ฌ์ฉํ๋ ๊ฒ์ด ๋ถ๊ฐ๋ฅํ ๊ฒ์ผ๋ก ๋ณด์ฌ์ง.
Apache WSGI ๋ชจ๋์ ์ค์นํ๋ฉด ๋๋ถ๋ถ ์๋์ผ๋ก ํ์ฑํ ๋์ง๋ง, ํ์ํ ๊ฒฝ์ฐ ํ์ฑํ
# wsgi ๋ชจ๋ ํ์ฑํ $ sudo a2enmod wsgi
๊ทธ ์ธ๋ Python ๋ฒ์ ์ ๋ง๊ฒ pip ๋ฅผ ์ค์นํ๊ณ pip ๋ฅผ ํตํด virtualenv ๋ฑ์ ์ค์น
Python Virtual Environment
์๋ก์ด ํ๋ก์ ํธ๋ฅผ ์์ฑํ๋ ๊ฒฝ์ฐ๋ผ๋ฉด virtualenv ๋ฅผ ๊ตฌ์ฑํ์ฌ Django project ๋ฅผ ์์ฑํ๊ฑฐ๋ ์ด๋ฏธ ์๋ ํ๋ก์ ํธ๋ฅผ ์๋ฒ์ deploy ํด์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ์๋ virtualenv ๋ง ๊ตฌ์ฑํ๋ฉด ๏ฟฝ๏ฟฝ๏ฟฝ ๊ฒ.
$ mkdir ~/myproject $ cd ~/myproject $ virtualenv venv $ source ~/myproject/venv/bin/activate (venv) $ pip install django (venv) $ (venv) django-admin startproject myproject ~/myproject
Project Settings
์ด์ Django project ์ settings ์ค์ ์ค์ ์ด ํ์ํ ํญ๋ชฉ์ ๋ฑ ๋๊ฐ์ง. ์ ๊ทผ ๊ฐ๋ฅํ Host ์ค์ ๊ณผ Static File ์ ๊ทผ์ ์ํ STATIC_ROOT ์ค์
# ~/myproject/myproject/settings.py ... ALLOWED_HOSTS = ["myproject.com", "127.0.0.1"] ... STATIC_URL = '/static/' STATIC_ROOT = os.path.join(BASE_DIR, 'static/')
Initial Project Setup
Database ๋ฅผ ์๋กญ๊ฒ ์์ฑํ ํ์๊ฐ ์๋ค๋ฉด,
(venv) $ python manage.py makemigrations (venv) $ python manage.py migrate
Super User (admin) ์ด ํ์ํ๋ค๋ฉด,
(venv) $ python manage.py createsuperuser
Static File ๋ค์ settings.py ์ ์ค์ ํ ๊ณณ์ ๋ชจ์ผ๊ธฐ ์ํด,
(venv) $ python manage.py collectstatic
๊ทธ ์ธ์ ufw firewall ๋ iptables ์ค์ ์ด ํ์ํ๋ค๋ฉด ์ํ
Django ๋์ ํ์ธ
(venv) $ python manage.py runserver 0.0.0.0:8000
์ด์ python (Django ์ค์ ) ์ ๋์ด๋ venv ์์ ๋น ์ง๋ค.
(venv) $ deactivate
Apache Configuration
Django ํ๋ก์ ํธ๊ฐ ์ฌ์ฉํ VirtualHost ๋ฅผ ์ค์ ํ๋ค. /etc/apache2/sites-available ์ ์ ํธํ๋ ์๋ํฐ๋ฅผ ์ฌ์ฉํ์ฌ ์ ๋นํ ์ค์ ํ์ผ์ ๋ง๋ค์ด์ ํธ์งํ๋ค.
$ sudo emacs /etc/apache2/sites-available/myproject.com.conf
์ค์ ํ๋ ํญ๋ชฉ์ ํฌ๊ฒ ๋๋ ์
Django settings ์ ์ค์ ํ static ํ์ผ๋ค์ ์ ๊ทผํ ์ ์๋ ์์น๋ฅผ ์๋ ค์ฃผ๋ ๊ฒ
Django wsgi.py ์ ์ ๊ทผํ ์ ์๋ ์์น๋ฅผ ์๋ ค ์ฃผ๋ ๊ฒ
WSGI Daemon ์ด ์ฌ์ฉํ virtualenv ํ๊ฒฝ path
... ServerName myproject.com ... Alias /static /home/user/myproject/static <Directory /home/user/myproject/static> Require all granted </Directory> ... <Directory /home/user/myproject/myproject> <Files wsgi.py> Require all granted </Files> </Directory> ... WSGIDaemonProcess myproject python-home=/home/user/myproject/venv python-path=/home/user/myproject WSGIProcessGroup myproject WSGIScriptAlias / /home/user/myproject/myproject/wsgi.py ...
ServerName ์๋ Django ์์ ์ฌ์ฉํ Domain ๋ฑ์ ์ค์ ํ๋ค. ์ด๋ฅผ ์ด์ฉํด์ apache ์ ํด๋น ์ฌ์ดํธ๋ฅผ ํ์ฑํ์ํฌ ์๋ ์๋ค.
# enable myproject.com site $ sudo a2ensite myproject.com
์ด๋ก์จ Apache ์ค์ ๋ ๋
Permissions
Apache ๊ฐ Django ์ ์ ๊ทผ ๊ถํ์ด ์์ด์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์๋ ์๋ค. ์ด ๋๋ฅผ ์ํด์ ์ฃผ์ ํ์ผ๋ค์ Apache ๊ฐ ์ ๊ทผํ ์ ์๋๋ก ๊ถํ์ ์ค์ ํ๋ค.
$ chmod 664 ~/myproject/db.sqlite3 $ chmod 775 ~/myproject $ sudo chown :www-data ~/myproject/db.sqlite3 $ sudo chown :www-data ~/myproject
์ด์ Apache ์ฌ์์์ ํด์ ์ค์ ๋ค์ ์ ์ฉํ๊ณ Django ์ ์ ๊ทผ ๊ฐ๋ฅํ๋๋ก ํ๋ค.
$ sudo apache2ctl configtest ... Syntax OK $ sudo systemctl restart apache2
0 notes
Text
Extract Docker Image as tar file
# docker save -o <path for tar file> <docker image name>
to load it,
# docker load -i <path to tar file>
0 notes
Text
ใใพใใๅใฏใๆ่ก็ใซ้ฃใใใจ่จใฃใใใคใพใใ1ใคใใ้ธๆ่ขใๅบใใฆใใชใใใๅใใใในใใใจใฏใไฟบใซ้ธๆ่ขใไธใใใใจใ ใAๆกใBๆกใCๆกใๅบใใฎใใๅใฎไปไบใงใ็ก็ใใฉใใใฏไฟบใๅคๆญใใใใจใ ใใๅใ1ใคใใๆกใๅบใใฆใใชใใฃใใใใๅใจใใไบบๆ ผใๅฆๅฎใใใใจใซใชใใใงใใAใBใCใๅบใใฆใใใฐใAใฏใกใใฃใจๆใใใBใฏๅ
จ็ถใใกใCใฏใใใใใจๅคๆญใงใใใ้ธๆ่ขใใใใฐใCโๆกใDๆกใ็ใพใใใใใใใชใใใใใชใใฐใใๅใๅฆๅฎใใชใใฆๆธใใใๅใ็ก็ใ ใจ่จใฃใฆใใใใจใฏใๆ่ก็ใซ็ก็ใใใชใใใๅใ่จใในใใชใฎใฏใใใใใ1ใตๆใงใใใใจๆใใจ100ไบบๆใใฆ100ๅๅใใใใพใใใใใพใใใใใใพใใใใใจใใใใจใ ใใใใ่ชฟในใใฎใใจใณใธใใขใฎไปไบใ ใ
https://diamond.jp/articles/-/171045?display=b
1 note
ยท
View note
Text
์ธ์ฆ์ : ์ค์ ํ์ผ ์์ด ์์ฑํ๊ธฐ
Root CA KEY : openssl genrsa -out ca.key 4096
CRT: openssl req -new -x509 -days 3650 -key ca.key -out ca.crt
Intermediate CA
KEY: openssl genrsa -out ia.key 4096
CRT: openssl req -new -key ia.key -out ia.csr
Sign: openssl x509 -req -days 730 -in ia.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out ia.crt
PKCS12: openssl pkcs12 -export -out ia.p12 -inkey ia.key -in ia.crt -chain -CAfile ca.crt
์ถ์ฒ: https://blog.didierstevens.com/2008/12/30/howto-make-your-own-cert-with-openssl/
0 notes
Link
App informations(like sale history) finder in app shopper web site from App Store using action extension.
0 notes
Text
Microsoft Smartscreen Bypass
์น์์ ๋ค์ด๋ก๋ ๋ฐ์ ์คํ ํ์ผ์ Smartscreen ํํฐ์ ์ํด ์คํ ์ ๊ฒฝ๊ณ ์ฐฝ์ด ๋ฑ์ฅํ๊ฒ ๋๋๋ฐ ์ด๋ฅผ ํํผํ๊ธฐ ์ํด์๋ code signing์ผ๋ก ์๋ช
์ ํ๊ณ ๋ค์ด๋ก๋ ์๋ฅผ ๋์ฌ reputation์ ์ถ์ ํด์ผ ํจ.
EV code signing์ผ๋ก ์งํํ๋ฉด reputation์ด ์์ด๋ ์๋๊ฐ ๋น ๋ฅธ ๊ฒ์ผ๋ก ์ถ์ ๋จ.
0 notes
Link
์ด๋ค ์ํฉ์์ HTTP ์ํ ์ฝ๋๊ฐ ๊ฒฐ์ ๋๋์ง ์๊ธฐ ์ฝ๊ฒ ์ ๋ฆฌ๋ ๊ธ
0 notes
Link
i tag ์ญ์ ๋ง์ฐฌ๊ฐ์ง.
์ ์ฌ์ดํธ์์๋ ๋ค์๊ณผ ๊ฐ์ด ์ฐจ์ด์ ์ ์ค๋ช
ํ๊ณ ์๋ค.
Browsers display <strong> as <b>, and <em> as <i>. However, there is a difference in the meaning of these tags: <b> and <i> defines bold and italic text, but <strong> and <em> means that the text is "important".
0 notes
Link
HTML 5์์๋ ํ๊ทธ ์ฌ์ฉ์ ๊ฐ๋ฅํ์ง๋ง ๊ธฐ์กด๊ณผ ๋ค๋ฅด๊ฒ ๊ฐ์กฐํ๊ณ ์ถ์ ๋์ ํ์ด๋ผ์ดํธ, ์ค์ํ ํ์ ๋ฑ์ ์ํ ์๋ก์ด ํ๊ทธ๋ค์ ๊ตฌ๋ถํ๊ณ ์ฌ์ฉํ๋ ๊ฒ์ ๊ถ์ฅํ๊ณ ์๋ค.
0 notes
Text
HTML์์ Doctype์ด ๊ฐ์ง๋ ์๋ฏธ
์น์๋ W3C ํ์ค์ด๋ผ๋ ๊ฒ์ด ์๋ค. ๋๋ถ๋ถ์ ๋ธ๋ผ์ฐ์ ์์๋ ์ด ํ์ค์ ์ง์ํ๋ ค๊ณ ํ ํ
์ง๋ง ๋ธ๋ผ์ฐ์ ๋ง๋ค ๋ฒ๊ทธ๊ฐ ์กด์ฌํ ์ ์๊ณ ์น ๊ฐ๋ฐ์๋ค์ ํด๋น ๋ฒ๊ทธ๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด ๋ธ๋ผ์ฐ์ ์ ๋ง์ถฐ ์น ํ์ด์ง๋ฅผ ๊ฐ๋ฐํ๊ธฐ๋ ํ๋ค. ๊ทธ๋ฐ๋ฐ ์ด๋ฐ ํธํ์ฑ์ ์ ์งํ๊ธฐ ์ํ ์ฝ๋๋ก ์ธํด ์น ํ์ค์ ์๊ฒฉํ๊ฒ ์งํค๋ ๋ค๋ฅธ ์น ๋ธ๋ผ์ฐ์ ์์ ๋ง๊ฐ์ ธ ๋ณด์ธ๋ค๋ฉด? ์ด๋ฐ ์
์ํ์ ํด๊ฒฐํ๊ธฐ ์ํด Microsoft์ MacIE ํ์ด Doctype switching ์ด๋ผ๋ ๋ฐฉ๋ฒ์ ์ ์ํ๋ค.
Doctype์ด๋? ๋ฌธ์๊ฐ ์ฌ์ฉํ๋ ์ธ์ด๊ฐ ๋ฌด์์ธ์ง๋ฅผ ์ ์ธํ์ฌ ๋ฌธ์๋ฅผ ์ฒ๋ฆฌํ ๋ DTD(Document Type Definition)์ ์ฌ์ฉํ๋๋ก ํ๋ element์ด๋ค.
example:
<!DOCTYPE HTML PUBLIC โ-//W3C//DTD HTML 4.0//ENโ โhttp://www.w3.org/TR/REC-html40/strict.dtdโ>
<!DOCTYPE HTML PUBLIC โ-//W3C//DTD HTML 4.0 Transitional//ENโ>
๋ณดํต ์ด๋ฌํ ์์๋ค์ ๋ฌธ์์์ ๊ฐ์ฅ ์ฒซ ๋ฒ์งธ ์ค์ ๋ํ๋๋ฉฐ ๋ธ๋ผ์ฐ์ ๋ ์ด๋ฅผ ์ฃผ์ํ๊ฒ ๋๋ค.
๋ธ๋ผ์ฐ์ ์์๋ Doctype์ ๋ณด๊ณ ์ ์ ํ ํ์ํ ๋ฐฉ๋ฒ์ ๊ฒฐ์ ํ๊ฒ ๋๋ค.
ํ์ค์ ์๊ฒฉํ๊ฒ(example์ ์ฒซ๋ฒ์งธ) ์ ์ฉํ๊ธฐ๋ฅผ ์ํ๊ฑฐ๋ ์กฐ๊ธ ๋์จํ๊ฒ(example ์ ๋๋ฒ์งธ) ์ํ ์๋ ์๋ค. ํ์ค์ ์๊ฒฉํ๊ฒ ๏ฟฝ๏ฟฝ๏ฟฝ๋ฅผ ๊ฒฝ์ฐ ์ด์ ๋ง์ง ์๋ ๊ฒ์ ํ์ํ์ง ์๊ฑฐ๋ ํ ๊ฒ์ด๊ณ ๋์จํ๊ฒ ์ ์ฉํ๋ค๋ฉด ์์ ์ ๋ณด์ฌ์ฃผ๋ ๋ฐฉ์์ผ๋ก ์ ์ฉํ ์ ์์ ๊ฒ์ด๋ค.
์ด๋ฅผ ์ฌ์ฉํ๋ฉด ์ผ์ผ์ด ๋ธ๋ผ์ฐ์ ์ ํธํ์ฑ์ ์ํด ๋งค๋ฒ ๊ณ ์น์ง ์์๋ ๋ ๊ฒ์ด๋ค. ํ์ค์ ์งํค๋ฉด ๋ธ๋ผ์ฐ์ ๊ฐ ์
๋ฐ์ดํธ๋ฅผ ํตํ ๊ณ์ํ์ ๋ฐ๋ผ์ฌ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ด๋ค. ๊ทธ๋ฆฌ๊ณ ์ค๋๋ ํ์ด์ง์ ๊ฒฝ์ฐ ์๋กญ๊ฒ ๋ง๋ค์ง ์์๋ ๊ฐ๋จํ๊ฒ ํ์ค์ ๋ง๊ฒ ํ์ํ๋ ๊ฒ์ด ๊ฐ๋ฅํด ์ง ๊ฒ์ด๋ค.
ํ์ค์ ์๊ฒฉํ๊ฒ ๋ฐ๋ฅด๋ ค๋ฉด
Doctype์ ์ฌ์ฉํ์ฌ DTD๋ฅผ ์ ์ํ๋ค. ์ด ๋, URL์ ์ ์ํ ์ ์๋ค.
ํ์ค์ ์คํ์ฌ ์น ํ์ด์ง๋ฅผ ๋ง๋ ๋ค.
๋ฌธ์์ ์ ํจ์ฑ์ ๊ฒ์ฌํ๊ธธ ์ํ์ง๋ง ์๊ฒฉํ๊ฒ ๋ฐ๋ฅด์ง๋ ์์ ๊ฒฝ์ฐ,
Doctype์ ์ฌ์ฉํ์ฌ DTD๋ฅผ ์ ์ํ๋ URL์ ์ ์ธํ๋ค.
0 notes
Text
[Raspberry Pi] Raspbian์ USB์ ์ค์นํ๊ณ ๊ตฌ๋ํ๊ธฐ
Raspbian์ ๋ค์ด๋ก๋
Raspberry Pi Website์์ ๋ค์ด๋ก๋
Raspbian OS๋ฅผ USB Flash Drive์ ์ค์น
๋ค์ด๋ก๋ํ Raspbian ์ด๋ฏธ์ง๋ฅผ USB Flash Drive์ ์ฎ๊ธด๋ค.
Windows์ ๊ฒฝ์ฐ, Win32 Disk Imager ๋ฅผ ์ฌ์ฉ๊ฐ๋ฅํ๋ค.
Mac์ ๊ฒฝ์ฐ, ์ฝ์ ๋ช
๋ น์ด๋ก
$ diskutil list
์ ์คํํ์ฌ USB Flash Drive ์ฅ์น๋ช
(/dev/disk3)์ ์ฐพ๋๋ค. ์ด๋, ์ด ์ฅ์น๋ช
์ ์ค์ํ๋ ํ๋ฆฌ์ง ์๋๋ก ์กฐ์ฌ.
$ diskutil unmountDisk /dev/disk3
๋ช
๋ น์ด๋ก ์ธ๋ง์ดํธํ ๋ค,
$ sudo dd bs=1m if=raspbian.img of=/dev/disk3
๋ช
๋ น์ผ๋ก USB Flash Drive์ ์ด๋ค.
SD ์นด๋ ์ค์
SD์นด๋๋ FAT32๋ก ํฌ๋ฉงํ๋ค.
๊ทธ๋ฆฌ๊ณ 2.์์ ์ค์นํ USB Flash Drive์์ ๋ณด์ด๋ ํ์ผ๋ค์ SD์นด๋์ ๋ณต์ฌํ๋ค. (๋ถํธ๋ก๋์ ๊ด๋ จ๋ ํ์ผ๋ค๋ง์ด ๋ณด์ผ ๊ฒ์ด๊ณ ์ฉ๋์ ์ผ๋ง ๋์ง ์์ ๊ฒ์ด๋ค)
boot path ๋ณ๊ฒฝ
SD์นด๋์ ๋ณต์ฌํ ํ์ผ๋ค ์ค์ cmdline.txt ๊ฐ ์์ ๊ฒ์ธ๋ฐ, ์ด ๋ด๋ถ์ boot path๊ฐ ๊ธฐ๋ก์ด ๋์ด ์๊ณ ์ด๋ฅผ USB Flash Drive๋ฅผ ๊ฐ๋ฅดํค๋๋ก ๋ณ๊ฒฝํ๋ค. root=/dev/sda2
USB Flash Drive์์ ๊ตฌ๋
Raspbian์ด USB Flash Drive์ ์ ์ฒด ์ฉ๋์ ์ฌ์ฉํ ์ ์๋๋ก ํ์ฅ
USB Flash Drive๋ก ๊ธฐ๋์ด ๋์๋ค ํ์ฌ๋ ์ฉ๋์ img ์ฉ๋ ์ ๋ ๋ฐ์ ์ฌ์ฉํ์ง ๋ชป ํ๊ณ ์๋ค.
ํํฐ์
์ค์ ์ ํตํด ์ด๋ฅผ ํ์ฅํด์ค๋ค.
sudo fdisk /dev/sda
๋ก p ๋ก ํํฐ์
์ ํ์ธํด๏ฟฝ๏ฟฝ๋ฉด ์๋ง /dev/sda2๋ก ์กํ์์ ๊ฒ์ธ๋ฐ d (์ญ์ ) ํ์ฌ 2๋ฅผ ์ญ์ ํด์ฃผ๊ณ n ํ์ฌ ๋ค์ ์ก์์ฃผ๋ ๋ฐ ์ด๋ ์ฃผ์ํ ๊ฒ์ ์ฒ์์ ์์ ์นํฐ ์ซ์๋ฅผ ๊ธฐ์ตํด๋ฌ์ผํ๋ค. ์๋ฅผ ๋ค์ด 122880 ๊ฐ์.
n์ผ๋ก 2๋ฒ ํํฐ์
์ ๋ค์ ์ก์ ์ค ๋, ์์ ์นํฐ๋ฅผ 122880์ ๋์ผํ๊ฒ ์ก์์ฃผ๊ณ ๋๋๋ ์นํฐ๋ ์ํ๋๋๋ก ํน์ ๊ทธ๋ฅ ๋์ด๊ฐ๋ฉด ๊ธฐ๋ณธ์ผ๋ก ์ ๋ถ ์ฌ์ฉํ๋ค.
์ค์ ์ด ๋๋๋ฉด w ๋ก ์ ์ฅํ ๋๋ด๊ณ ์ฌ๋ถํ
ํด์ค๋ค.
sudo resize2fs /dev/sda2
๋ก ํํฐ์
ํฌ๊ธฐ๋ฅผ ๋ค์ ์ก์์ฃผ๊ณ ๋ค์ ํ๋ฒ ์ฌ๋ถํ
ํด์ค๋ค.
df -h
์ด์ ํ์ธํด๋ณด๋ฉด ์คํ ๋ฆฌ์ง ์ฉ๋์ด ๋์ด๋ ๊ฒ์ ํ์ธํ ์ ์์ ๊ฒ์ด๋ค.
0 notes
Link
๋ฉ์ ์ ์ฑ์ด๋ผ๋๊ฒ ์ข๋ ์ซ๋ ๊ฒฐ๊ตญ ์ฌ๋๋ค์ด ๋ง์ด ์ฐ๋ ๊ฑธ ์ธ ์ ๋ฐ์ ์์ด์ ์ด๋ฅผ ํตํฉํ ์ ์๋ ์ฑ์ด ์์๊น ์๊ฐํ ์ ์ด ์์๋๋ฐ ์ฑ์ด ์๋๋ผ ๊ธฐ์ ์ ํ์คํํ์ฌ ๋ค๋ค ์ฌ์ฉํ๋๋ก ํ๋ ๋ฐฉ๋ฒ์ด ์ ๋ต์ด์๊ตฌ๋. ์ด ๋ฐฉ๋ฒ์ด ์ฑ๊ณตํ๋ค๋ฉด ์ฌ๋๋ค์ด ์ฌ์ฉํ๋ ๋ฉ์ ์ ๊ฐ ์ข ๋ ๋ค์ํด์ง๊ฒ ์ง?
0 notes
Photo
Block out the world. Hear what you need. hush.technology
Hush is a wireless noise masking earplug device that lets you sleep through anything while still letting you hear alarms, alerts and phone calls.
์ค๋งํธ ๊ท๋ง๊ฐ. ์ถ์๋ฅผ ์ํด ํ๋ฉ์ ๋ฐ๋ ์ค์ธ๋ฏ.
0 notes