K8s-one-line-Challenge

잔잔한 호수에 돌맹이는 내가던졌다.

K8s의 Service는 selector 에서 지정한 label로 pod에게 트래픽을 흘린다.

그런데 아이러니하게도 service 에서 연결된 pod를 한번에 조회할순 없다.

service 에서 selector 나 endpoint를 확인해서 labels 를 보고 확인해야 한다. 그 과정을 한번 보자.

my-service1 이라는 서비스에서 사용하는 pod를 조회할꺼다.

k get svc -o wide
NAME          TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE     SELECTOR
kubernetes    ClusterIP   198.19.128.1     <none>        443/TCP        2d13h   <none>
my-service1   NodePort    198.19.231.233   <none>        80:30001/TCP   2d12h   app=my-nginx1
my-service2   NodePort    198.19.172.176   <none>        80:30002/TCP   2d12h   app=my-nginx2
my-service3   NodePort    198.19.200.20    <none>        80:30003/TCP   2d12h   app=my-nginx3

k get pods -l app=my-nginx1 --show-labels 
NAME                         READY   STATUS    RESTARTS   AGE   LABELS
my-nginx1-67f499d79c-g7vr7   1/1     Running   0          26h   app=my-nginx1,pod-template-hash=67f499d79c
my-nginx1-67f499d79c-j4f9k   1/1     Running   0          26h   app=my-nginx1,pod-template-hash=67f499d79c
my-nginx1-67f499d79c-mqxzs   1/1     Running   1          26h   app=my-nginx1,pod-template-hash=67f499d79c

kubectl. 에서 svc 를 get하고 -o wide 명령어를 쓰면 selector 가보인다. 거기서 get pod -l app=my-nginx1 이라 일일이 지정해줘야지만 확인할수 있다. 명령어 두줄치면 되긴한데 귀찮다. 이렇게 된이상 한줄치기는 물러설수 없다.

미끼를 물어주신 iamai 님께 감사를 드린다. - 재차 감사! - 예아!

kubectl get endpoints |grep my-service1 |awk '{print $2}'|tr "," "\n" |awk -F":" '{print $1}' |grep -f - <(kubectl get po -o wide)
my-nginx1-67f499d79c-g7vr7   1/1     Running    0          26h   198.18.0.74    nks-pool-1119-w-gzg   <none>           <none>
my-nginx1-67f499d79c-j4f9k   1/1     Running    0          26h   198.18.2.250   nks-pool-1119-w-gzh   <none>           <none>
my-nginx1-67f499d79c-mqxzs   1/1     Running    1          26h   198.18.1.208   nks-pool-1119-w-gzi   <none>           <none>

endpoint 에서 조회된 IP를 awk 로 떼어서 한줄씩으로 변환후 포트를 제거한다. 그리고 pod list 에서 IP가 grep 된 줄만 출력한다.

[root@linuxer-bastion ~]# kubectl get endpoints
NAME          ENDPOINTS                                         AGE
kubernetes    10.0.12.10:6443,10.0.12.11:6443,10.0.12.16:6443   2d13h
my-service1   198.18.0.74:80,198.18.1.208:80,198.18.2.250:80    2d13h
my-service2   198.18.0.173:80,198.18.1.155:80,198.18.2.120:80   2d13h
my-service3   198.18.0.6:80,198.18.1.139:80,198.18.2.70:80      2d13h
[root@linuxer-bastion ~]# kubectl get endpoints |grep my-service1 
my-service1   198.18.0.74:80,198.18.1.208:80,198.18.2.250:80    2d13h
[root@linuxer-bastion ~]# kubectl get endpoints |grep my-service1 |awk '{print $2}'
198.18.0.74:80,198.18.1.208:80,198.18.2.250:80
[root@linuxer-bastion ~]# kubectl get endpoints |grep my-service1 |awk '{print $2}'|tr "," "\n" 
198.18.0.74:80
198.18.1.208:80
198.18.2.250:80
[root@linuxer-bastion ~]# kubectl get endpoints |grep my-service1 |awk '{print $2}'|tr "," "\n" |awk -F":" '{print $1}' 
198.18.0.74
198.18.1.208
198.18.2.250
[root@linuxer-bastion ~]# kubectl get endpoints |grep my-service1 |awk '{print $2}'|tr "," "\n" |awk -F":" '{print $1}' |grep -f - <(kubectl get po -o wide)
my-nginx1-67f499d79c-g7vr7   1/1     Running    0          26h   198.18.0.74    nks-pool-1119-w-gzg   <none>           <none>
my-nginx1-67f499d79c-j4f9k   1/1     Running    0          26h   198.18.2.250   nks-pool-1119-w-gzh   <none>           <none>
my-nginx1-67f499d79c-mqxzs   1/1     Running    1          26h   198.18.1.208   nks-pool-1119-w-gzi   <none>           <none>
[root@linuxer-bastion ~]# kubectl get po -o wide
NAME                         READY   STATUS     RESTARTS   AGE   IP             NODE                  NOMINATED NODE   READINESS GATES
busybox                      0/1     Init:0/2   0          26h   198.18.2.60    nks-pool-1119-w-gzh   <none>           <none>
my-nginx1-67f499d79c-g7vr7   1/1     Running    0          26h   198.18.0.74    nks-pool-1119-w-gzg   <none>           <none>
my-nginx1-67f499d79c-j4f9k   1/1     Running    0          26h   198.18.2.250   nks-pool-1119-w-gzh   <none>           <none>
my-nginx1-67f499d79c-mqxzs   1/1     Running    1          26h   198.18.1.208   nks-pool-1119-w-gzi   <none>           <none>
my-nginx2-659945d9d8-2sggt   1/1     Running    1          26h   198.18.1.155   nks-pool-1119-w-gzi   <none>           <none>
my-nginx2-659945d9d8-cjkft   1/1     Running    0          26h   198.18.2.120   nks-pool-1119-w-gzh   <none>           <none>
my-nginx2-659945d9d8-szw59   1/1     Running    0          26h   198.18.0.173   nks-pool-1119-w-gzg   <none>           <none>
my-nginx3-694994cd8c-l4m6k   1/1     Running    1          26h   198.18.1.139   nks-pool-1119-w-gzi   <none>           <none>
my-nginx3-694994cd8c-lbqsd   1/1     Running    0          26h   198.18.2.70    nks-pool-1119-w-gzh   <none>           <none>
my-nginx3-694994cd8c-xjzkc   1/1     Running    0          26h   198.18.0.6     nks-pool-1119-w-gzg   <none>           <none>
nginx                        1/1     Running    0          26h   198.18.0.80    nks-pool-1119-w-gzg   <none>           <none>

이해를 돕기위해 결과를 한줄씩 쳐서 출력했다.

iamai 님의 shell에 대한 이해도를 볼수있었다.

나는 grep를 쓰지않고 출력하고 싶었다. 여러 엔지니어들을 보면 jsonpath로 예쁘게 깍는것이 부러웠다. 방법은 다양했다 json | jq 부터 jsonpath custom-columns 까지 방법이 많은데 나도 한번 써볼까 싶었다.

k get pod -l $(k get svc my-service1 -o=jsonpath='{..selector}' | sed 's/map//' | sed 's/:/=/' | tr -s '[[:space:]]' ' ') --show-labels
NAME                         READY   STATUS    RESTARTS   AGE   LABELS
my-nginx1-67f499d79c-g7vr7   1/1     Running   0          26h   app=my-nginx1,pod-template-hash=67f499d79c
my-nginx1-67f499d79c-j4f9k   1/1     Running   0          26h   app=my-nginx1,pod-template-hash=67f499d79c
my-nginx1-67f499d79c-mqxzs   1/1     Running   1          26h   app=my-nginx1,pod-template-hash=67f499d79c

시작부터 iamai 님과의 다른접근을 볼수있다. 나는 label로 접근했고, iamai 님은 IP로 접근했다.

selector 는 label을 기반으로 pod와 매핑되기때문에 IP가 우선이 되서는 안된다 생각했다. IP는 고정된 값이 아니므로. 그래서 label 을 사용하기로 생각했다.

[root@linuxer-bastion ~]# k get svc my-service1 -o=jsonpath='{..selector}' 
map[app:my-nginx1]
[root@linuxer-bastion ~]# k get svc my-service1 -o=jsonpath='{..selector}' | sed 's/map//' 
[app:my-nginx1]
[root@linuxer-bastion ~]# k get svc my-service1 -o=jsonpath='{..selector}' | sed 's/map//' | sed 's/:/=/' 
[app=my-nginx1]
[root@linuxer-bastion ~]# k get svc my-service1 -o=jsonpath='{..selector}' | sed 's/map//' | sed 's/:/=/' | tr -s '[[:space:]]' ' '
 app=my-nginx1

먼저 jsonpath를 이용하여 service의 selector를 찾는다 여기서 sed 명령어로 map[app:my-nginx1] 이라는 문자열을 두번 파이프라인하여 [app=my-nginx1]로 변환된다. json으로 출력한 문자열은 = -> : 으로 치환되어 표기된다. 그래서 변경해줘야 했다. 괄호를 벗겼다. 괄호를 벗은 값은 내가 처음부터 원했던 service - selector - label 이다. 이제 이값을 이용해서 pod 를 리스팅 하고 label를 보면 완성이다.

k get pod -l $(k get svc my-service1 -o=jsonpath='{..selector}' /| sed 's/map//' | sed 's/:/=/' | tr -s '[[:space:]]' ' ') --show-labels
NAME                         READY   STATUS    RESTARTS   AGE   LABELS
my-nginx1-67f499d79c-g7vr7   1/1     Running   0          26h   app=my-nginx1,pod-template-hash=67f499d79c
my-nginx1-67f499d79c-j4f9k   1/1     Running   0          26h   app=my-nginx1,pod-template-hash=67f499d79c
my-nginx1-67f499d79c-mqxzs   1/1     Running   1          26h   app=my-nginx1,pod-template-hash=67f499d79c

내가 작성한 스크립트는 폰트크기 15다

k get ep -o custom-columns=IP:.subsets[].addresses[].ip
IP
10.0.12.10
198.18.0.74
198.18.0.173
198.18.0.6

성주님께서 주신 IP 추출 팁

오랜만에 머리를 굴렸더니 재미있었다.

오늘도 같이 머리를 싸매서 고민을 해주신 봄님, iamai 님, 성주님께 감사를 드린다.

더좋은 아이디어나 생각이 있다면 얼른 결과를 공유해주시길 바란다!

즐거운 새벽되시라!

하고 누우려는데 성주님께서 주신 IP list 로 하나더 만들고 싶었다.

k get ep my-service1 -o custom-columns=IP:.subsets[].addresses[*].ip | tr "," "\n" | grep -v IP | grep -f - <(kubectl get po -o wide --show-labels) 
my-nginx1-67f499d79c-g7vr7   1/1     Running    0          27h   198.18.0.74    nks-pool-1119-w-gzg   <none>           <none>            app=my-nginx1,pod-template-hash=67f499d79c
my-nginx1-67f499d79c-j4f9k   1/1     Running    0          27h   198.18.2.250   nks-pool-1119-w-gzh   <none>           <none>            app=my-nginx1,pod-template-hash=67f499d79c
my-nginx1-67f499d79c-mqxzs   1/1     Running    1          27h   198.18.1.208   nks-pool-1119-w-gzi   <none>           <none>            app=my-nginx1,pod-template-hash=67f499d79c

성주님+iamai님의 조언을 합쳤다 중간에 grep -v IP 는 내 생각이다.

시원하게 끝내고 잔다!

정말로 좋은새벽되시라.

kubernetes-CentOS7-install

작년 10월 작성했던 install script가 달라졌다.

<#!/bin/sh
setenforce 0
sed -i --follow-symlinks 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/sysconfig/selinux
swapoff -a
modprobe br_netfilter
echo '1' > /proc/sys/net/bridge/bridge-nf-call-iptables
yum install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
yum install -y docker-ce
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
EOF
yum install -y kubelet kubeadm kubectl
sed -i "s|ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock|ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --exec-opt native.cgroupdriver=systemd|" /usr/lib/systemd/system/docker.service
echo "net.bridge.bridge-nf-call-ip6tables = 1" >> /etc/sysctl.conf
echo "net.bridge.bridge-nf-call-iptables = 1" >> /etc/sysctl.conf
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
sysctl -p
systemctl enable docker
systemctl enable kubelet

큰 틀의 변화라면 작년의 클러스터 설치에선 kubeadm.conf 에서 docker와 kube의 cgroup을 변경해주는 방식이 었다면 근래에는 Docker의 Cgroup를 변경해야한다.

error: failed to run Kubelet: failed to create kubelet:
misconfiguration: kubelet cgroup driver: "systemd" is different from docker cgroup driver: "cgroupfs"

그렇지 않으면 위와같은 에러가 발생한다. 이에러를 피하기위해 sed 로 Docker의 systemctl service file에서 docker exec 구문에 --exec-opt native.cgroupdriver=systemd native driver의 실행을 수정해 주면된다.

변경된지 확인하는방법은

docker info | grep systemd
Cgroup Driver: systemd

명령어로 cgroup 를 확인할수 있다.

여기까지 확인되었으면, 작업한 Server의 스냅샷을 생성후, 스냅샷을 기반으로 워커노드3대를 생성한다.

위에작성한 스크립트는 init script 에서도 프로비저닝시에 사용할수있도록 만들었으니 그냥 사용해도 된다.

스냅샷이 잘 생성되면 kubectl init 를 하자.

kubeadm init --pod-network-cidr=10.254.0.0/16

init 가 끝나면 config 를 복사해준다

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
export KUBECONFIG=/etc/kubernetes/admin.conf

명령어로 복사를한다. 설치과정에서 프린팅된다 admin.conf 까지 같이 export 한다.

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 10.0.10.9:6443 --token 6ghues.yxwqnp87920d4arm \
	--discovery-token-ca-cert-hash sha256:49c750f19ef34b5f3ab73ceb91a2ce540a65418b693c24a1ee5acaeee2e80972 

다음과 같은 내용이 프린팅되는데 join 부분만 쓰면된다.

woker node에서 join한다

[preflight] Running pre-flight checks
	[WARNING Hostname]: hostname "k8s-worker-003" could not be reached
	[WARNING Hostname]: hostname "k8s-worker-003": lookup k8s-worker-003 on 169.254.169.53:53: no such host
[preflight] Reading configuration from the cluster...
[preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml'
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Starting the kubelet
[kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap...

This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.

Run 'kubectl get nodes' on the control-plane to see this node join the cluster.

다음 메시지가 나오면 정상적으로 클러스터가 셋팅된 것이다.

echo 'source <(kubectl completion bash)' >>~/.bashrc
kubectl completion bash >/etc/bash_completion.d/kubectl
echo 'alias k=kubectl' >>~/.bashrc
echo 'complete -F __start_kubectl k' >>~/.bashrc

bash 에서 shell 자동완성 설정까지 넣어주면 완성이다.

TAB을 이용한 자유를 누려보자!

K8s-CNI-정리

https://cloud.google.com/kubernetes-engine/docs/concepts/network-overview?hl=ko

오리뎅이 님의 쿠버네티스 네트워킹 PPT 자료입니다.

오리뎅이 님의 쿠버네티스 네트워킹 PPT 자료입니다.

두가지 URL로 CNI와 iptables의 연관 관계를 이해하고 정리 해보려한다.

CNI는 L2 / L3 / overlay 를 구성 및 k8s 의 네트워크을 관리한다.
이 때 k8s의 라우팅은 kube-proxy를 이용해서 iptables 룰을 관리한다.

iptables는 netfilter의 라우팅 룰을 편리하게 사용할수 있도록 만들어진 인터페이스고, 실제로는 패킷을 필터링하고 라우팅하는 역할은 netfilter가 맡게된다.

-_-;

ipvs 모드는 또 다시 생각해보자.

https://docs.projectcalico.org/networking/enabling-ipvs

일단 k8s 의 iptables_mode가 굉장히 비 효율적인 방법이라는건 알 수 있었다.

k8s-cmd

yum install bash-completion -y
source <(kubectl completion bash)
echo "source <(kubectl completion bash)" >> ~/.bashrc

kubectl apply -f 파일명
kubectl apply -k ./경로

kubectl create -f 파일

kubectl get node
kubectl get pods
kubectl get pods --all-namespaces
kubectl get service
kubectl get events
kubectl get pv
kubectl get pvc
kubectl get pc

kubectl delete -f 파일명
kubectl delete -k 파일명

k8s-Centos7-install

#!/bin/sh
setenforce 0
sed -i --follow-symlinks 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/sysconfig/selinux
swapoff -a
modprobe br_netfilter
echo '1' > /proc/sys/net/bridge/bridge-nf-call-iptables
yum install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
yum install -y docker-ce
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
EOF

yum install -y kubelet kubeadm kubectl
systemctl enable docker
systemctl enable kubelet
sed -i 's/cgroup-driver=systemd/cgroup-driver=cgroupfs/g' /usr/lib/systemd/system/kubelet.service.d/10-kubeadm.conf

K8s centos7 base install

userdate 등에 넣고 쓸수있다.

#Master 에서 작업

kubeadm init --pod-network-cidr=사용하려는 pod cidr
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

kubeadm join token 이 나오면 cluster node 에서 join 해준다

kubernetes-newbe-1

개념만 맨날 보고 관리형만 썼더니 날 kuber는 완전 젬벵이었다.

그래서 CKA공부를 시작했다.

9월2일부터 시작해서 오늘 External-lb까지 설정해보았다.

정보가 너무 많고 다양한데 길잡이는 없었다.

그래서 이번 블로깅 컨셉을 잡았다.

리눅서의 쿠버 길잡이다.

앞으로 추가되는 포스팅 기대하시라!