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

k8s ValidatingWebhookConfiguration 으로 문법 에러 ingress 리소스 생성 방지

# kubectl 과 같은 api 요청을 받는 k8s 서버는 kube-api handler 이후 요청한 리소스에 대해 mutating(리소스 변경),validating(리소스 검증) admission(허용 여부 판단 webhook) 처리를 하여 실제 리소스 설정(etcd 에 저장)될지 말지를 처리한다.

# nginx 에 적용될 server-snippet 등에 문법이 에러가 있는 ingress (리소스)를 적용 요청을 하면 에러 없이 리소스가 생성(등록)되는게 문제다.
kubectl apply -f syntax_error_ingress.yaml
ingress.extensions/ysoftman-test-ingress created

# nginx log 확인해 보면 에러 ingress 리소스 로드 시도가 계속 실패
kubectl logs -f $(kubectl get pod -n ingress-nginx | rg -N ingress-nginx-controller --color never  | awk '{print $1}')
 -------------------------------------------------------------------------------
Error: exit status 1
2021/12/22 17:19:34 [emerg] 15035#15035: invalid number of arguments in "proxy_set_header" directive in /tmp/nginx-cfg062794518:1076
nginx: [emerg] invalid number of arguments in "proxy_set_header" directive in /tmp/nginx-cfg062794518:1076
nginx: configuration file /tmp/nginx-cfg062794518 test failed
-------------------------------------------------------------------------------
W1222 17:19:34.507544       7 queue.go:130] requeuing ysoftman-test/ysoftman-test-ingress, err
-------------------------------------------------------------------------------

# 잘못된 ingress 리소스가 등록되어 계속 nginx 가 리로딩 실패해 문제가 되니 바로 지우자.
kubectl delete -f syntax_error_ingress.yaml

# 잘못된 설정으로 ingress-nginx-controller 가 전체에 영향 주는것을 막기 위해
# validating admission webhook server 를 옵션으로 노출할 수 있다.
# ValidatingWebhookConfiguration 리소스를 등록한다.


#####


# ValidatingWebhookConfiguration 으로 문법 에러 ingress 리소스 생성 방지하기

# (minikube 기준) kube-apiserver enable-admission-plugins 옵션에 ValidatingAdmissionWebhook 가 있는지 확인
kubectl get pod kube-apiserver-minikube -o=json -n kube-system | jq '.spec.containers[0].command' | rg -N "enable-admission-plugins"
  "--enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota",

# ValidatingAdmissionWebhook 보이지 않아도 디폴트로 추가되어 있어 별도로 추가하지 않아도 된다.
# master 노드(장비) 마다 접속해 다음 파일에서
# --enable-admission-plugins 값을 추가하면
# kubelet(cluster의 모든 노드에 떠있는 agent)이 변경을 감지해 kube-apiserver(pod)가 자동으로 재시작 된다.
sudo vi /etc/kubernetes/manifests/kube-apiserver.yaml


# 방법1 - helm 으로 설치하면 ValidatingWebhookConfiguration 관련 리소스들이 자동 설치된다.


# 방법2 - ValidatingWebhookConfiguration 수동 등록
# 다음 명령 결과가 있다면 admission controller 를 사용할 수 있다.
# k8s 버전에 따라 
# k8s 1.6 이후는 admissionregistration.k8s.io/v1
# k8s 1.9 이후는 admissionregistration.k8s.io/v1beta1
kubectl api-versions | grep admissionregistration

# ingress-nginx-controller 버전 확인
kubectl get daemonset ingress-nginx-controller -n ingress-nginx -o=json | jq '.spec.template.spec.containers[0].image'
"quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.25.1"

# ValidatingWebhookConfiguration 은 TLS 로 통신해야 한다.
# 다음과 같이 self-singed 로 키를 생성한다.
# service 에서 사용할 이름이 매칭될 수 있도록 CN을 다음과 같이 설정한다. (CN=${SERVICE_NAME}.${NAMESPACE}.svc)
openssl req -x509 -newkey rsa:2048 -keyout validating-webhook-key.pem -out validating-webhook-cert.pem -days 100000 -nodes -subj "/CN=ingress-nginx-controller-admission.ingress-nginx.svc"

# secret 리소스를 등록하자.(base64 인코딩돼 등록되기 때문에 secret 리소스를 보면 LS0... 으로 시작하는 문자열이 된다.)
kubectl create secret tls ingress-validation-tls -n ingress-nginx \
--key validating-webhook-key.pem \
--cert validating-webhook-cert.pem

# ingress-nginx-controller 옵션 --validating-webhook 옵션들 추가
# secret 는 volumes, volumeMounts 로 pod 에서 파일로 접근하도록 한다.
kubectl edit daemonset ingress-nginx-controller -n ingress-nginx
... 생략 ...
      containers:
      - args:
        - /nginx-ingress-controller
        - --enable-ssl-chain-completion=false
        - --configmap=$(POD_NAMESPACE)/ingress-nginx
        - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
        - --udp-services-configmap=$(POD_NAMESPACE)/udp-services
        - --annotations-prefix=nginx.ingress.kubernetes.io
        - --default-backend-service=default/default-backend-service
        - --report-node-internal-ip-address
        - --validating-webhook=:8443
        - --validating-webhook-certificate=/usr/local/certificates/tls.crt
        - --validating-webhook-key=/usr/local/certificates/tls.key
... 생략 ...
        ports:
        - containerPort: 8443
          name: webhook
          protocol: tcp
... 생략 ...
          volumeMounts:
          - name: webhook-cert
            mountPath: /usr/local/certificates/
            readOnly: true
... 생략 ...
      volumes:
      - name: webhook-cert
        secret:
          secretName: ingress-validation-tls

# ValidatingWebhookConfiguration 과 ingress-nginx-controller-admission service 리소스 등록은 아래 URL에 정리


#####


# 참고 이슈(삽질 엄청함ㅠ)
# 위의 모든 설정을 했는데 invalid ingress 가 아무런 제약없이 created 된다.
# ingrss nginx controller pod 로그를 보면 validationwebhook 은 동작되지만
kubectl logs -f $(kubectl get pod -n ingress-nginx | rg -N ingress-nginx-controller --color never  | awk '{print $1}') | rg "admission" -C 2

# 다음 로그 처럼 accepting 되는 문제가 있었다.
server.go:61] handling admission controller request /extensions/v1beta1/ingress?timeout=10s
main.go:87] accepting non ingress  in namespace ysoftman-test-namespace extensions/v1beta1, Resource=ingresses

# 나와 같이 nginx-ingress-controller:0.25.1 에서
# extensions/v1beta1 를 사용하지 못하는 문제가 있었다.

# syntax_error_ingress apiVersion 을 다음과 같이 변경
extensions/v1beta1 --> networking.k8s.io/v1beta1

# ValidatingWebhookConfiguration 에 networking.k8s.io/v1beta api 추가
  - apiGroups:
    - networking.k8s.io
    - extensions
    apiVersions:
    - v1
    - v1beta1
... 생략 ...
      path: /networking.k8s.io/v1beta1/ingresses

# 이제 server_snippnet 오타가 있는 ingress 등록시 에러가 발생하고 생성되지 않는다.
kubectl apply -f syntax_error_ingress.yaml
namespace/ysoftman-test-namespace unchanged
Error from server: error when creating "syntax_error_ingress.yaml": admission webhook "validate.nginx.ingress.kubernetes.io" denied the request:
-------------------------------------------------------------------------------
Error: exit status 1
2021/12/28 19:11:31 [emerg] 1385#1385: unexpected "}" in /tmp/nginx-cfg650933801:19967
nginx: [emerg] unexpected "}" in /tmp/nginx-cfg650933801:19967
nginx: configuration file /tmp/nginx-cfg650933801 test failed

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

# 앱 배포(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

# 참고 kubectl 명령들