레이블이 top인 게시물을 표시합니다. 모든 게시물 표시
레이블이 top인 게시물을 표시합니다. 모든 게시물 표시

kubectl top node error

# 설치
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

# node 를 조회하면 다음 에러가 발생한다.(kubectl top pods 는 정상동작)
kubectl top node
error: metrics not available yet

# kube-system > metrics-server deployment 가 제대로 동작하고 있지 않았다.
kubectl get deployment metrics-server -n kube-system
NAME             READY   UP-TO-DATE   AVAILABLE   AGE
metrics-server   0/1     1            0           26h

# 이슈1 - 이미지 다운로드 실패
# 원인은 registry.k8s.io 에 대해서 방화벽 설정으로 이미지를 받아오지 못해서였다.
Pulling image "registry.k8s.io/metrics-server/metrics-server:v0.6.3"

# 우선 로컬에 이미지를 다운로드 받자.
docker pull registry.k8s.io/metrics-server/metrics-server:v0.6.3

# 이미지를 tar 로 만든다.
docker save -o metrics-server-v0.6.3.tar registry.k8s.io/metrics-server/metrics-server:v0.6.3

# 워커 노드에 tar 파일 전송
rsync -avz ./metrics-server-v0.6.3.tar ysoftman@worker1/home/ysoftman/
rsync -avz ./metrics-server-v0.6.3.tar ysoftman@worker2/home/ysoftman/
rsync -avz ./metrics-server-v0.6.3.tar ysoftman@worker3/home/ysoftman/

# 노드의 tar 이미지 파일을 로딩한다.
ssh ysoftman@worker1 "sudo docker load -i /home/ysoftman/metrics-server-v0.6.3.tar"
ssh ysoftman@worker2 "sudo docker load -i /home/ysoftman/metrics-server-v0.6.3.tar"
ssh ysoftman@worker3 "sudo docker load -i /home/ysoftman/metrics-server-v0.6.3.tar"

# metrics-server deployment 명세에 다음이 설정되어 있기 때문에
# imagePullPolicy: IfNotPresent
# pod 가 running 된다.

# 이슈2 - tls 비활성화
# metrics 로그를 보면 아래와같이 노드(kubelet)의 메트릭 수집시 실패한다고 나온다.
scraper.go:140] "Failed to scrape node" err="Get \"https://10.10.10.100:10250/metrics/resource\": read tcp 10.10.1.10:40752->10.10.10.100:10250: read: connection reset by peer" node="ysoftman-cpu1"

# metrics-server deployment> containers args 에 다음을 추가하면 위 에러는 발행하지 않고 정상 동작(scraping node ... scrap finished)한다.
- --secure-port=4443
- --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
- --kubelet-use-node-status-port
- --metric-resolution=15s
- --kubelet-insecure-tls  # 추가옵션
- --v=6 # 추가옵션 (Scraping node "node=xxxx" 노드 수집 성공 메시지 확인용)

# 이슈3 - apiservice 적용 안되는 이슈
# 아직도 error:metrics not available yet 이 발생한다.
# 찾아보니 kubectl 에서 top 커맨드 사용시 발생하는 에러 메시지였다.

# k8s api 로 node 메트릭을 다음과 같이 실행하면 결과가 나온다.
NODE_NAME="ysoftman-cpu1"
kubectl get --raw /api/v1/nodes/$NODE_NAME/proxy/metrics/resource | grep -i -E "node_cpu|node_mem"

# metrics api 에서 pods 응답은 나온다.
kubectl get --raw /apis/metrics.k8s.io/v1beta1/pods | jq 

# 하지만 nodes 응답을 보면 items: [] 로 빈값으로 나온다.
kubectl get --raw /apis/metrics.k8s.io/v1beta1/nodes | jq 

# metrics-server pod log 는 다음과 같이 노드로부터 정보를 받아 저장했다고 나온다.
round_trippers.go:553] GET https://10.10.10.10:10250/metrics/resource 200 OK in 2 millisecond
server.go:139] "Storing metrics"
server.go:144] "Scraping cycle complete"

# metrics-server 를 삭제했는데, k top nodes/pods 에러가 발행하지 않는다.
kubectl delete -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/downl
oad/components.yaml

# top 명령을 받고 있는 별도의 pod 가 있는것으로 의심된다.
# v1beta1.metrics.k8s.io 를 사용하는 api 서비를 조회하면
kubectl get apiservices | grep -i v1beta1.metrics.k8s.io

# 다음과 같이 prometheus-adapter 서비스가 나온다.
v1beta1.metrics.k8s.io     prometheus-adapter/prometheus-adapter

# kubectl top nodes 동작하는 클러스터는 다음과 같다.
v1beta1.metrics.k8s.io     kube-system/metrics-server

# metrics-server (kind:APIService) 부분이 반영이 안되는게 문제였다.
# prometheus-adapter > v1beta1.metrics.k8s.io 를 사용하고 있고, 이를 argo-cd 에서 항상 sync 하고 있어 삭제해도 다시 생성된다.

linux disk or memory /tmp directory

# go 서버(k8s pod)에 multipart 형식으로 파일을 업로드하면 context.multipartfrom() 에서 
# /tmp 위치에 multipart-3000453554 등의 이름으로 임시파일을 생성하게 된다.
# 여러 linux 배포판에서 disk IO 를 줄이기 위해 /tmp 는 디폴트로 tmpfs(RAM based) 파일시스템을 사용한다고 한다.
# 사용한 리눅스 배포판은 Debian GNU/Linux 9 (stretch) 이다.
# 그런데 df, mount, findmnt 명령에는 /tmp 마운트(파일시스템) 정보가 보이지 않는다.

# 파일 업로드를 진행하면
# /tmp/multipart... 파일이 점점 커지면서
watch -n 1 ls -ahl /tmp

# free 는 점점 줄어 들고 있는것 처럼 보인다.
# -s: repeat printing every N seconds
# -w: wide output
# -m: show output in mebibytes
free -s 1 -w -m

# /tmp 사용량을 보면 mounted on / 정보가 나온다.
# 이는 disk 를 사용하고 있다는 얘기다.
# 메모리 뿐만 아니라  / 의 disk 용량도 줄어들고 있는것이 확인된다.
watch -n 1 df -m /tmp

# 다시 free 결과를 보면 cache(pages with actual contents of files or block devices) 용량이 증가한다.
# 예전 free 관련에서 정리한 포스팅을 다시 참고해보면
# cache 의 목적은 최근 자주 사용되는 데이터를 메모리에 보관하여 재사용시 디스크까지 가서 않고 메모리에서 빠르게 액세스/로딩을 위해 사용된다.
# cache 사용량이 증가했지만 
# 가용메모리 = free + buffers + cached 로 사용할 수 있는 메모리가 줄어든것이 아니였다.
# 실제로 kubectl top 로 보면 메모리 사용량은 증가하지 않았다.
# kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
kubectl top pod -n my-namespace

# 결론... /tmp 는 디스크를 사용하고 있었다.

linux namespace

# 2002년 리눅스 커널에 포함된 namespace(mnt, pid, net, ipc, cgroup...타입) 로 isolation 구현
# 모든 프로세스들은 특정 네임스페이스에 속하고 unshare 로 새로운 네임스페이스에서 프로세스를 실행할 수 있다. 네임스페이스는 exit 로 빠져나올 수 있다.
# unshare 시 프로세스를 명시하지 않으면 ${SHELL}값(/bin/sh 또는 /bin/bash등)이 디폴트로 실행된다.

#####

# mnt namespace
# 부모(호스트)로 부터 격리된 mount타입(-m, --mount)의 네임스페이스로 /bin/bash 프로그램 실행
unshare --mount /bin/sh

# mount_ns 에 마운트하면 현재 네임스페이스에서만 마운트된것을 알 수 있다.
# tmpfs : 가상 메모리 파일시스템
# ushare 된 마운트 스페이스(격리됨)에서 생성한 마운트는 호스트에서 보이지 않는다.
mkdir /tmp/mount_ns
mount -n -t tmpfs tmpfs /tmp/mount_ns
mount | grep mount_ns

# 터미널을 하나 더 띄워 호스트 네임스페이스에서 보면 값이 다른것을 알 수 있다.
readlink /proc/$$/ns/mnt

# 호스트에서 tmpfs 마운트 정보가 안보이는것을 확인
mount | grep mount_ns

# 테스트 결과

#####

# pid namespace
# 새로운 pid(-p, --pid), -f(--fork) 네임스페이스으로 실행
# --mount-proc Just before running the program, mount the proc filesystem at mountpoint (default is /proc)
# --mount-prod 옵션을 사용하면 pid 네임스페이스가 /proc/{pid} 로 마운트되어 쉽게 pid 네임스페이스 접근할 수 있도록 해준다.(mount namspace 도 생긴다.)
unshare -fp --mount-proc /bin/sh

# 호스트 네임스페이스와 현재 pid 네임스페이스에 다른 pid 로 보인다.
# 현재 pid 네임스페이스에서 프로세스를 확인해보면 1번이다.
echo $$
ps -ef

# pid 네임스페이스에서의 pid namespace 정보를 보면
# 아래 호스트의 unshare mount namespace 와 다른것을 알 수 있다.
# unshare(mt ns id:4026532202) ---> pid-namespace /bin/sh (pid ns id:4026532203)
lsns -t pid -p 1

# 호스트에서 unshare 프로세스 pid 찾기
ps -ef | grep unshare

# ushare 프로세스의 namespace 정보
# ls -ahl /proc/{pid}/ns 로도 알 수 있다.
lsns -p {pid}

# mnt 네임스페이스ID 로 확인
lsns {namespace id}

# 테스트 결과 화면

#####

# cgroup namespace
# cgroup 는 controlgroup으로 프로세스의 리소스 제어하는 파일시스템이다.(sys/fs/cgroup)
# sleep 백그라운드 프로세스를 freezer(cgroup 작업 중지,재개를 위한 subsystem)의 sub2로 등록
mkdir -p /sys/fs/cgroup/freezer/sub2
sleep 100000 &
[1] 2932

# 테스트를 위해 sleep pid 환경변수로 설정 
export sleep_pid=2932

# sleep pid 를 sub2 cgroup 으로 등록
echo ${sleep_pid} > /sys/fs/cgroup/freezer/sub2/cgroup.procs

# 현재 프로세스도 freezer sub1 로 등록하자.
mkdir -p /sys/fs/cgroup/freezer/sub1

# 현재프로세스 확인, 테스트를 위해 현재 pid 환경변수로 설정 
echo $$
2178
export parent_pid=$(echo $$)

# 현재 프로세스 pid 를 sub1 cgroup 으로 등록
echo ${parent_pid} > /sys/fs/cgroup/freezer/sub1/cgroup.procs

# freezer (init process, PID 1), parent, sleep pid 확인
cat /proc/1/cgroup | grep freezer
cat /proc/${parent_pid}/cgroup | grep freezer
cat /proc/${sleep_pid}/cgroup | grep freezer

# freezer 파일 확인
tree -L 1 /sys/fs/cgroup/freezer/
/sys/fs/cgroup/freezer/
├── cgroup.clone_children
├── cgroup.procs
├── cgroup.sane_behavior
├── docker
├── notify_on_release
├── release_agent
├── sub1
├── sub2
└── tasks

# 새로운 cgroup(-C, --cgroup) 네임스페이스로 실행
unshare -Cm /bin/sh

# freezer (init process, PID 1), parent, sleep pid 확인해보면
# sub1 --> / 가 루트가 되고
# sub2 --> ../sub2 로 변경되었지만 호스트 cgroup 은 그대로 보인다.
cat /proc/1/cgroup | grep freezer
cat /proc/2178/cgroup | grep freezer
cat /proc/2932/cgroup | grep freezer

# 테스트 결과

#####

# stress 툴로 시스템 부하(cpu)를 테스트해보자.
# new_root 에 bash 준비하기
mkdir -p new_root/{bin,usr,lib,lib64} new_root/lib/x86_64-linux-gnu/ new_root/usr/lib/x86_64-linux-gnu
cp /bin/bash new_root/bin
cp /bin/mount new_root/bin
cp /lib/x86_64-linux-gnu/{libtinfo.so.5,libdl.so.2,libc.so.6} new_root/lib
cp /lib64/ld-linux-x86-64.so.2 new_root/lib64

# mount 명령등 준비하기
cp -rv /bin/{ls,cat,mount,umount,mkdir,rmdir,rm,cp,grep,ps} new_root/bin
cp -rv /usr/lib/x86_64-linux-gnu/* new_root/usr/lib/x86_64-linux-gnu
cp -rv /lib/x86_64-linux-gnu/* new_root/lib/x86_64-linux-gnu
cp -rv /lib64/* new_root/lib64

# stress, cgroup 툴 설치
apt-get install -y stress cgroup-tools

# chroot 후 필요한 파일들 복사
mkdir -p new_root/usr/bin/bin
cp /usr/bin/{top,stress,cgcreate,cgset,cgexec} new_root/usr/bin/

# top 실행시 필요한 파일들 복사
mkdir -p new_root/usr/share/terminfo
cp -r /usr/share/terminfo/ new_root/usr/share/terminfo

# cgcreate 시 root uid 파악에 필요
mkdir -p new_root/etc
cp /etc/group new_root/etc/group
cp /etc/passwd new_root/etc/passwd

# cgroup 관련 마운트 확인
mount | grep -E "cgroup*.cpu"

# chroot 후 mount 하기
chroot new_root
mkdir -p /sys/fs/cgroup
mkdir -p /sys/fs/cgroup/{cpuset,"cpu,cpuacct"}
mount -t cgroup -o cpuset cgroup /sys/fs/cgroup/cpuset
mount -t cgroup -o cpu,cpuacct cgroup /sys/fs/cgroup/cpu,cpuacct

# /proc 마운트
mkdir -p /proc
mount -t proc proc /proc

# mycgroup 생성 및 확인
cgcreate -a root -g cpu:mycgroup
ls -al /sys/fs/cgroup/cpu,cpuacct/ | grep mycgroup

# CPU 사용률(%) = (cpu.cfs_quota_us / cpu.cfs_period_us) * 100
# cpu.cfs_period_us 를 확인해 보면 100000(us, 100ms) 이다.
# cat /sys/fs/cgroup/cpu,cpuacct/cpu.cfs_period_us
# 따라서 cpu.cfs_quota_us=30000 을 주면 30% cpu 사용률로 제한한다.
cgset -r cpu.cfs_quota_us=30000 mycgroup

# mycgroup 에 strecc -c(--cpu) 1로 부하 테스트 백그라운드로 실행
cgexec -g cpu:mycgroup stress -c 1 &

# top 으로 stress 프로세스 30% 사용 확인
export TERM="xterm-256color"
top
  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
 3129 root      20   0    8248     96      0 R  30.0  0.0   0:03.50 stress

# 테스트 결과

#####

# net namespace
# 새로운 network(-n, --net) 네임스페이스으로 실행
unshare --net /bin/sh

# 호스트 네임스페이스와 정보가 다른것을 알 수 있다.
ip a

# 테스트 결과

# ip 로 net namespace 생성해보기
ip netns add mynet

# net namespace 확인
ip netns list
# 또는
ls /var/run/netns

# nsenter 로 net네임스페이스(--net)에 들어가기
# 별도 프로그램 명시하지 않으면 디폴트로 $SHELL -> /bin/bash 를 실행한다.
nsenter --net=/var/run/netns/mynet
ip a

# net 네임스페이스에서 현재 프로세스의 pid,user,ipc,mnt등의 네임스페이스 정보 확인
lsns -p $$

# 호스트에서 net 네임스페이스 id 확인
# readlink /proc/$$/ns/net 대신 lsns 명령어로도 네임스페이스 정보를 확일 수 있다.
# lsns -t 타입 -p pid
lsns -t net -p $$

# 테스트 결과

#####

# user namespace 생성
# 새로운 user(-U, --user) 네임스페이스으로 실행
unshare --user /bin/sh

# 새로운 user 네임스페이스에서의 사용자 정보 확인
whoami
id

# 네임스페이스 확인해보기
ls -al /proc/$$/ns
lsns -p $$

# 테스트 결과 화면

# container 와 호스트 root 가 같은것인지 확인해보기
# docker 로 busybox 컨테이너 띄우기
docker container run -it --name busybox --rm busybox

# ps 로 보면 root 로 실행됐고, uid=0 으로 되어 있다
ps -ef
id

# 현재 프로세스의 user 네임스페이스 확인
readlink /proc/$$/ns/user

# 호스트에서도 확인해보면 root 이름이고 uid=0 이다.
ps -ef | grep root | head -3
id

# 호스트에서 현재 프로세스의 user 네임스페이스 확인해보면 위 container user namespace id 와 같은것을 알 수 있다.
# 결국 container 의 root 도 호스트 user 네임스페이스를 공유하기 때문에 호스트 root 와 같은것이다.
readlink /proc/$$/ns/user

# 테스트 결과 화면

# 참고로 docker v1.10 이상 부터는 별도의 user namespace 를 지원하지만
기본적으로 docker 로 컨테이너를 실행하면 root 로 프로세스를 실행한다.(user namespace 를 별도로 만들지 않고 호스트를 user namespace 를 사용한다.)
# 이 때문에 container root 계정이 악용될 수 있음을 인지해야 한다.
# docker remap 설정으로 uid 를 다르게할 수 있다. 아래 별도 포스트로 정리

#####

# uts(unix time sharing system) namespace
# 새로운 uts(-u, --uts) 네임스페이스으로 실행
unshare --uts /bin/sh

# 호스트명 변경하고 확인
hostname ysoftman
hostname

# 터미널을 하나 더 띄워 호스트를 확인해 보면 영향을 주지 않는것을 알 수 있다.
# 테스트 화면

#####

# ipc(interprocess communication) namespace
# shared memory, queue, semaphore 등의 리소스에서 사용되며 같은 ipc 네임스페이스안 프로세스들은 ipc 통신할 수 있다.
# ipc (shared memory, pipe) 상태 정보 보기
# -m  Write information about active shared memory segments.
ipcs -m

# ipc shared memeory 리소스 1000byte 생성
# -m Create a shared memory segment of size bytes.
ipcmk -M 1000

# 1000 byte shared memory segemnt 가 생성된것을 확인할 수 있다.
ipcs -m

# 새로운 ipc(-i, --ipc) 네임스페이스 생성
unshare --ipc /bin/sh

# 새로운 ipc 네임스페이스에서는 호스트에서 만든 1000bytes 리소스가 보이지 않는다.
ipcs -m

# 호스트로 나오기
exit

# ipc 리소스 삭제
# -M Remove the shared memory segment created with shmkey after the last detach is performed.
ipcrm -M {shared memory segment key}

# 삭제된 리소스 확인 
ipcs -m

# 위 과정을 테스트한 결과

uptime cpu load high 찾기

# uptime 확인시 2년 넘게 운영되는 서버가
# system load average (cpu) 가 높게 나오고 계속 올라간다.
# top, htop 에서 프로세스들의 cpu 사용률 확인해 봤지만
# 아래 그림과 같이 높은 cpu 를 사용하는 프로세스는 보이지 않았다.
# 대신 cpu 1개가 계속 100% 상태다.


# 하지만 다음과 같이 pcpu(%cpu) 항목 보기로 cpu 사용률정렬(-r)해서 보면 보인다.
ps -eo %cpu,pid,user,args -r | head -3
%CPU   PID USER     COMMAND
 99    895 root     /sbin/rngd -f
 8.1 30810 root     /usr/lib/systemd/systemd-journald
 0.9 30738 root     htop

# 참고로 맥에서는 -f 기본에 %cpu 컬럼추가해서 봐도 된다.
ps -ef -o %cpu -r | head -3

# htop 에서 CPU% 가 99%인 /sbin/rngd 가 ps 로 보면 높은 cpu 사용률을 보인다.
# 찾아보니 rngd 는 Check and feed random data from hardware device to kernel 로 위와 같은 상황시 재부팅해야한다고 한다.
# 커널 3.10.0-514.21 부터 /dev/hwrnd 가 생겼고
# 기존 rngd 에서 에러가 발생할 수 있어 업데이트가 필요하다고 한다.


kubernetes(k8s) command

# kubernetes(쿠버네티스,줄여서 k8s,배의 조타수)는 도커 기반의 컨테이너를
# 배포, 스케일링등(docker orchestrator) 위한 오픈소스 플랫폼

# 용어
# cluster : master + node 구성된 추상적인 단위
# master : node 이벤트를 김지하고 cluster 를 관리하는 주체
# node : 실제 서버들
# pod : 도커 컨테이너 집합, 가장 작은 단위로 node 위에서 동작하는 앱(docker container 에 담긴) 1개 이상으로 구성
# object : pod, volume, namespace 등
# Deployment : 리소스의 한 종류(kind)로 pod 에 컨테이너를 띄운다.
# Service : 리소스의 한 종류(kind)로 오픈(노출)하기전 Deployment 와같은 리소스를 묶어 주는 추상적인 개념
# ingress : Servcie 를 외부에서 접속할 수 있게 해준다.
# GCP(GoogleCloudPlatform), AWS(AmazonWebService)로 클러스터를 구성한다.
# 참고 GCP, AWS 등의 Cloud Provider 를 사용하지 않고 클러스터 구성하는 경우
# 장비를 구하기도 힘들고 구성도 어려워 비추
# https://kubernetes.io/docs/setup/scratch/

# 구축된 k8s 환경이없다면 minikube 로 로컬에서 k8s 클러스터를 구성할 수있다.
https://minikube.sigs.k8s.io/docs/start/

# kubectl(kubernets cli tool) 설치
# centos, ubuntu
# https://kubernetes.io/docs/tasks/tools/install-kubectl/
# https://kubernetes.io/ko/docs/tutorials/
# mac
brew install kubernetes-cli

# 개인적으로 GCP의 k8s 는 요금이 발생해 현재 사용하고 있지 않다.
# k8s cluster 생성 후 로컬에서 해당 클러스터를 사용하려면 다음 설정을 해야 한다.
kubectl config set-credentials ysoftman --username=ysoftman --password=aaa123
kubectl config set-cluster ysoftman-test-cluster --insecure-skip-tls-verify=true --server https://10.10.10.10:6443
kubectl config set-context ysoftman-test-context --cluster=ysoftman-test-cluster --user=ysoftman
kubectl config use-context ysoftman-test-context

# 접속 설정에 password 대신 토큰 사용할 수도 있다.
# 토큰 생성전에는 최초 username, password 로 접속이 필요하다.
# 사용자 토큰 파악
kubectl --namespace=kube-system get secrets | grep ysoftman | awk '{print $1}' | xargs kubectl --namespace=kube-system describe secrets

# ~/.kube/config 에 다음과 같이 user수정
#- name: ysoftman
#  user:
#    password: aaa123
#    username: ysoftman
- name: ysoftman
  user:
    token: zzzzz

# 설정 보기
kubectl config view

# 클러스터 정보 보기
kubectl cluster-info

# 노드 상태 보기
kubectl get nodes -o wide

# pod 상태 보기
kubectl get pods -o wide

# pod 내부 정보 보기 (CrashLoopBackOff 상태일때 확인)
kubectl describe pod

# kubectl top 명령은 metrics-server 를 설치해야 사용할 수 있다.
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

# node 별 cpu, memory 사용량 보기, cpu 순으로
kubectl top node --sort-by=cpu

# pod 별 cpu, memory 사용량 보기, memory 순으로
kubectl top pod --sort-by=memory

# contianer 별 cpu, memory 사용량 보기, cpu 순으로
kubectl top pod --containers --sort-by=cpu

# ktop(https://github.com/vladimirvivien/ktop)으로 cpu,memory 사용을 더 편하게 볼 수도 있다.
# 설치
brew install ktop

# 전체 네임스페이스의 리소스 보기
ktop

# 특정 네임스페이스에 해당하는 리소스만 보기
ktop -n ysoftman

# 앱 배포(Deployment)
# deployment 설명 : https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.16/#deployment-v1-apps
# 예제 : https://kubernetes.io/docs/concepts/services-networking/connect-applications-service/

# nginx 배포 예제 yaml 파일 다운로드
curl https://raw.githubusercontent.com/kubernetes/website/master/content/en/examples/service/networking/run-my-nginx.yaml -O

# run-my-nginx.yaml 내용
apiVersion: apps/v1   # 앱 생성에 사용할 k8s api 버전
kind: Deployment   # 생성할 resource 종류
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 2
  template:
    metadata:   # 오브젝트 구분을 위한 값
      labels:
        run: my-nginx
    spec:      # 생성할 오브젝트의 상태(스펙)
      containers:    # 컨테이너를 구동하는경우
      - name: my-nginx
        image: nginx
        ports:
        - containerPort: 80

# yaml 파일로 앱 배포(object 생성)
kubectl apply -f run-my-nginx.yaml

# 배포(실행중) 상태 보기
kubectl get all -o wide

# pod 에 보이는 IP 는 kubernetes 내부에 사용하는 IP 로 접근할 수 없다.
kubectl get pods -o wide

# 다음 명령이 실행될 동안 my-nginx-xxxx pod 80 포트가 로컬 9999 포트로 임시로 포트 포워딩 된다.
kubectl port-forward my-nginx-xxxx 9999:80
http://localhost:9999/ 로 확인

# pod ssh 접속
# kubectl exec -h 참고
kubectl exec -it my-nginx-xxxx -- /bin/bash

# 이름을 알기 위해서 다음처럼 사용하면 편하다.
kubectl exec -it $(kubectl get pods -o name | sed 's/pod\///' | grep my-nginx) -- /bin/bash

# local -> k8s pod container 파일 복사
# pod 내 container 가 여러개면 -c 로 container 이름을 지정하면 된다.
kubectl cp file.txt ysoftman_namespace/ysoftman_pod:/home/ysoftman/ -c ysoftman_container

# pod log 확인
# kubectl logs -h 참고
kubectl logs my-nginx-xxxx

# -f 옵션으로 stream 되는 로그를 follow 할 수 도 있다.
kubectl logs my-nginx-xxxx -f

# pod 내 2개 이상의 container 가 있는 경우
kubectl logs my-nginx-xxxx -c 컨테이너이름

# 서비스(Service) 생성
# nginx-svc.yaml 다운로드
curl https://raw.githubusercontent.com/kubernetes/website/master/content/en/examples/service/networking/nginx-svc.yaml -O

# 위 Deployment 된 앱을 서비스 단위로 묶어 준다.
# nginx-svc.yaml 를 다음과 같이 nodeport 설정 추가한다.
apiVersion: v1 # https://kubernetes.io/ko/docs/concepts/overview/kubernetes-api/ 참고
kind: Service
metadata:
  name: my-nginx
  labels:
    run: my-nginx
spec:
  type: NodePort
  ports:
  - port: 80
    protocol: TCP
    nodePort: 30010 # 30000~32767
  selector:
    run: my-nginx

# 서비스 적용
# 참고로 2개의 yaml 을 --- 로 구분해서 파일 하나로 만들어 한번에 적용해도 된다.
# 참고로 yaml 수정하고 apply 하면 수정된 내용을 다시 반영된다.
kubectl apply -f nginx-svc.yaml

# my-nginx 가 서비스된 것을 확인(service 대신 svc 도 가능)
kubectl get service

# my-nginx 서비스만 조회
kubectl get service -l app=my-nginx

# 참고로 my-nginx 서비스 설정을 yaml 파일로 저장할 수 있다.
kubectl get service -l app=my-nginx -o yaml > temp.yaml

# my-nginx 서비스 events(log) 확인
kubectl describe service my-nginx

# 전체 네임스페이스(-A, --all-namespaces)에서 pod, service, ingress 등 함께 조회
kubectl get pod,svc,ingress --all-namespaces

# 전체 네임스페이스에서 모든 리소스 조회
kubectl get all -A

# k8s 클러스터 외부에서는 노드IP:30010 로 접속 가능
kubectl get nodes -o wide
http://노드IP:30010

# 참고로 사용하는 클라우드 서비스에서 ingress 를 지원한다면
# NodePort 는 주석처리하고 ingress(kind) yaml 만들어 적용하면 된다.
# ingress 를 사용하면 host, path 등의 분기처리등 다양한 기능을 이용할 수 있다.
# 배포한 앱 삭제
kubectl delete service my-nginx
kubectl delete deployment my-nginx

# pod 전체 삭제
# pod 만 삭제하면 replica 에 의해 pod 를 복원하려고 한다.
# 따라서 deployment object 를 먼제 삭제해야 한다.
kubectl delete pods --all

# unknown 상태의 pods 가 삭제되지 않는다면 다음 옵션을 사용하자.
kubectl delete pods --all --grace-period=0 --force --wait=false

# 네임스페이스안의 리소스들 모두 삭제
all=pods,deployments,rs 등의미, 단 secrets,configmaps 등 일부는 수동으로 삭제해야 한다..
kubectl delete all --all --namespace ysoftman-namespace

# namespace 삭제
kubectl delete ns ysoftman-namespace

# 네트워크 정책 참고
https://kubernetes.io/docs/concepts/services-networking/network-policies/
https://github.com/ahmetb/kubernetes-network-policy-recipes

#####

# resource 종류 : https://kubernetes.io/docs/reference/kubectl/overview/#resource-types
# 지원되는 resources 리스트 보기
kubectl api-resources

# 리소스 설명 보기
kubectl explain 리소스명

# 지원하는 api 종류 보기
kubectl get apiservices

# vi 에디터로 ysoftman 서비스 수정
KUBE_EDITOR="vi" kubectl edit svc/ysoftman

# ysoftman deployment 재시작(pod 새로 생성)
kubectl rollout restart deployment/ysoftman

# ysoftman statefulset 재시작(pod 새로 생성)
kubectl rollout restart statefulset/ysoftman

# 새 pod 로 시작
# replicas=0 으로 만면 pod 삭제 후 # replicas=1 로 새 pod 생성
kubectl scale --replicas=0 deployment/ysoftman
kubectl scale --replicas=1 deployment/ysoftman

#####

# 노드 재부팅시
# node 확인
kubectl get nodes

# ysoftman1 노드에 pod 스케쥴링 되지 않도록 방지
# drain 과정에 cordon 이 있어, drain 할거면 굳이 할 필요 없음
kubectl cordon ysoftman1

# ysoftman1 노드의 모든 pod 를 graceful 종료
# drain 과정에 cordon 이 포함되어 있다.
# daemonset 이 있는 경우라면 --ignore-daemonsets 옵션 추가
kubectl drain ysoftman1

# ysoftman1 노드에 다시 pod 스케쥴링 하기
# 재부팅되면 cordon 상태라 uncordon 해야 된다.
kubectl uncordon ysoftman1

# 추가로 tain/toleration 은
# ysoftman1 노드에 pod 스케쥴링 되지 않도록 방지
# cordon 과 다르게 toleration 로 강제로 스케쥴링 되게 할 수 있다.
kubectl taint node ysoftman1 key1=value1:NoSchedule

# ysoftman1 노드에 taint 무시하고 pod 스케쥴링
kubectl toleration node ysoftman1

#####

# 새노드 추가시
# master(control-plane) 에서 조인을 위한 토큰 확인
sudo kubeadm token create --print-join-command

# 새로운 노드에서 다음 명령을 실행해 master 노드에 join 하도록 한다.
sudo kubeadm join {control-plane-ip}:6443 --token {토큰값}

# 참고 kubectl 명령들

glances monitoring

glances 는 unix 계열에서 기본적으로 사용하는 모니터링 프로그램인 top 과 비슷하다.
윈도우, 안드로이드 폰에서도 작동된다.

# 맥에서 다음과 같이 pip 로 설치시
pip install glances

# 다음과 같이 디렉토리를 생성하지 못해 에러가 발생한다.
"error: could not create '/System/Library/Frameworks/Python.framework/Versions/2.7/share': Operation not permitte"

# 이때는 --user 옵션을 주어 현재 사용자 로컬 위치에 설치하자.
# /Users/ysoftman/Library/Python/2.7/lib/python/site-packages/glances
# /Users/ysoftman/Library/Python/2.7/bin
# 환경 추가
# export PATH=$PATH:~/Library/Python/2.7/bin:
pip install --user glances

# 최근엔 brew 로도 설치할 수 있다.
brew install glances

# 실행
glances

# 웹서버 모드로 실행(bottle 이 설치되어 있어야 한다.)
sudo pip install bottle
glances -w

http://0.0.0.0:61208 로 웹 모니터링 페이지를 볼수 있다.

htop vtop bpytop 사용

# nix 계열에서 프로세스 모니터링을 위해 기본적으로 사용된 top 프로그램들

# C 로 만든 htop
# http://hisham.hm/htop/index.php
# https://github.com/hishamhm/htop
# 설치
# centos
yum install htop

# ubuntu
apt-get install htop

# mac
brew install htop

# h : help
# t : tree view
# p : program path
# q : quit
# P : sort by CPU
# M : sort by MEM
# T : sort by TIME
# space : tag process



# javascript 로 만든 vtop
https://parall.ax/vtop
https://github.com/MrRio/vtop
# 설치 (실행 후 업데이트 버전이 있으면 자동 업데이트)
sudo npm install -g vtop
# 실행시 옵션으로 테마를 적용할 수 있다. ex) vtop --theme monokai


# bpytop
https://github.com/aristocratos/bpytop
# python 으로 만들어졌고 cpu 온도까지 표시되는 가장 최신 스타일의 top 프로그램이다.
# 설치
pip3 install bpytop --upgrade
brew install hacker1024/hacker1024/coretemp
brew install osx-cpu-temp

# osx-cpu-temp 는 cpu 통 온도 하나만 표시하는데,
# 코어별 온도가 표시되는 coretemp 설치하면 사용하지 않아 설치할 필요 없다.
# 그런데 맥북에서 coretemp 실행하면 0 번째 코어를 찾지 못하는 문제가 있다.
# imac 에선 코어별 SMC 센서 코드가 TCOC, TC1C .. 로 0부터 시작하지만
# macbook 에선 TC1C, TC2C,.. 로 1부터 시작하는 차이가 있다.
# 그리고 CPU 전체 온도를 imac 에선 CPU DIE 로 TC0D 로 사용하지만
# macbook 에선 CPU Proximity 로 TC0P 로 사용한다.
# SMC 코드 참고 https://logi.wiki/index.php/SMC_Sensor_Codes
# 이 때문에 맥북에선 cpu core 별 온도가 표시되지 않는다.
# 해당 coretemp 코드 수정해서 PR 날린 상태다.
# 아래처럼 기존 패키지는 삭제하고 repo 로 빌드하고 복사해 사용하면 온도가 표시된다.
brew uninstall osx-cpu-temp coretemp 
git clone https://github.com/ysoftman/coretemp && cd ./coretemp && make && ./coretemp && cp -v ./coretemp /usr/local/bin

# macbookpro(mbp) coretemp 수정 PR 생성했는데 머지됐다.
# 그냥 coretemp 사용하면 된다.ㅎ

# M : 메뉴설정에서 테마 변경등을 변경할 수 있다.


# tmux 로 4개의 top 을 띄워본 화면
# 0 기본 top
# 1 htop
# 2 vtop
# 3 bpytop


# btm
# 설치
brew install bottom
# rust 로 만들었고, usage 를 그래프로 보고 싶을때 bpytop, vtop 보다 빠르게 로딩돼 좋다.

# ytop
# 설치
brew install ytop
# rust 로 만들었고, btm 처럼 빠르다.

# btop
# 설치
brew install btop
# c++ 로 만들었고 bpytop과 UI가 비슷하다.

Linux top 사용과 정보 설명

[top 실행 시 많이 사용된는 옵션]
top -d 0.5 -c -u ysoftman
(delay) -d 0.5 : 0.5초 마다 화면을 갱신
(user) -u ysoftman : ysoftman 사용자 소유의 프로세스를 표시
(command) -c : 프로세스를 실행시켰을 때의 명령줄을 표시

[top 실행 후 명령]
space bar : refresh
d 입력 후 딜레이 값 입력 : 입력한 딜레이 값에 따라 refresh
u 입력후 사용자이름 입력 : 사용자 소유의 프로세스 표시
k 입력후 PID 입력 : pid 에 해당하는 프로세스 종료
B : 상단정보 및 running 프로세스 정보를 bold로 표시/해제
b : running 프로세스 정보를 하이라이트하여 표시/해제
e : 메모리 단위(k/m/g/t/p) 변경
x : b 또는 B 로 표시할때 colum 하이라이트 표시/해제
y : b 또는 B 로 표시할때 row 하이라이트 표시/해제
R : 정렬 변경 (오름차순/내림차순)
o : 항목 내용 표시 순서 변경(항목에 대한하는 알파벳(대/소문자)로 순서 변경)
F : 정렬 기준 필드 정하기
z : 컬러/모노 표시
c : 명령줄 표시/해제
l : load average 줄 표시/해제
t : task cpu states 줄 표시/해제
m : memory 줄 표시/해제
i : idle 프로세스 표시/해제
H : thread 표시/해제
q : 종료

[top 으로 리소스 사용량을 볼 때 각 항목에 대한 설명]

PID(ProcessID) : 프로세스 ID
USER : 프로세스를 실행시킨 사용자
PR(Priority) : 프로세스 우선순위
NI(Nice value) : 프로세스 NICE 값(음수값이 우선순이가 높음)
VIRT(Virtual Image (kb)) : 프로세스가 사용하고 있는 가상 메모리 사용량
RES(Resident Size (kb)) : 프로세스가 사용하고 있는 실제 메모리 사용량
SHR(Shared Mem Size (kb))  : 프로세스가 사용하고 있는 공유 메모리 크기
S(Process Status) : 프로세스 상태(R(Running), S(Sleeping), T(stopped Trace) W(Swapped out), Z(Zombie))
%CPU(CPU Usage) : 프로세스의 CPU 사용률
%MEM(Memory Usage) : 프로세스의 메모리 상용률
TIME+(CPU Time : 프로세스가 CPU 를 사용한 시간(멀티쓰레드,멀티프로세스의 모든 합)
COMMAND : 프로세세를 실행한 명령