## 양쪽 노드에서 설치 및 확인
kevin@k8s-node1:~$ sudo apt -y install nfs-kernel-server
kevin@k8s-node1:~$ sudo systemctl enable --now nfs-server
kevin@k8s-node1:~$ sudo systemctl status nfs-server
## nfs server(1번)에서만 수행
## /etc/exports 파일은 서버가 클라이언트에 반출하는 모든 디렉토리를 표시한다
kevin@k8s-node1:~$ sudo vi /etc/exports
/data_dir *(rw,sync,no_root_squash,no_subtree_check)
## NFS에서 사용하는 고정포트 2049
kevin@k8s-node1:~$ sudo netstat -nlp | grep 2049
tcp 0 0 0.0.0.0:2049 0.0.0.0:* LISTEN -
## nfs client 설치
## node2에서 수행
kevin@k8s-node2:~$ sudo apt -y install nfs-common
kevin@k8s-node2:~$ sudo mkdir -p /data_dir/nfs
## node1에서 확인
kevin@k8s-node1:~$ sudo systemctl restart nfs-server
kevin@k8s-node1:~$ sudo systemctl status nfs-server
## mount 시키기
kevin@k8s-node2:~$ sudo mount -t nfs k8s-node1:/data_dir /data_dir/nfs
## mount 확인
kevin@k8s-node2:~$ df -h
Filesystem Size Used Avail Use% Mounted on
k8s-node1:/data_dir 66G 13G 53G 20% /data_dir/nfs
...
## node2에 nfs1을 생성한다
kevin@k8s-node2:~$ cd /data_dir/nfs/
kevin@k8s-node2:/data_dir/nfs$ sudo touch nfs1
kevin@k8s-node2:/data_dir/nfs$ ls
k8s-2.txt nfs1
## node1에도 nfs1이 생겼다.
kevin@k8s-node1:~$ cd /data_dir/
kevin@k8s-node1:/data_dir$ ls
k8s-2.txt nfs1
docker container 내부 용량 제한?
default는 unlimit이었다.
--storage-opt size= : container 내부의 / 용량을 잡아주었다.
dd명령 임시 파일 -> fdisk -> mount : mount된 directory 용량 제한
ㄴ OS 의존적이라는 단점이 있다.
=> kubernetes에서는 PV,PVC로 제어할 수 있다.
## mysql-pod describe
kevin@k8s-master:~/LABs$ kubectl describe po mysql-pod
...
Mounts:
/var/lib/mysql from host-path (rw)
...
Volumes:
host-path:
Type: HostPath (bare host directory volume)
Path: /data_dir/mysql-data
...
## /var/lib/mysql이 /와 같은 공간을 차지하고 있다. 제어 필요
## mysql-pod가 만들어진 node2에서 수행
kevin@k8s-node2:~$ sudo su -
root@k8s-node2:~# dd if=/dev/zero of=temphdd.img count=512 bs=1M
root@k8s-node2:~# ls -lh
total 512M
drwx------ 3 root root 24 9월 29 10:49 snap
-rw-r--r-- 1 root root 512M 10월 6 09:27 temphdd.img
## 파일 시스템 붙이기
root@k8s-node2:~# mkfs.xfs temphdd.img
## backup_dir directory 생성해서 mount
root@k8s-node2:~# mkdir /backup_dir
root@k8s-node2:~# mount -o loop temphdd.img /backup_dir
## 확인
root@k8s-node2:~# df -h | grep /backup_dir
/dev/loop11 507M 30M 478M 6% /backup_dir
## 권한 주기
root@k8s-node2:~# chown -R kevin.kevin /backup_dir/
## master에서 수행
## 이동
kevin@k8s-master:~/LABs$ mkdir hostpath
kevin@k8s-master:~/LABs$ cd hostpath/
## yaml 파일 작성
kevin@k8s-master:~/LABs/hostpath$ vi hostpath-2.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-vol5
spec:
nodeSelector:
kubernetes.io/hostname: k8s-node2
containers:
- name: container
image: dbgurum/k8s-lab:initial
volumeMounts:
- name: host-path
mountPath: /backup
volumes:
- name: host-path
hostPath:
path: /backup_dir
type: DirectoryOrCreate
## apply
kevin@k8s-master:~/LABs/hostpath$ kubectl apply -f hostpath-2.yaml
## 확인
kevin@k8s-master:~/LABs/hostpath$ kubectl get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-vol5 1/1 Running 0 4s 10.109.131.62 k8s-node2 <none> <none>
## describe
kevin@k8s-master:~/LABs/hostpath$ kubectl describe po pod-vol5
...
Mounts:
/backup from host-path (rw)
...
Volumes:
host-path:
Type: HostPath (bare host directory volume)
Path: /backup_dir
HostPathType: DirectoryOrCreate
...
## 500M로 용량이 제한되었다.
kevin@k8s-master:~/LABs/hostpath$ kubectl exec -it pod-vol5 -- df -h
Filesystem Size Used Avail Use% Mounted on
/dev/loop11 507M 30M 478M 6% /backup
## Google Cloud SDK Shell에서 실행
C:\k8s>gcloud container clusters list
NAME LOCATION MASTER_VERSION MASTER_IP MACHINE_TYPE NODE_VERSION NUM_NODES STATUS
k8s-cluster asia-northeast3-a 1.22.12-gke.2300 34.64.237.123 e2-medium 1.22.12-gke.2300 3 RUNNING
Updates are available for some Google Cloud CLI components. To install them,
please run:
$ gcloud components update
## 디스크 만들기
C:\k8s>gcloud compute disks create mongo-storage --size=10G --zone=asia-northeast3-a
## 확인
C:\k8s>gcloud compute disks list
NAME LOCATION LOCATION_SCOPE SIZE_GB TYPE STATUS
gke-k8s-cluster-k8s-nodepool-bc541242-jgo3 asia-northeast3-a zone 100 pd-standard READY
gke-k8s-cluster-k8s-nodepool-bc541242-o1ji asia-northeast3-a zone 100 pd-standard READY
gke-k8s-cluster-k8s-nodepool-bc541242-zuc3 asia-northeast3-a zone 100 pd-standard READY
mongo-storage asia-northeast3-a zone 10 pd-standard READY
## yaml 파일 작성
C:\k8s>notepad gce-mongo.yaml
apiVersion: v1
kind: Pod
metadata:
name: gce-mongo-pod
spec:
containers:
- image: mongo
name: mongo-container
volumeMounts:
- name: mongodb-data
mountPath: /data/db
ports:
- containerPort: 27017
protocol: TCP
volumes:
- name: mongodb-data
gcePersistentDisk:
pdName: mongo-storage
fsType: ext4
## apply
C:\k8s>kubectl apply -f gce-mongo.yaml
## 확인
C:\k8s>kubectl get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
gce-mongo-pod 1/1 Running 0 33s 10.12.3.9 gke-k8s-cluster-k8s-nodepool-bc541242-o1ji <none> <none>
## pod describe
C:\k8s>kubectl describe po gce-mongo-pod
...
Mounts:
/data/db from mongodb-data (rw)
...
Volumes:
mongodb-data:
Type: GCEPersistentDisk (a Persistent Disk resource in Google Compute Engine)
PDName: mongodb-storage
FSType: ext4
Partition: 0
ReadOnly: false
...
C:\k8s>kubectl delete -f gce-mongo.yaml
: mongo-sorage가 생성되었다.
: GKE dashboard로도 확인 가능하다.
PV(Persistent Volume)
: 지속적 볼륨, 가상 스토리지 인스턴스(dd)
관리자에 의해서 생성된다.
OS, Cloud 등에서 실제 storage의 물리적 공간(disk)을 활용해서 PV를 만든다.
ㄴ 용량, 권한(AccessModes)을 잘 부여해야 한다.
PVC(Persistent Volume Claim)
: PV를 요청한다.
사용자(개발자)에 의해 PV를 프로비저닝하는 요청이다.
PV를 얼마만큼 어떤 권한으로 쓸지를 요청한다.
ㄴ 용량, 권한을 부여하면 매칭되는 PV에 자동 연결이 된다.
AccessModes
- ReadWriteOnce(RWO) : 하나의 Node가 volume을 RW 가능하도록 mount
- ReadWriteMany(RWX) : 여러 Node가 volume을 RW 가능하도록 mount
- ReadOnlyMany(ROX) : 여러 Node가 volume을 RO 가능하도록 mount
## persistentvolumes v1 확인
kevin@k8s-master:~/LABs/hostpath$ kubectl api-resources | grep -i persis
persistentvolumeclaims pvc v1 true PersistentVolumeClaim
persistentvolumes pv v1 false PersistentVolume
## yaml 파일 작성
kevin@k8s-master:~/LABs$ mkdir pv-pvc && cd $_
kevin@k8s-master:~/LABs/pv-pvc$ vi pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv1
spec:
capacity:
storage: 1G
accessModes:
- ReadWriteOnce
## persistentVolumeReclaimPolicy : pod가 날아가도 데이터가 남아있게 할 것인지
## Retain(남겨놓기), Recycle(안에 있고 재사용), Delete(pv 자체가 사라진다)
persistentVolumeReclaimPolicy: Retain
local:
path: /data_dir
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- {key: kubernetes.io/hostname, operator: In, values: [k8s-node1]}
## yaml 파일 작성
kevin@k8s-master:~/LABs/pv-pvc$ vi pv2.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv2
spec:
capacity:
storage: 1G
accessModes:
- ReadOnlyMany
persistentVolumeReclaimPolicy: Retain
local:
path: /data_dir
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- {key: kubernetes.io/hostname, operator: In, values: [k8s-node1]}
## yaml 파일 작성
kevin@k8s-master:~/LABs/pv-pvc$ vi pv3.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv3
spec:
capacity:
storage: 2G
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
local:
path: /data_dir
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- {key: kubernetes.io/hostname, operator: In, values: [k8s-node1]}
## apply
kevin@k8s-master:~/LABs/pv-pvc$ kubectl apply -f pv.yaml
kevin@k8s-master:~/LABs/pv-pvc$ kubectl apply -f pv2.yaml
kevin@k8s-master:~/LABs/pv-pvc$ kubectl apply -f pv3.yaml
## 확인
kevin@k8s-master:~/LABs/pv-pvc$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv1 1G RWO Retain Available 2m30s
pv2 1G ROX Retain Available 64s
pv3 2G RWX Retain Available 6s
## PVC 생성
## yaml 코드 작성
kevin@k8s-master:~/LABs/pv-pvc$ vi pvc.yaml
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc2
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1G
storageClassName: ""
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc3
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5G
storageClassName: ""
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc4
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1G
storageClassName: ""
## apply
kevin@k8s-master:~/LABs/pv-pvc$ kubectl apply -f pvc.yaml
## 확인 - 용량과 접근방식에 따라 PV를 선택한다
## 조건이 맞지 않으면 pending 상태가 된다.
kevin@k8s-master:~/LABs/pv-pvc$ kubectl get pv,pvc
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/pv1 1G RWO Retain Bound default/pvc2 8m12s
persistentvolume/pv2 1G ROX Retain Bound default/pvc1 6m46s
persistentvolume/pv3 2G RWX Retain Bound default/pvc4 5m48s
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/pvc1 Bound pv2 1G ROX 9s
persistentvolumeclaim/pvc2 Bound pv1 1G RWO 9s
persistentvolumeclaim/pvc3 Pending 9s
persistentvolumeclaim/pvc4 Bound pv3 2G RWX 9s
## PVC가 pod에 붙는다. PV는 pod에 붙지 않는다.
## yaml 파일 작성
kevin@k8s-master:~/LABs/pv-pvc$ vi mynode.yaml
apiVersion: v1
kind: Pod
metadata:
name: mynode-pod
spec:
containers:
- image: dbgurum/mynode:1.0
name: mynode-container
ports:
- containerPort: 8000
volumeMounts:
- name: mynode-path
mountPath: /mynode
volumes:
- name: mynode-path
persistentVolumeClaim:
claimName: pvc1
## apply
kevin@k8s-master:~/LABs/pv-pvc$ kubectl apply -f mynode.yaml
## 확인
kevin@k8s-master:~/LABs/pv-pvc$ kubectl get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
mynode-pod 1/1 Running 0 13s 10.111.156.127 k8s-node1 <none> <none>
## mynode-pod로 들어가기
kevin@k8s-master:~/LABs/pv-pvc$ kubectl exec -it mynode-pod -- bash
## mount 확인
root@mynode-pod:/# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 66G 13G 53G 20% /mynode
...
## mynode-pod에 파일 생성
root@mynode-pod:/# echo 'i love k8s' > /mynode/pvc1.txt
root@mynode-pod:/# ls /mynode/
k8s-2.txt nfs1 pvc1.txt
## node1의 /data_dir에 pvc1.txt가 있다.
kevin@k8s-node1:/data_dir$ ls -l /data_dir/
total 8
-rw-r--r-- 1 root root 11 10월 5 16:45 k8s-2.txt
-rw-r--r-- 1 root root 0 10월 6 09:15 nfs1
-rw-r--r-- 1 root root 11 10월 6 11:19 pvc1.txt
## pvc를 원하는 pv에 붙이기
## yaml 파일 작성
kevin@k8s-master:~/LABs/pv-pvc$ vi pv-pvc-select.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv4
labels:
name: pv4
spec:
capacity:
storage: 1G
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
local:
path: /data_dir
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- {key: kubernetes.io/hostname, operator: In, values: [k8s-node1]}
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc5
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1G
storageClassName: ""
selector:
matchLabels:
name: pv4
## apply
kevin@k8s-master:~/LABs/pv-pvc$ kubectl apply -f pv-pvc-select.yaml
## pv4가 pvc5에 붙었다.
kevin@k8s-master:~/LABs/pv-pvc$ kubectl get pv,pvc
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/pv1 1G RWO Retain Bound default/pvc2 40m
persistentvolume/pv2 1G ROX Retain Bound default/pvc1 39m
persistentvolume/pv3 2G RWX Retain Bound default/pvc4 38m
persistentvolume/pv4 1G RWO Retain Bound default/pvc5 4s
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/pvc1 Bound pv2 1G ROX 32m
persistentvolumeclaim/pvc2 Bound pv1 1G RWO 32m
persistentvolumeclaim/pvc3 Pending 32m
persistentvolumeclaim/pvc4 Bound pv3 2G RWX 32m
persistentvolumeclaim/pvc5 Bound pv4 1G RWO 4s
## yaml 파일 작성
kevin@k8s-master:~/LABs/pv-pvc$ vi nfs-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv
spec:
capacity:
storage: 1G
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
nfs:
path: /data_dir
server: 192.168.56.101
## apply
kevin@k8s-master:~/LABs/pv-pvc$ kubectl apply -f nfs-pv.yaml
## nfs-pv 생성 확인
kevin@k8s-master:~/LABs/pv-pvc$ kubectl get pv,pvc
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/nfs-pv 1G RWO Retain Available 3s
persistentvolume/pv1 1G RWO Retain Bound default/pvc2 44m
persistentvolume/pv2 1G ROX Retain Bound default/pvc1 42m
persistentvolume/pv3 2G RWX Retain Bound default/pvc4 41m
persistentvolume/pv4 1G RWO Retain Bound default/pvc5 3m15s
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/pvc1 Bound pv2 1G ROX 35m
persistentvolumeclaim/pvc2 Bound pv1 1G RWO 35m
persistentvolumeclaim/pvc3 Pending 35m
persistentvolumeclaim/pvc4 Bound pv3 2G RWX 35m
persistentvolumeclaim/pvc5 Bound pv4 1G RWO 3m15s
## 3G로 수정하기
kevin@k8s-master:~/LABs/pv-pvc$ kubectl edit pv pv3
22 storage: 3G
## pv3 CAPACITY가 수정되었다
kevin@k8s-master:~/LABs/pv-pvc$ kubectl get pv,pvc
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/nfs-pv 1G RWO Retain Available 2m52s
persistentvolume/pv1 1G RWO Retain Bound default/pvc2 46m
persistentvolume/pv2 1G ROX Retain Bound default/pvc1 45m
persistentvolume/pv3 3G RWX Retain Bound default/pvc4 44m
persistentvolume/pv4 1G RWO Retain Bound default/pvc5 6m4s
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/pvc1 Bound pv2 1G ROX 38m
persistentvolumeclaim/pvc2 Bound pv1 1G RWO 38m
persistentvolumeclaim/pvc3 Pending 38m
persistentvolumeclaim/pvc4 Bound pv3 2G RWX 38m
persistentvolumeclaim/pvc5 Bound pv4 1G RWO 6m4s
## yaml 파일 작성
kevin@k8s-master:~/LABs/pv-pvc$ vi pv-pvc-pod.yaml
storage: 10G
accessModes:
- ReadWriteOnce
hostPath:
path: "/mnt/data"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-volume
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 3G
---
apiVersion: v1
kind: Pod
metadata:
name: web-pod
spec:
volumes:
- name: web-pv-storage
persistentVolumeClaim:
claimName: pvc-volume
containers:
- name: web-container
image: nginx
ports:
- containerPort: 80
name: "web-server"
volumeMounts:
- mountPath: "/usr/share/nginx/html"
name: web-pv-storage
## apply
kevin@k8s-master:~/LABs/pv-pvc$ kubectl apply -f pv-pvc-pod.yaml
## 확인
kevin@k8s-master:~/LABs/pv-pvc$ kubectl get pv,pvc
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/pv-volume 10G RWO Retain Bound default/pvc-volume manual 7s
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/pvc-volume Bound pv-volume 10G RWO manual 7s
## storage 20G로 수정
kevin@k8s-master:~/LABs/pv-pvc$ kubectl edit pv pv-volume
...
22 - ReadWriteOnce
23 capacity:
24 storage: 20G
## 확인
kevin@k8s-master:~/LABs/pv-pvc$ kubectl get pv,pvc
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/pv-volume 20G RWO Retain Bound default/pvc-volume manual 2m56s
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/pvc-volume Bound pv-volume 10G RWO manual 2m56s
## node1에서 mount 확인
kevin@k8s-node1:/mnt$ cd
kevin@k8s-node1:~$ cd /mnt/data
kevin@k8s-node1:/mnt/data$ ls
## yaml 파일 작성
C:\k8s>notepad pv-pvc-pod.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: mongodb-pv
spec:
capacity:
storage: 1G
accessModes:
- ReadWriteOnce
- ReadOnlyMany
persistentVolumeReclaimPolicy: Retain
gcePersistentDisk:
pdName: mongo-storage
fsType: ext4
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mongodb-pvc
spec:
resources:
requests:
storage: 1G
accessModes:
- ReadWriteOnce
storageClassName: ""
---
apiVersion: v1
kind: Pod
metadata:
name: mongo-pod
spec:
containers:
- image: mongo
name: mongodb
volumeMounts:
- name: mongo-data
mountPath: /data/db
ports:
- containerPort: 27017
protocol: TCP
volumes:
- name: mongo-data
persistentVolumeClaim:
claimName: mongodb-pvc
## apply
C:\k8s>kubectl apply -f pv-pvc-pod.yaml
## 확인
C:\k8s>kubectl get pv,pvc
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/mongodb-pv 1G RWO,ROX Retain Bound default/mongodb-pvc 12s
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/mongodb-pvc Bound mongodb-pv 1G RWO,ROX 12s
C:\k8s>kubectl delete -f pv-pvc-pod.yaml
https://github.com/soyeonnn/whatisyourmotto.git
## 이동
kevin@k8s-master:~/LABs$ mkdir gitrepo && cd $_
## yaml 파일 작성
kevin@k8s-master:~/LABs/gitrepo$ vi gitrepo.yaml
apiVersion: v1
kind: Pod
metadata:
name: gitrepo-pod
labels:
app: motto
spec:
containers:
- image: nginx:1.23.1-alpine
name: web-container
volumeMounts:
- name: gitrepo
mountPath: /usr/share/nginx/html
volumes:
- name: gitrepo
gitRepo:
repository: https://github.com/soyeonnn/whatisyourmotto.git
revision: main
directory: .
## apply
kevin@k8s-master:~/LABs/gitrepo$ kubectl apply -f gitrepo.yaml
## git에서 수정해도 그게 반영되지 않는다. => deprecated
## 확인
kevin@k8s-master:~/LABs/gitrepo$ kubectl get po -o wide | grep git
gitrepo-pod 1/1 Running 0 47s 10.111.156.65 k8s-node1 <none> <none>
kevin@k8s-master:~/LABs/gitrepo$ kubectl describe po gitrepo-pod
...
Mounts:
/usr/share/nginx/html from gitrepo (rw)
...
Volumes:
gitrepo:
Type: GitRepo (a volume that is pulled from git when the pod is created)
Repository: https://github.com/soyeonnn/whatisyourmotto.git
Revision: main
...
## 접속 확인
kevin@k8s-master:~/LABs/gitrepo$ curl 10.111.156.65
## yaml 파일 작성
kevin@k8s-master:~/LABs/gitrepo$ vi gitrepo-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: gitrepo-svc
spec:
selector:
app: motto
ports:
- port: 10080
targetPort: 80
nodePort: 30080
type: NodePort
## apply
kevin@k8s-master:~/LABs/gitrepo$ kubectl apply -f gitrepo-svc.yaml
## 확인
kevin@k8s-master:~/LABs/gitrepo$ kubectl get po,svc -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/gitrepo-pod 1/1 Running 0 5m43s 10.111.156.65 k8s-node1 <none> <none>
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
service/gitrepo-svc NodePort 10.101.32.165 <none> 10080:30080/TCP 53s app=motto
## windows에서 http://192.168.56.101:30080/ 접속해서 확인
## node1에 접속
kevin@k8s-node1:~$ sudo su -
## mount한 volume 이름으로 찾기
root@k8s-node1:~# find / -name gitrepo
/var/lib/kubelet/pods/6d7d39e6-b811-4078-9493-b3d503b19cd3/volumes/kubernetes.io~git-repo/gitrepo
/var/lib/kubelet/pods/6d7d39e6-b811-4078-9493-b3d503b19cd3/plugins/kubernetes.io~git-repo/gitrepo
find: ‘/run/user/1000/gvfs’: Permission denied
find: ‘/run/user/125/gvfs’: Permission denied
## 이동
root@k8s-node1:~# cd /var/lib/kubelet/pods/6d7d39e6-b811-4078-9493-b3d503b19cd3/volumes/kubernetes.io~git-repo/gitrepo
## git clone data 확인
root@k8s-node1:/var/lib/kubelet/pods/6d7d39e6-b811-4078-9493-b3d503b19cd3/volumes/kubernetes.io~git-repo/gitrepo# ls
assets css index.html js
## 삭제
C:\k8s>gcloud compute disks delete mongo-storage --zone asia-northeast3-a
## 확인
C:\k8s>gcloud compute disks list
NAME LOCATION LOCATION_SCOPE SIZE_GB TYPE STATUS
gke-k8s-cluster-k8s-nodepool-bc541242-jgo3 asia-northeast3-a zone 100 pd-standard READY
gke-k8s-cluster-k8s-nodepool-bc541242-o1ji asia-northeast3-a zone 100 pd-standard READY
gke-k8s-cluster-k8s-nodepool-bc541242-zuc3 asia-northeast3-a zone 100 pd-standard READY
: key:value 구조의 데이터(환경변수, 명령의 인수(args), 구성 파일(*.conf, nginx.conf))를 저장한다.
kevin@k8s-master:~$ kubectl api-resources | grep -i configmap
configmaps cm v1 true ConfigMap
kubectl create configmap
--from-literal=key=value | --from-literal key=value
--from-file=[file_name] | --from-file [file_name]
## configmap 생성
kevin@k8s-master:~/LABs$ kubectl create configmap log-level-cm --from-literal=LOG_LEVEL=DEBUG
## 생성 확인
kevin@k8s-master:~/LABs$ kubectl get cm
NAME DATA AGE
kube-root-ca.crt 1 7d
log-level-cm 1 14s
kevin@k8s-master:~/LABs$ kubectl describe cm log-level-cm
...
LOG_LEVEL:
----
DEBUG
...
## yaml 파일 확인
kevin@k8s-master:~/LABs$ kubectl get cm log-level-cm -o yaml
apiVersion: v1
data:
LOG_LEVEL: DEBUG
kind: ConfigMap
metadata:
creationTimestamp: "2022-10-06T05:16:09Z"
name: log-level-cm
namespace: default
resourceVersion: "221429"
uid: fb035262-a5e2-445e-990c-f90b072a7ac9
## configmap 생성
kevin@k8s-master:~/LABs$ kubectl create cm env-cm --from-literal=key1=value1 --from-literal=key2=value2
## 확인
kevin@k8s-master:~/LABs$ kubectl describe cm env-cm
...
Data
====
key1:
----
value1
key2:
----
value2
...
## conf 파일 작성
kevin@k8s-master:~/LABs$ vi redis.conf
key1=kubernetes
key2=docker
key3=linux
key4=gke
## 파일로 configmap 생성
kevin@k8s-master:~/LABs$ kubectl create cm redis-cm --from-file=redis.conf
## 확인
kevin@k8s-master:~/LABs$ kubectl get cm
NAME DATA AGE
env-cm 2 2m48s
kube-root-ca.crt 1 7d
log-level-cm 1 16m
redis-cm 1 8s
## 확인
kevin@k8s-master:~/LABs$ kubectl describe cm redis-cm
...
Data
====
redis.conf:
----
key1=kubernetes
key2=docker
key3=linux
key4=gke
...
## --dry-run 붙여서 configmap 생성
kevin@k8s-master:~/LABs$ kubectl create configmap my-pwd --from-literal=mypwd=k8spass# --dry-run=client -o yaml > my-pwd.yaml
## yaml 파일 확인
kevin@k8s-master:~/LABs$ cat my-pwd.yaml
apiVersion: v1
data:
mypwd: k8spass#
kind: ConfigMap
metadata:
creationTimestamp: null
name: my-pwd
위에서 만든 configmap을 pod에 참조시킨다.
1. 환경변수로 넣기
## yaml 파일 작성
kevin@k8s-master:~/LABs$ vi cm-pod1.yaml
apiVersion: v1
kind: Pod
metadata:
name: log-level-pod
spec:
containers:
- image: nginx:1.23.1-alpine
name: log-level-container
envFrom:
- configMapRef:
name: log-level-cm
## apply
kevin@k8s-master:~/LABs$ kubectl apply -f cm-pod1.yaml
## 확인
kevin@k8s-master:~/LABs$ kubectl get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
log-level-pod 1/1 Running 0 5s 10.111.156.67 k8s-node1 <none> <none>
## pod 속에 환경변수로 들어가있는지 확인한다
kevin@k8s-master:~/LABs$ kubectl exec -it log-level-pod -- env
...
LOG_LEVEL=DEBUG
...
## yaml 파일 작성
kevin@k8s-master:~/LABs$ vi cm-pod2.yaml
apiVersion: v1
kind: Pod
metadata:
name: log-level-pod2
spec:
containers:
- image: nginx:1.23.1-alpine
name: log-level-container
volumeMounts:
- name: cm-volume
mountPath: /etc/config
volumes:
- name: cm-volume
configMap:
name: log-level-cm
## apply
kevin@k8s-master:~/LABs$ kubectl apply -f cm-pod2.yaml
## 확인
kevin@k8s-master:~/LABs$ kubectl get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
log-level-pod2 1/1 Running 0 19s 10.109.131.63 k8s-node2 <none> <none>
## pod 속에서 확인
kevin@k8s-master:~/LABs$ kubectl exec -it log-level-pod2 -- ls /etc/config
LOG_LEVEL
kevin@k8s-master:~/LABs$ kubectl exec -it log-level-pod2 -- cat /etc/config/LOG_LEVEL
DEBUG
## redis pod yaml 파일 작성
kevin@k8s-master:~/LABs$ vi redis-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: redis-cm-pod
spec:
containers:
- image: redis
name: redis-container
volumeMounts:
- name: redis-volume
mountPath: /opt/redis-config
volumes:
- name: redis-volume
configMap:
name: redis-cm
## apply
kevin@k8s-master:~/LABs$ kubectl apply -f redis-pod.yaml
## 확인
kevin@k8s-master:~/LABs$ kubectl get po
NAME READY STATUS RESTARTS AGE
redis-cm-pod 1/1 Running 0 15s
## pod 속에 파일이 있는지 확인
kevin@k8s-master:~/LABs$ kubectl exec -it redis-cm-pod -- cat /opt/redis-config/redis.conf
key1=kubernetes
key2=docker
key3=linux
key4=gke
key:value 구조의 데이터(암호, 기밀데이터)를 저장한다.
암호화는 하지 않고, encoding(base64)을 한다.
-> MYSQL_ROOT_PASSWORD, openssl -> *.crt -> https(tls)
kevin@k8s-master:~$ kubectl api-resources | grep -i secret
secrets v1 true Secret
## secret 생성
kevin@k8s-master:~/LABs$ kubectl create secret generic my-pwd --from-literal=mypwd=k8spass#
## 확인
kevin@k8s-master:~/LABs$ kubectl describe secrets my-pwd
Type: Opaque
## encoding 되어 저장되어 있다
kevin@k8s-master:~/LABs$ kubectl get secret -o yaml
mypwd: azhzcGFzcyM=
## decoding 해보기
kevin@k8s-master:~/LABs$ echo azhzcGFzcyM= | base64 -d
k8spass#
## secret 2개 생성
kevin@k8s-master:~/LABs/cmsecret$ kubectl create secret generic mysecret --from-literal=user_name=myuser \
> --from-literal=password=mypassword
## 확인
kevin@k8s-master:~/LABs/cmsecret$ kubectl get secrets
NAME TYPE DATA AGE
mysecret Opaque 2 8s
kevin@k8s-master:~/LABs/cmsecret$ kubectl describe secrets mysecret
Type: Opaque
위에서 만든 secret을 pod에 참조시킨다.
1. 환경변수로 넣기
## yaml 파일 작성
k8spass#kevin@k8s-master:~/LABs$ vi sec-pod-1.yaml
apiVersion: v1
kind: Pod
metadata:
name: sec-pod
spec:
containers:
- image: nginx:1.23.1-alpine
name: sec-container
envFrom:
- secretRef:
name: my-pwd
## apply
kevin@k8s-master:~/LABs$ kubectl apply -f sec-pod-1.yaml
## 확인
kevin@k8s-master:~/LABs$ kubectl get pod
NAME READY STATUS RESTARTS AGE
sec-pod 1/1 Running 0 33s
## decoding 되어서 환경변수로 저장되어 있다
kevin@k8s-master:~/LABs$ kubectl exec -it sec-pod -- env
mypwd=k8spass#
## yaml 파일 작성
kevin@k8s-master:~/LABs$ vi sec-pod-2.yaml
apiVersion: v1
kind: Pod
metadata:
name: sec-pod2
spec:
containers:
- image: redis
name: redis-container
volumeMounts:
- name: redis-volume
mountPath: /opt/redis-config
volumes:
- name: redis-volume
secret:
secretName: my-pwd
## apply
kevin@k8s-master:~/LABs$ kubectl apply -f sec-pod-2.yaml
## 확인
kevin@k8s-master:~/LABs$ kubectl get po
NAME READY STATUS RESTARTS AGE
sec-pod2 1/1 Running 0 12s
## pod 안에서 확인
kevin@k8s-master:~/LABs$ kubectl exec -it sec-pod2 -- ls /opt/redis-config
mypwd
kevin@k8s-master:~/LABs$ kubectl exec -it sec-pod2 -- cat /opt/redis-config/mypwd
k8spass#
## pod yaml 파일 작성
kevin@k8s-master:~/LABs$ vi nginx-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod93
spec:
containers:
- image: nginx
name: nginx-pod93
env:
- name: USER_NAME
valueFrom:
secretKeyRef:
name: mysecret
key: user_name
## apply
kevin@k8s-master:~/LABs$ kubectl apply -f nginx-pod.yaml
## 확인
kevin@k8s-master:~/LABs$ kubectl get po
NAME READY STATUS RESTARTS AGE
nginx-pod93 1/1 Running 0 12s
## user_name만 환경변수로 들어오고, password는 들어오지 않는다
kevin@k8s-master:~/LABs$ kubectl exec -it nginx-pod93 -- env
USER_NAME=myuser
Ambassador 설계 패턴
pod 속에 porxy container가 존재한다.
proxy는 toss 역할과 캐시로 저장하는 역할을 한다.
## 이동 kevin@k8s-master:~/LABs$ mkdir ambassador kevin@k8s-master:~/LABs$ cd ambassador/ ## configmap yaml 파일 작성 kevin@k8s-master:~/LABs/ambassador$ vi flaskapp-conf.yaml apiVersion: v1 kind: ConfigMap metadata: name: nginx-conf data: nginx.conf: |- user nginx; worker_processes 1; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; upstream flaskapp { server localhost:9000; } server { listen 80; location / { proxy_pass http://flaskapp; proxy_redirect off; } } } ## pod yaml 파일 작성 kevin@k8s-master:~/LABs/ambassador$ vi flaskapp-pod.yaml apiVersion: v1 kind: Pod metadata: name: flaskapp-pod labels: app: flaskapp spec: containers: - image: nginx:1.21-alpine name: proxy-container volumeMounts: - name: nginx-proxy-config mountPath: /etc/nginx/nginx.conf subPath: nginx.conf ports: - containerPort: 80 protocol : TCP - image: oeckikekk/py_flask:1.0 name: flaskapp-container ports: - containerPort: 9000 protocol: TCP volumes: - name: nginx-proxy-config configMap: name: nginx-conf ## service yaml 파일 작성 kevin@k8s-master:~/LABs/ambassador$ vi flaskapp-svc.yaml apiVersion: v1 kind: Service metadata: name: flaskapp-svc spec: selector: app: flaskapp ports: - protocol: TCP port: 80 targetPort: 80 nodePort: 31111 type: NodePort ## apply kevin@k8s-master:~/LABs/ambassador$ kubectl apply -f flaskapp-conf.yaml kevin@k8s-master:~/LABs/ambassador$ kubectl apply -f flaskapp-pod.yaml kevin@k8s-master:~/LABs/ambassador$ kubectl apply -f flaskapp-svc.yaml ## configmap 확인 kevin@k8s-master:~/LABs/ambassador$ kubectl get cm nginx-conf 1 80s ## pod, service 확인 kevin@k8s-master:~/LABs/ambassador$ kubectl get po,svc -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod/flaskapp-pod 2/2 Running 0 98s 10.109.131.2 k8s-node2 <none> <none> NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR service/flaskapp-svc NodePort 10.111.55.47 <none> 80:31111/TCP 71s app=flaskapp ## windows에서 http://192.168.56.102:31111/ 접속해서 확인
## 이동
kevin@k8s-master:~/LABs$ mkdir cmsecret
kevin@k8s-master:~/LABs$ cd cmsecret/
## configmap yaml 파일 작성
kevin@k8s-master:~/LABs/cmsecret$ vi cm-lab.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: cm-dev
data:
SSH: 'false'
User: kevin
## secret yaml 파일 작성
kevin@k8s-master:~/LABs/cmsecret$ vi sec-lab.yaml
apiVersion: v1
kind: Secret
metadata:
name: sec-dev
data:
key: YnJhdm9teWxpZmU=
## pod yaml 파일 작성
kevin@k8s-master:~/LABs/cmsecret$ vi cm-sec-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: cm-sec-pod
spec:
containers:
- name: cm-sec-container
image: dbgurum/k8s-lab:initial
envFrom:
- configMapRef:
name: cm-dev
- secretRef:
name: sec-dev
## apply
kevin@k8s-master:~/LABs/cmsecret$ kubectl apply -f cm-lab.yaml
kevin@k8s-master:~/LABs/cmsecret$ kubectl apply -f sec-lab.yaml
kevin@k8s-master:~/LABs/cmsecret$ kubectl apply -f cm-sec-pod.yaml
## configmap 확인
kevin@k8s-master:~/LABs/cmsecret$ kubectl get cm
NAME DATA AGE
cm-dev 2 24s
## configmap describe
kevin@k8s-master:~/LABs/cmsecret$ kubectl describe cm cm-dev
...
Data
====
SSH:
----
false
User:
----
kevin
...
## secret describe
kevin@k8s-master:~/LABs/cmsecret$ kubectl describe secrets sec-dev
Type: Opaque
## decoding 되어서 나온다
kevin@k8s-master:~/LABs/cmsecret$ kubectl exec -it cm-sec-pod -- env
User=kevin
key=bravomylife
SSH=false
## 파일로 만들기
kevin@k8s-master:~/LABs$ echo 'k8s-account' > k8s-account.txt
kevin@k8s-master:~/LABs$ echo 'k8spass#' > k8s-pwd.txt
## secret 생성
kevin@k8s-master:~/LABs$ kubectl create secret generic account-pwd-secret \
> --from-file=k8s-account.txt --from-file=k8s-pwd.txt
## deployment yaml 파일 생성
kevin@k8s-master:~/LABs$ vi sec-depl.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-deploy
labels:
app: src-app
spec:
replicas: 2
selector:
matchLabels:
app: sec-app
template:
metadata:
labels:
app: sec-app
spec:
containers:
- name: testapp
image: dbgurum/k8s-lab:secret-1.0
ports:
- containerPort: 8080
env:
- name: SECRET_USERNAME
valueFrom:
secretKeyRef:
name: account-pwd-secret
key: k8s-account.txt
- name: SECRET_PASSWORD
valueFrom:
secretKeyRef:
name: account-pwd-secret
key: k8s-pwd.txt
## service yaml 파일 생성
kevin@k8s-master:~/LABs$ vi sec-svc.yaml
apiVersion: v1
kind: Service
metadata:
labels:
app: sec-app
name: web-deploy-svc
spec:
ports:
- nodePort: 30303
port: 8000
protocol: TCP
targetPort: 8080
selector:
app: sec-app
type: NodePort
## apply
kevin@k8s-master:~/LABs$ kubectl apply -f sec-depl.yaml
kevin@k8s-master:~/LABs$ kubectl apply -f sec-svc.yaml
## 확인
kevin@k8s-master:~/LABs$ kubectl get deploy,po,svc -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
deployment.apps/web-deploy 2/2 2 2 17s testapp dbgurum/k8s-lab:secret-1.0 app=sec-app
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/web-deploy-595d4d579d-7nvpx 1/1 Running 0 17s 10.109.131.4 k8s-node2 <none> <none>
pod/web-deploy-595d4d579d-x2q6n 1/1 Running 0 17s 10.111.156.69 k8s-node1 <none> <none>
service/web-deploy-svc NodePort 10.109.225.8 <none> 8000:30303/TCP 12s app=sec-app
## 연결해서 확인
kevin@k8s-master:~/LABs$ curl 192.168.56.101:30303/env
... "SECRET_USERNAME=k8s-account\n","SECRET_PASSWORD=k8spass#\n" ...