✔️ Volume (볼륨)
파드는 기본적으로 데이터를 영구히
저장할 수 없다.
데이터를 저장
할 수는 있지만 컨테이너 즉, 파드를 삭제하면 해당 데이터는 다 사라지게 된다.
따라서 별도의 라이프 사이클을 가지는 별도의 오브젝트 리소스가 필요하다.
쿠버네티스에서는 이것을 Volume
이라고 한다.
vagrant@k8s-node1 ~ kubectl explain pod.spec
volumes <[]Object>
List of volumes that can be mounted by containers belonging to the pod.
More info: https://kubernetes.io/docs/concepts/storage/volumes
컨테이너에게 제공할 볼륨을 구성할 수 있다.
vagrant@k8s-node1 ~ kubectl explain pod.spec.volumes
volumes
안에는 여러 FIELDS
가 많이 존재한다.
pod.spec.volumes.*
에는 어떤 종류의 볼륨을 연결할 것인가 ? 하는 볼륨의 유형이 들어간다.
클라우드 서비스(AWS, Azure 등)를 포함한 여러 형태의 볼륨이 존재하며 볼륨을 생성하면 볼륨의 id가 나온다.
간단한 예시를 보자
awsElasticBlockStore
: AWS EBS 볼륨을 연결, 파드에 EBS 볼륨을 연결한다.
aws ec2 create-volume --availability-zone=eu-west-1a --size=10 --volume-type=gp2`
apiVersion: v1
kind: Pod
metadata:
name: test-ebs
spec:
containers:
- image: k8s.gcr.io/test-webserver
name: test-container
volumeMounts:
- mountPath: /test-ebs
name: test-volume
volumes:
- name: test-volume # 적당한 이름을 지정한다.
# 이 AWS EBS 볼륨은 이미 존재해야 한다.
awsElasticBlockStore:
volumeID: "<volume-id>"
fsType: ext4
awsElasticBlockStore
가 지정된 자리에 다른 여러 볼륨의 유형이 들어갈 수 있다.
vagrant@k8s-node1 ~ kubectl explain pod.spec.volumes.emptyDir
FIELDS:
medium <string>
What type of storage medium should back this directory. The default is ""
which means to use the node's default medium. Must be an empty string
(default) or Memory. More info:
https://kubernetes.io/docs/concepts/storage/volumes#emptydir
sizeLimit <string>
Total amount of local storage required for this EmptyDir volume. The size
limit is also applicable for memory medium. The maximum usage on memory
medium EmptyDir would be the minimum value between the SizeLimit specified
here and the sum of memory limits of all containers in a pod. The default
is nil which means that the limit is undefined. More info:
http://kubernetes.io/docs/user-guide/volumes#emptydir
어떤 볼륨을 사용하느냐에 따라 즉, 볼륨의 유형에 따라 필드가 다 다르다.
medium
: 해당 디렉토리를 백업해야 하는 저장 매체 유형default
: "", 아무것도 없다.memory
: 메모리(RAM)를 지정한다. RAM Disk를 사용한다.
메모리는 디스크보다 훨씬 빠르다. SSD <<<<<<<< RAM 속도memory
를 사용하려면 메모리 크기에 여유가 있어야 하며 고속의 임시 스토리지 사용하는 용도로 사용할 수 있다.
sizeLimit
: 해당 EmptyDir 볼륨에 필요한 로컬 스토리지의 총량
✔️ emptyDir
임시로 사용할 빈 볼륨을 제공, 파드 삭제시 볼륨도 같이 삭제
쿠버네티스의 워커 노드 호스트(파드)에 빈 디렉토리를 제공하고 파드끼리 공유한다.
Docker의 Bind 볼륨과 비슷한 개념이다.
중요한 것은 해당 디렉토리에 내용을 채워서 제공할 수 없다.
✔️ emptyDir
의 용도
- 디스크 기반의 병합 종류와 같은 스크레치(비어있는) 공간
- 충돌로부터 복구하기위해 긴 계산을 검사점으로 지정
- 웹 서버 컨테이너가 데이터를 처리하는 동안 컨텐츠 매니저 컨테이너가 가져오는 파일을 보관
→ 임시로 사용하는 공간으로 사용하는 형태를 띈다.
해당 그림에서의 Volume
이 emptyDir
이다.
파드에 볼륨을 제공하게 되면 파드에 있는 모든 컨테이너는 해당되는 볼륨을 공유하게 된다.
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: k8s.gcr.io/test-webserver
name: test-container
volumeMounts:
- mountPath: /cache
name: cache-volume
volumes:
- name: cache-volume # 이름을 지정
emptyDir: {} # 유형에 따른 필드가 들어간다.
{}
: 아무것도 없음을 의미한다. medium
이나 sizeLimit
어떤 것도 설정하지 않는다.
containers
에서 초기 볼륨을 정의한뒤 volumeMounts
(볼륨 마운트)할 때 volumeMounts.name
은 volumes.name
과 매칭되어야 한다.
mountPath
에는 어디에 마운트 시킬 것인지를 지정한다.name
에는 마운트할 볼륨의 이름을 지정한다.
✔️ emptyDir 예제
myweb-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: myweb-pod
spec:
containers:
- name: myweb1
image: httpd
volumeMounts:
- name: emptyvol
mountPath: /empty
- name: myweb2
image: ghcr.io/c1t1d0s7/go-myweb:alpine
volumeMounts:
- name: emptyvol
mountPath: /empty
volumes:
- name: emptyvol
emptyDir: {}
리스트로 여러개의 볼륨을 세팅할 수 있다. 이때 디렉토리가 없으면 자동으로 만든다.
vagrant@k8s-node1 ~/volume/emptydir kubectl create -f myweb-pod.yaml
pod/myweb-pod created
vagrant@k8s-node1 ~/volume/emptydir kubectl get po
NAME READY STATUS RESTARTS AGE
myweb-pod 2/2 Running 0 6s
vagrant@k8s-node1 ~/volume/emptydir kubectl describe po myweb-pod
myweb1:
Container ID: containerd://9ffe861bbda2153a26d5b7a1577470e604311afef31c71da1b204fe088d9ef18
Image: httpd
Image ID: docker.io/library/httpd@sha256:2d1f8839d6127e400ac5f65481d8a0f17ac46a3b91de40b01e649c9a0324dea0
Port: <none>
Host Port: <none>
State: Running
Started: Tue, 24 May 2022 09:49:44 +0000
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/empty from emptyvol (rw)
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-nn8q4 (ro)
myweb2:
Container ID: containerd://7e9c2da3fd1a44d46dd789f612866008deb7320447e38b77257f5a0547d0691b
Image: ghcr.io/c1t1d0s7/go-myweb:alpine
Image ID: ghcr.io/c1t1d0s7/go-myweb@sha256:925dd88b5abbe7b9c8dbbe97c28d50178da1d357f4f649c6bc10a389fe5a6a55
Port: <none>
Host Port: <none>
State: Running
Started: Tue, 24 May 2022 09:49:44 +0000
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/empty from emptyvol (rw)
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-nn8q4 (ro)
Volumes:
emptyvol:
Type: EmptyDir (a temporary directory that shares a pod's lifetime)
Medium:
SizeLimit: <unset>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 43s default-scheduler Successfully assigned default/myweb-pod to node3
Normal Pulling 43s kubelet Pulling image "httpd"
Normal Pulled 41s kubelet Successfully pulled image "httpd" in 1.929684123s
Normal Created 41s kubelet Created container myweb1
Normal Started 41s kubelet Started container myweb1
Normal Pulled 41s kubelet Container image "ghcr.io/c1t1d0s7/go-myweb:alpine" already present on machine
Normal Created 41s kubelet Created container myweb2
Normal Started 41s kubelet Started container myweb2
파드를 생성하고 볼륨을 마운팅한뒤 describe
명령을 통해 Events:
에서 진행 과정을 확인할 수 있다.
Events:
- node3에
myweb-pod
를 할당한다. httpd
이미지를 받아온다.myweb1
컨테이너를 만든다.myweb1
컨테이너를 시작한다.myweb2
에서도 동일 작업을 반복한다.
Volumes
에서 볼륨의 Type
은 EmptyDir
인 것을 확인할 수 있다.EmptyDir (a temporary directory that shares a pod's lifetime)
: 파드를 제거하면 EmptyDir
도 지워진다.
myweb1
, myweb2
의 Mounts
설정을 보면 /empty
디렉토리에 emptyvol
을 rw로 마운팅한 것을 볼 수 있다.
vagrant@k8s-node1 ~/volume/emptydir kubectl explain pod.spec.containers.volumeMounts
pod.spec.containers.volumeMounts
: 컨테이너 볼륨을 연결할 때 사용하는 필드
FIELDS:
- mountPath (필수) : 경로
- name (필수) :
volumes
에 정의한 이름 - readOnly : default는 false이며
true
로 세팅시 readOnly로 마운팅
vagrant@k8s-node1 ~/volume/emptydir kubectl exec -it myweb-pod -- bash
Defaulted container "myweb1" out of: myweb1, myweb2 # myweb1이 먼저 실행되었다.
root@myweb-pod:/usr/local/apache2# cd /
root@myweb-pod:/# ls
bin boot dev empty etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@myweb-pod:/# cd empty
root@myweb-pod:/empty# ls
root@myweb-pod:/empty# touch a b c
root@myweb-pod:/empty# exit
exit
root(/) 밑에 empty
디렉토리가 만들어졌고 현재 빈 상태이다.touch
명령어로 a
, b
, c
파일을 만들고 종료한다.
vagrant@k8s-node1 ~/volume/emptydir kubectl exec -it myweb-pod -c myweb2 -- sh
/ # cd /empty/
/empty # ls
a b c
/empty #
empty
디렉토리로 가면 a
, b
, c
파일이 그대로 존재하는 것을 볼 수 있다.
즉, 같은 볼륨을 서로 공유하고 있다.
일반적으로 볼륨은 파드와 라이프 사이클을 별개로 가져가려고 구성하는 것인데, emptyDir
은 파드의 라이프 사이클과 함께한다.
따라서 파드의 삭제시 데이터도 함께 삭제되므로 임시로 사용하는 볼륨이다.
하나의 파드에 여러개의 컨테이너가 있을 때 여러개의 컨테이너가 데이터를 주고 받아야 하는 경우 사용할 수 있는 형태의 볼륨이다.
✔️ gitRepo (사용 중단됨)
emptyDir
과 기본적인 기능은 같다. 다른점은 git
저장소를 동기화시킨다.emptyDir
은 비어있는 디렉토리를 제공할 뿐이지만 gitRepo
를 사용하면 emptyDir
와 동일한 방식으로 제공하지만 git repository의 데이터를 복제한 데이터를 채워서 제공한다.
git clone
명령을 사용해 emptyDir
에 데이터를 채워서 파드에게 제공한다.
apiVersion: v1
kind: Pod
metadata:
name: server
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- mountPath: /mypath
name: git-volume
volumes:
- name: git-volume
gitRepo:
repository: "git@somewhere:me/my-git-repository.git"
revision: "22f1d8406d464b0c0874075539c1f2e96c253775"
사용 방법은 다음과 같다.repository
주소를 지정하고 코드에 버전이 있는 경우 commit version
을 지정한다.
해당 되는 버전에 맞는 내용을 복제해서 마운팅시킨다.
하지만 현재 사용 중단 상태로 이를 대체하기 위해 initContainer를 사용한다.
✔️ gitRepo (사용 중단됨) → initContainer(초기화 컨테이너)
vagrant@k8s-node1 ~/volume/emptydir kubectl explain pod.spec
initContainers <[]Object>
vagrant@k8s-node1 ~/volume/emptydir kubectl explain pod.spec.initContainers
우리가 Containers
에 설정할 수 있는 구성이 initContainers
에도 똑같이 존재한다.
초기화 컨테이너라는 것은 파드가 생성될 때 딱 한번만 실행된다. 실행 후에는 종료한다.
따라서 초기화 컨테이너에서 실행하는 App은 종료되는 App이어야 한다.
App이 종료되지 않으면 Containers
에 설정해놓은 컨테이너가 실행되지 않는다.
즉, initContainers
가 끝나야 Containers
가 실행될 수 있다. (ec2 인스턴스의 user-data와 비슷한 성격을 가진다고 볼 수 있다.)
📌 initContainers
의 사용 예시
파드에 초기화 컨테이너, 컨테이너, 볼륨이 정의되어 있다고 하자
initContainers
가 먼저 볼륨에 연결한다.initContainers
의 App이 작업을 진행한 후 그 결과를 볼륨(Disk)에 저장한다. 그리고initContainers
는 종료한다.- 그 다음 컨테이너가 실행된다. 컨테이너의 App도 볼륨에 연결해서
initContainers
의 App이 계산하고 남겨 놓은 결과 데이터를 갖고 작업한다.
gitRepo
는 많이 사용하던 방식이었으나 더 이상 사용할 수 없게됨에 따라서 그 기능과 똑같은 기능을 만들려고 하면 initContainers
방식을 사용해야 한다.
초기화 컨테이너는 git
저장소에 있는 코드를 다운로드 받아서 저장하는 역할을 하고 컨테이너가 그것을 사용한다.
📌 CMD를 배치하는 방법
vagrant@k8s-node1 ~/volume/initcontainer kubectl explain pod.spec.containers.args
KIND: Pod
VERSION: v1
FIELD: args <[]string>
init-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: init-pod
spec:
initContainers:
- name: gitpull
image: alpine/git
args:
- clone
- -b
- v2.18.1
- https://github.com/kubernetes-sigs/kubespray.git
- /repo
volumeMounts:
- name: gitrepo
mountPath: /repo
containers:
- name: gituse
image: busybox
args:
- tail
- -f
- /dev/null # shell을 사용하는 이미지를 계속 띄워놓기 위함
volumeMounts:
- name: gitrepo
mountPath: /kube
volumes:
- name: gitrepo
emptyDir: {}
/repo
여기에 저장하라고 했으므로 실제 볼륨도 mountPath: /repo
이렇게 연결해야 한다.
그럼 해당 볼륨에 kubespray.git
저장소의 코드를 복제하게 된다.
init-pod
라는 파드가 만들어질 것이며 거기에는 emptyDir
형태로 만들어진 볼륨이 있다.
맨 처음에 initContainers
가 먼저 생성이 되고 연결을 시작해서 git clone
으로 kubespray
코드를 받아서 저장한다. 그리고 initContainers
는 종료한다.
그다음 busybox
이미지를 사용한 컨테이너가 뜨고 동일한 볼륨을 마운팅해서 앞서 initContainers
가 남긴 결과물을 사용하여 작업한다.
Every 1.0s: kubectl get pod k8s-node1: Tue May 24 10:41:40 2022
NAME READY STATUS RESTARTS AGE
init-pod 1/1 Running 0 25s
initContainers
가 총 1개 있다는 소리이며 그 하나가 Completed
되면 1/1이 되고 그다음에 컨테이너가 실행된다.PodInitializing
: 초기화 컨테이너의 작동이 완료됨, 이후 Running
상태로 바뀐다.
vagrant@k8s-node1 ~/volume/initcontainer kubectl describe po init-pod
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 2m49s default-scheduler Successfully assigned default/init-pod to node2
Normal Pulling 2m49s kubelet Pulling image "alpine/git"
Normal Pulled 2m42s kubelet Successfully pulled image "alpine/git" in 7.619113195s
Normal Created 2m41s kubelet Created container gitpull
Normal Started 2m41s kubelet Started container gitpull
Normal Pulling 2m36s kubelet Pulling image "busybox"
Normal Pulled 2m31s kubelet Successfully pulled image "busybox" in 5.009120803s
Normal Created 2m31s kubelet Created container gituse
Normal Started 2m31s kubelet Started container gituse
1) node3에 init-pod
가 배치되었다.
2) alpine/git
image를 pulling한다.
3) initContainers
의 작업을 진행한다. (Created
, Started
)
4) initContainers
가 완료(Completed
)되면 컨테이너(busybox
)를 띄운다.
vagrant@k8s-node1 ~/volume/initcontainer kubectl exec -it init-pod -- sh
Defaulted container "gituse" out of: gituse, gitpull (init)
/ # cd /kube
/kube # ls
CNAME OWNERS_ALIASES ansible.cfg extra_playbooks logo requirements-2.9.txt scripts
CONTRIBUTING.md README.md ansible_version.yml facts.yml mitogen.yml requirements-2.9.yml setup.cfg
Dockerfile RELEASE.md cluster.yml index.html recover-control-plane.yml requirements.txt setup.py
LICENSE SECURITY_CONTACTS code-of-conduct.md inventory remove-node.yml reset.yml test-infra
Makefile Vagrantfile contrib legacy_groups.yml requirements-2.10.txt roles tests
OWNERS _config.yml docs library requirements-2.11.txt scale.yml upgrade-cluster.yml
/kube
디렉토리에 가면 해당 저장소의 코드가 존재하는 것을 볼 수 있다.
initContainers
의 개념은 git
을 동기화시키는 것에만 사용되는 것은 아니다.gitRepo
라는 타입이 더 이상 사용되지 않기 때문에 'initContainers
라는 기법을 이용해서 작업을 할 수 있다'라는 것이다.
해당 방식은 많이 쓰는 패턴으로 반드시 알아둬야 한다.
✔️ hostPath
hostPath
는 호스트의 특정 경로를 컨테이너의 볼륨으로 제공할 수 있다.
Docker에서의 Bind 방식과 매우 흡사하다.
hostPath
는 호스트에 미리 특정 경로를 사용할 수 있기 때문에 그 경로에 데이터를 채워서 컨테이너에게 제공할 수 있다.
vagrant@k8s-node1 ~/volume/hostpath kubectl explain pod.spec.volumes.hostPath
FIELDS:
path <string> -required-
Path of the directory on the host. If the path is a symlink, it will follow
the link to the real path. More info:
https://kubernetes.io/docs/concepts/storage/volumes#hostpath
type <string>
Type for HostPath Volume Defaults to "" More info:
https://kubernetes.io/docs/concepts/storage/volumes#hostpath
path
: 경로를 지정해야 한다.type
: 타입을 지정해야 한다.
가장 많이 쓰는 유형은 Directory
와 File
이다.
DirectoryOrCreate
: Path에서 주어진 디렉토리의 경로가 없으면 빈 디렉터리를 생성한다.Directory
: 주어진 경로에 디렉터리가 있어야 함File
: 주어진 경로에 파일이 있어야 함, 파드가 없으면 볼륨을 연결할 수 없고 파드가 만들어지지 않음Socket
: 4계층과 5계층 사이에 존재하는socket
(특정 서비스의 IP와 Port의 쌍)을 이용해서 접근
vagrant@k8s-node1 ~/volume/hostpath ps -ef | grep containerd
root 3288 1 0 02:51 ? 00:00:04 /usr/local/bin/containerd-shim-runc-v2 -namespace k8s.io -id 347aabaf419945cf1e5175659293e86316b6e06e60c7c5142e48236091515602 -address /run/containerd/containerd.sock # sock
vagrant@k8s-node1 ~/volume/hostpath sudo ls -l /run/containerd/containerd.sock
srw-rw---- 1 root root 0 May 24 02:50 /run/containerd/containerd.sock
해당 파일로 접근시 containerd
서비스로 네트워크에 접근할 수 있다.
/dev/
디렉토리 디스크 장치 파일을 지정하면 거기로 접근할 수 있다.
✔️ Challenge
/mnt/web_contents/index.html
<h1> Hello hostPath </h1>
httpd
이미지를 사용하고 /mnt/web_contents/
에 index.html
파일이 존재하는 ReplicaSet
(replicas: 3
) 생성하기
✔️ Solution
myweb-rs-hp.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: myweb-rs-hp
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: myweb
image: httpd
volumeMounts:
- name: web-contents
mountPath: /usr/local/apache2/htdocs/
volumes:
- name: web-contents
hostPath:
type: Directory
path: /web_contents
volumes.name
에 _
는 허용하지 않는다.web-contents
를 httpd
에 제공하고 마운트 위치는 /usr/local/apache2/htdocs/
이다.
vagrant@k8s-node1 ~/volume/hostpath sudo mkdir /web_contents
vagrant@k8s-node1 ~/volume/hostpath sudo echo "<h1> Hello hostPath </h1>" | sudo tee /web_contents/index.html
Hello hostPath
vagrant@k8s-node1 ~/volume/hostpath cat /web_contents/index.html
<h1> Hello hostPath <h1>
📌 hostPath
타입 사용시 발생하는 잦은 실수
vagrant@k8s-node1 ~/volume/hostpath kubectl get rs,po -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
replicaset.apps/myweb-rs-hp 3 3 1 7s myweb httpd app=web
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/myweb-rs-hp-5t9zp 1/1 Running 0 7s 10.233.90.74 node1 <none> <none>
pod/myweb-rs-hp-7gbv6 0/1 ContainerCreating 0 7s <none> node2 <none> <none>
pod/myweb-rs-hp-gbl7j 0/1 ContainerCreating 0 7s <none> node3 <none> <none>
node1
의 파드는 정상적으로 실행 중이지만 나머지 두 노드는 생성되지 않고 있다.
vagrant@k8s-node1 ~/volume/hostpath kubectl describe po myweb-rs-hp-7gbv6
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 96s default-scheduler Successfully assigned default/myweb-rs-hp-7gbv6 to node2
Warning FailedMount 32s (x8 over 96s) kubelet MountVolume.SetUp failed for volume "web-contents" : hostPath type check failed: /web_contents is not a directory
실행되지 않는 두번째 파드(myweb-rs-hp-7gbv6
)를 살펴보면 kubelet
이 마운트를 할 수 없으며(FailedMount
) /web_contents
는 디렉토리가 아니라는 메세지를 출력한다.
vagrant@k8s-node1 ~/volume/hostpath kubectl describe po myweb-rs-hp-gbl7j
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 3m59s default-scheduler Successfully assigned default/myweb-rs-hp-gbl7j to node3
Warning FailedMount 117s kubelet Unable to attach or mount volumes: unmounted volumes=[web-contents], unattached volumes=[web-contents kube-api-access-sdwjf]: timed out waiting for the condition
Warning FailedMount 112s (x9 over 4m) kubelet MountVolume.SetUp failed for volume "web-contents" : hostPath type check failed: /web_contents is not a directory
세번째 파드(myweb-rs-hp-gbl7j
)를 살펴봐도 동일한 내용을 출력하는 것을 확인할 수 있다.
파드를 만들어지는 순서를 되짚어보자
1. 볼륨을 지정했으므로 해당 볼륨이 있는지 없는지 먼저 체크한다.
2. 볼륨이 정상적으로 있다면 이미지를 pulling한다. 그리고 컨테이너를 생성하고 실행한다.
3. 즉, 파드에서 볼륨을 지정하면 해당 볼륨 유무를 먼저 체크하게 된다.
/web_contents
디렉토리가 있는 노드는 node1
뿐이다.
ReplicaSet
에 의해 3개의 파드가 만들어지고 node1, 2, 3에 고르게 분배됐다고 해보자
오직 node1
에만 연결할 수 있는 볼륨(/web_contents
)이 있고 node2, 3에는 없다.
emptyDir
이나 hostPath
는 로컬 스토리지이다.
즉, 해당 되는 볼륨을 로컬에 있는 파드에게는 제공할 수는 있지만 네트워크를 넘어서 다른 호스트에 접근할 수는 없다. 이것은 네트워크 기반의 스토리지가 아니기 때문이다.
대표적인 네트워크 스토리지인 NFS
는 볼륨이 어딘가에 있더라도 다른 호스트에 제공할 수 있지만 hostPath
는 네트워크 스토리지가 아니다.
vagrant@k8s-node1 ~/volume/hostpath ssh node2 sudo mkdir /web_contents
vagrant@k8s-node1 ~/volume/hostpath ssh node3 sudo mkdir /web_contents
vagrant@k8s-node1 ~/volume/hostpath ssh node2 "echo "Hello hostPath" | sudo tee /web_contents/index.html"
Hello hostPath
vagrant@k8s-node1 ~/volume/hostpath ssh node3 "echo "Hello hostPath" | sudo tee /web_contents/index.html"
Hello hostPath
vagrant@k8s-node1 ~/volume/hostpath kubectl get po
NAME READY STATUS RESTARTS AGE
myweb-rs-hp-5t9zp 1/1 Running 0 12m
myweb-rs-hp-7gbv6 1/1 Running 0 12m
myweb-rs-hp-gbl7j 1/1 Running 0 12m
따라서 각 호스트에 제공할 수 있는 로컬 스토리지를 생성해주면 파드가 Running
상태가 된다.
로컬 스토리지 : 다른 호스트에 스토리지 볼륨을 제공할 수 없다.
emptyDir
hostPath
gitRepo
local
📌 Tip : tee
명령어
root 밑에 파일이나 디렉토리를 만들 수 있는 권한을 가진 것은 root 뿐이다.
vagrant@k8s-node1 ~/volume/hostpath sudo mkdir /a
vagrant@k8s-node1 ~/volume/hostpath echo "hello world" > /a/a.txt
zsh: permission denied: /a/a.txt
파일을 만들려고 하면 permission denied
가 발생한다. root 권한이 필요하다.
vagrant@k8s-node1 ~/volume/hostpath sudo echo "hello world" > /a/a.txt
zsh: permission denied: /a/a.txt
sudo
는 앞의 명령어(echo
)에만 적용되는 것이다.
echo
를 통해 "hello world" 라는 메세지를 /a/a.txt
파일을 생성한 뒤 입력한다.
해당 /a/a.txt
파일을 생성할 때 root 권한이 필요하다.
vagrant@k8s-node1 ~/volume/hostpath sudo echo "hello world" > sudo /a/a.txt
그리고 이러한 명령은 존재하지 않는다.
>
: 리다이렉션 기호는 반드시 명령 >
파일 형식을 지켜야한다.
권한이 없는 디렉토리에 파일을 생성하는 것은 불가능하다.
tee
라는 명령은 cat
과 비슷하며 표준 입력을 표준 출력으로 나타낸다.
vagrant@k8s-node1 ~/volume/hostpath echo "hello world" | sudo tee /a/a.txt
hello world
(|
)을 사용하여 뒤의 명령에 sudo
권한을 부여한다.
'DevOps > Kubernetes' 카테고리의 다른 글
[Kubernetes] 정적 프로비저닝 (Static Provisioning) ( + NFS 정적 프로비저닝) (0) | 2022.05.29 |
---|---|
[Kubernetes] PV(PersistentVolume), PVC(PersistentVolumeClaim) (0) | 2022.05.29 |
[Kubernetes] Readiness Probe (준비성 프로브) (0) | 2022.05.29 |
[Kubernetes] Ingress Challenge (0) | 2022.05.29 |
[Kubernetes] Ingress (인그레스) (0) | 2022.05.29 |
영차영차 성장 블로그
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!