watch -d 'kubectl get pod'
watch -d 'docker ps --format "table {{.Image}}\t{{.Status}}\t{{.Names}}"'
cat <<EOF > myweb.yaml
apiVersion: v1
kind: Pod
metadata:
name: myweb
spec:
containers:
- image: nginx:latest
name: myweb-container
ports:
- containerPort: 80
protocol: TCP
EOF
kubectl apply -f myweb.yaml
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
myweb 1/1 Running 0 7m19s 172.16.235.137 worker1 <none> <none>
watch 명령어 혹은 옵션을 통해 아래와 같이 상태 변화를 실시간으로 확인할 수 있다
[root@master aiden (⎈ |kube:default)]# ping 172.16.235.137
PING 172.16.235.137 (172.16.235.137) 56(84) bytes of data.
64 bytes from 172.16.235.137: icmp_seq=1 ttl=63 time=0.175 ms
64 bytes from 172.16.235.137: icmp_seq=2 ttl=63 time=0.174 ms
^C
--- 172.16.235.137 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1022ms
rtt min/avg/max/mdev = 0.174/0.174/0.175/0.000 ms
[root@master aiden (⎈ |kube:default)]# curl 172.16.235.137
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
... 생략 ...
kubectl delete pod myweb
사이드카 패턴은 어플리케이션 컨테이너와 독립적으로 동작하는 별도의 컨테이너를 붙이는 패턴이다. 사이드카는 상위 애플리케이션에 연결되고 애플리케이션에 대한 지원 기능을 제공한다. 사이드카 장애 시 어플리케이션이 영향을 받지 않는다.
myweb2 Pod 안에 2개의 컨테이너가 동작
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: **myweb2**
spec:
**containers**:
- name: **myweb2-nginx**
image: nginx
ports:
- containerPort: 80
protocol: TCP
- name: **myweb2-netshoot**
image: nicolaka/netshoot
command: ["/bin/bash"]
args: ["-c", "while true; do sleep 5; curl localhost; done"] # Pod가 종료되지 않도록 유지
EOF
[root@master aiden (⎈ |kube:default)]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
myweb2 2/2 Running 0 4h52m 172.16.235.138 worker1 <none> <none>
[root@master aiden (⎈ |kube:default)]# kubectl describe pod myweb2
... 생략 ...
myweb2-nginx:
Container ID: docker://1c6c7938e5d6b7c62c2cbfffd2c07ffca0fcdf430f2518025189432e34522133
Image: nginx
Image ID: docker-pullable://nginx@sha256:47ae43cdfc7064d28800bc42e79a429540c7c80168e8c8952778c0d5af1c09db
... 생략 ...
myweb2-netshoot:
Container ID: docker://ad902b7db93c3875600414e3182652aaa565d73136c307f949cb009318e1ff3a
Image: nicolaka/netshoot
Image ID: docker-pullable://nicolaka/netshoot@sha256:85ce79b823f8bdece01aaacb46ad5d01040f4b8544000d850fe03
... 생략 ...
root@worker1:~# docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Names}}" | grep myweb2
1c6c7938e5d6 nginx k8s_myweb2-nginx_myweb2_default_d0ae07e5-7c0b-4143-8dad-e67d29dcaf8f_0
ad902b7db93c nicolaka/netshoot k8s_myweb2-netshoot_myweb2_default_d0ae07e5-7c0b-4143-8dad-e67d29dcaf8f_0
e8d8f8fee19c k8s.gcr.io/pause:3.4.1 k8s_POD_myweb2_default_d0ae07e5-7c0b-4143-8dad-e67d29dcaf8f_0
⇒ 내부 컨테이너가 pause 컨테이너의 network namespace를 공유
[root@master aiden (⎈ |kube:default)]# kubectl logs -f myweb2 -c myweb2-nginx
... 생략 ...
127.0.0.1 - - [27/Jun/2021:03:59:34 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.77.0" "-"
127.0.0.1 - - [27/Jun/2021:03:59:39 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.77.0" "-"
127.0.0.1 - - [27/Jun/2021:03:59:44 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.77.0" "-"
... 생략 ...
⇒ myweb2-netshoot으로 부터 요청이 왔으며 IP는 127.0.0.1 이다.
kubectl exec -it myweb2 -c myweb2-netshoot -- /bin/bash
bash-5.1# curl -s localhost | grep nginx
<title>Welcome to nginx!</title>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
<a href="http://nginx.org/">nginx.org</a>.<br/>
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
bash-5.1# ip a
... 생략 ...
4: eth0@if15: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1480 qdisc noqueue state UP group default
link/ether ae:2c:04:99:5e:ae brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.16.235.138/32 brd 172.16.235.138 scope global eth0
valid_lft forever preferred_lft forever
kubectl exec -it myweb2 -c myweb2-nginx -- /bin/bash
apt update
apt install -y procps net-tools
root@myweb2:/# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1480
inet 172.16.235.138 netmask 255.255.255.255 broadcast 172.16.235.138
ether ae:2c:04:99:5e:ae txqueuelen 0 (Ethernet)
RX packets 6321 bytes 9712504 (9.2 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 3789 bytes 252598 (246.6 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
... 생략 ...
root@myweb2:/# netstat -tnlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 1/nginx: master pro
tcp6 0 0 :::80 :::* LISTEN 1/nginx: master pro
⇒ TCP 80 Listen 상태
kubectl delete pod --all
Labeling
시스템을 이용리소스
에 key-value
형식의 태그정보(Label)
을 붙임셀렉터
라는 것을 이용하여 특정 key-value 를 가진 리소스만 추출
할 수 있음cat <<EOF > labels.yaml
apiVersion: v1
kind: Pod
metadata:
name: myweb1
labels:
environment: production
app: nginx
spec:
containers:
- image: nginx
name: myweb1
ports:
- containerPort: 80
protocol: TCP
---
apiVersion: v1
kind: Pod
metadata:
name: myweb2
labels:
environment: dev
app: nginx
spec:
containers:
- image: nginx
name: myweb2
ports:
- containerPort: 80
EOF
kubectl apply -f labels.yaml
[root@master aiden (⎈ |kube:default)]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myweb1 1/1 Running 0 31s
myweb2 1/1 Running 0 31s
[root@master aiden (⎈ |kube:default)]# kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
myweb1 1/1 Running 0 48s app=nginx,environment=production
myweb2 1/1 Running 0 48s app=nginx,environment=dev
[root@master aiden (⎈ |kube:default)]# kubectl get pod -l environment=production
NAME READY STATUS RESTARTS AGE
myweb1 1/1 Running 0 81s
[root@master aiden (⎈ |kube:default)]# kubectl get pod -l app=nginx
NAME READY STATUS RESTARTS AGE
myweb1 1/1 Running 0 94s
myweb2 1/1 Running 0 94s
[root@master aiden (⎈ |kube:default)]# kubectl delete pod -l environment=production
pod "myweb1" deleted
[root@master aiden (⎈ |kube:default)]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myweb2 1/1 Running 0 2m26s
[root@master aiden (⎈ |kube:default)]# kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
myweb2 1/1 Running 0 3m41s app=nginx,environment=dev
[root@master aiden (⎈ |kube:default)]# kubectl label pod myweb2 app-
pod/myweb2 labeled
[root@master aiden (⎈ |kube:default)]# kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
myweb2 1/1 Running 0 4m18s environment=dev
[root@master aiden (⎈ |kube:default)]# kubectl get node --show-labels
NAME STATUS ROLES AGE VERSION LABELS
master Ready control-plane,master 11d v1.21.1 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=master,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node-role.kubernetes.io/master=,node.kubernetes.io/exclude-from-external-load-balancers=
worker1 Ready <none> 11d v1.21.1 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=worker1,kubernetes.io/os=linux
worker2 Ready <none> 11d v1.21.1 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=worker2,kubernetes.io/os=linux
worker3 Ready <none> 11d v1.21.1 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=worker3,kubernetes.io/os=linux
[root@master aiden (⎈ |kube:default)]# kubectl label node worker1 gpu=ndivia
node/worker1 labeled
[root@master aiden (⎈ |kube:default)]# kubectl get node --show-labels
NAME STATUS ROLES AGE VERSION LABELS
master Ready control-plane,master 11d v1.21.1 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=master,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node-role.kubernetes.io/master=,node.kubernetes.io/exclude-from-external-load-balancers=
worker1 Ready <none> 11d v1.21.1 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,gpu=ndivia,kubernetes.io/arch=amd64,kubernetes.io/hostname=worker1,kubernetes.io/os=linux
worker2 Ready <none> 11d v1.21.1 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=worker2,kubernetes.io/os=linux
worker3 Ready <none> 11d v1.21.1 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=worker3,kubernetes.io/os=linux
labels-node.yaml
cat <<EOF > labels-node.yaml
apiVersion: v1
kind: Pod
metadata:
name: myweb
spec:
containers:
- image: nginx
name: myweb
ports:
- containerPort: 80
protocol: TCP
**nodeSelector:
gpu: ndivia
EOF**
Pod 배포 / 확인
[root@master aiden (⎈ |kube:default)]# kubectl apply -f labels-node.yaml
pod/myweb created
[root@master aiden (⎈ |kube:default)]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
myweb 1/1 Running 0 45s 172.16.235.140 worker1 <none> <none>
깉은 YAML 템플릿을 이용하여 Pod 3개 더 생성
cat labels-node.yaml | sed "s/name: myweb/name: myweb2/g" | kubectl apply -f -
cat labels-node.yaml | sed "s/name: myweb/name: myweb3/g" | kubectl apply -f -
cat labels-node.yaml | sed "s/name: myweb/name: myweb4/g" | kubectl apply -f -
Pod 확인
[root@master aiden (⎈ |kube:default)]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
myweb 1/1 Running 0 2m30s 172.16.235.140 worker1 <none> <none>
myweb2 1/1 Running 0 33s 172.16.235.141 worker1 <none> <none>
myweb3 1/1 Running 0 33s 172.16.235.142 worker1 <none> <none>
myweb4 1/1 Running 0 30s 172.16.235.143 worker1 <none> <none>
⇒ nodeSelector를 통해 특정 노드를 선택하여 생성하였으므로, 다른 워커노드에 분산 배치되지 않음
파드 생성 시 Command(도커의 Entrypoint)와 Args(도커의 Cmd)를 전달할 수 있다
nginx Pod 생성 및 확인
[root@master aiden (⎈ |kube:default)]# kubectl run cmd-args --image nginx
pod/cmd-args created
[root@master aiden (⎈ |kube:default)]# kubectl get pod -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
cmd-args 1/1 Running 0 10s 172.16.235.144 worker1 <none> <none>
워커노드에서 컨테이너 상세 정보 확인
root@worker1:~# docker inspect `docker ps | grep cmd-args | awk '{print $1}'`
... 생략 ...
"Cmd": [
"nginx",
"-g",
"daemon off;"
],
"Healthcheck": {
"Test": [
"NONE"
]
},
"Image": "nginx@sha256:47ae43cdfc7064d28800bc42e79a429540c7c80168e8c8952778c0d5af1c09db",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": [
"/docker-entrypoint.sh"
],
... 생략 ...
cmd-args.yaml
cat << EOF > cmd-args.yaml
apiVersion: v1
kind: Pod
metadata:
name: cmd-args
spec:
restartPolicy: OnFailure
containers:
- image: nginx
name: cmd-args-nginx
ports:
- containerPort: 80
protocol: TCP
command: ["/bin/echo"]
args: ["hello"]
EOF
Pod 생성 및 확인
[root@master aiden (⎈ |kube:default)]# kubectl apply -f cmd-args.yaml
pod/cmd-args created
[root@master aiden (⎈ |kube:default)]# kubectl get pod -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
cmd-args 0/1 Completed 0 12s 172.16.235.145 worker1 <none> <none>
log 확인
[root@master aiden (⎈ |kube:default)]# kubectl logs cmd-args
hello
워커노드에서 컨테이너 정보 확인
root@worker1:~# docker inspect 27f58219cffa
... 생략 ...
"Cmd": [
"hello"
],
"Healthcheck": {
"Test": [
"NONE"
]
},
"Image": "nginx@sha256:47ae43cdfc7064d28800bc42e79a429540c7c80168e8c8952778c0d5af1c09db",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": [
"/bin/echo"
],
... 생략 ...
JWT Secret Key / DB 접속정보(IP, Database 명, ID, PW) 등 Pod에 환경변수 전달 시 사용
env.yaml
cat <<EOF > env.yaml
apiVersion: v1
kind: Pod
metadata:
name: mynginx
spec:
containers:
- image: nginx:latest
name: mynginx
ports:
- containerPort: 80
env:
- name: MYPASSWORD
value: QWE123
EOF
Pod 생성 및 확인
[root@master aiden (⎈ |kube:default)]# kubectl apply -f env.yaml
pod/mynginx created
[root@master aiden (⎈ |kube:default)]# kubectl exec mynginx -- env | grep MYPASSWORD
MYPASSWORD=QWE123
워커 노드에서 확인
root@worker1:~# docker inspect `docker ps | grep nginx | grep -v pause | awk '{print $1}'` --format '{{.Config.Env}}'
[MYPASSWORD=QWE123 KUBERNETES_PORT_443_TCP_PROTO=tcp KUBERNETES_PORT_443_TCP_PORT=443 KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1 KUBERNETES_SERVICE_HOST=10.96.0.1 KUBERNETES_SERVICE_PORT=443 KUBERNETES_SERVICE_PORT_HTTPS=443 KUBERNETES_PORT=tcp://10.96.0.1:443 KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443 PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin NGINX_VERSION=1.21.0 NJS_VERSION=0.5.3 PKG_RELEASE=1~buster]
⇒ 중요한 정보일 경우 보안관리가 필요
파드 내부 스토리지는 파드가 삭제 시 저장된 데이터도 삭제된다
파드 데이터를 지속적으로 저정하기 위해서는 볼륨을 사용해야 한다
hostPath : 워커 노드의 로컬 디렉터리를 공유해서 볼륨으로 사용
emptyDir : 파드가 실행되는 도중에만 필요한 데이터를 멀티 컨테이너가 함께 사용할 수 있도록 임시 저장 공간을 생성
그외 어느 노드에서도 접근해 사용할 수 있는 퍼시스턴트 볼륨(Persistent Volume)
****있다
hostpath.yaml
cat <<EOF > hostpath.yaml
apiVersion: v1
kind: Pod
metadata:
name: hostpath
spec:
containers:
- name: hostpath
image: busybox
args: [ "tail", "-f", "/dev/null" ]
volumeMounts:
- name: hostpath-volume
mountPath: /etc/data
volumes:
- name: hostpath-volume
hostPath:
path: /cndk
EOF
Pod 생성 및 확인
[root@master aiden (⎈ |kube:default)]# kubectl apply -f hostpath.yaml && watch "kubectl describe pod hostpath | grep Events -A 12"
pod/hostpath created
워커노드에서 디렉토리 확인
root@worker1:~# ls /
bin cdrom dev home lib32 libx32 media opt root sbin srv sys usr
boot cndk etc lib lib64 lost+found mnt proc run snap swap.img tmp var
⇒ cndk 생성 확인
Pod에 파일 생성
[root@master aiden (⎈ |kube:default)]# kubectl exec hostpath -- touch /etc/data/test.txt
워커노드에서 확인
root@worker1:~# ls /cndk
test.txt