실습

ClusterIP

  1. Deployment 생성

    cat <<'EOF' | kubectl apply -f -
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          labels:
            app: nginx
        spec:
          containers:
          - name: nginx
            image: nginx
            ports:
            - containerPort: 80
            volumeMounts:
            - name: html
              mountPath: /usr/share/nginx/html
          initContainers:
          - name: index
            image: curlimages/curl
            command:
            - "sh"
            - "-c"
            - "echo 'hello from $(POD_NAME), my ip is $(POD_IP)' > /data/index.html"
            volumeMounts:
            - name: html
              mountPath: /data
            env:
            - name: POD_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: POD_IP
              valueFrom:
                fieldRef:
                  fieldPath: status.podIP
          volumes:
          - name: html
            emptyDir: {}
    EOF
  2. Service 생성

    kubectl expose deployment nginx --port 80
  3. 생성된 Service 확인

    kubectl get svc nginx -o wide
  4. 생성된 Endpoint 확인

    kubectl get ep nginx
  5. 생성된 Pod의 IP주소 확인

    kubectl get pod -l app=nginx -o wide
  6. Endpoint에 타겟으로 등록되어 있는 Pod 목록 확인

    kubectl get ep nginx \
    -o jsonpath='{range .subsets[*].addresses[*]}{.targetRef.name}{"\t"}{.ip}{"\n"}{end}'
  7. 생성된 Deployment의 Replica 갯수를 6개로 조정

    kubectl scale deployment nginx --replicas=6
  8. 생성된 Pod의 IP주소 확인

    kubectl get pod -l app=nginx -o wide
  9. Endpoint에 타겟으로 등록되어 있는 Pod 목록 확인

    kubectl get ep nginx \
    -o jsonpath='{range .subsets[*].addresses[*]}{.targetRef.name}{"\t"}{.ip}{"\n"}{end}'
  10. Pod 생성

    kubectl run curl --image=nginx -- sleep 3600
  11. 위에서 생성한 Pod에서 Service 호출

    kubectl exec curl -- \
    bash -c "for i in {1..20};do curl -s $(kubectl get svc nginx -o=jsonpath='{.spec.clusterIP}');done"
  12. 새로운 터미널을 열고 kube-proxy 로그 확인 - 아래의 명령어를 입력하고 엔터키를 몇번 입력해서 간격을 만들어두면 새로운 로그를 좀 더 쉽게 알아볼수 있음

    kubectl -n kube-system logs ds/kube-proxy -f
  13. 기존 터미널로 돌아와서 생성된 Deployment의 Replica 갯수를 3개로 조정

    kubectl scale deployment nginx --replicas=3
  14. 다른 터미널로 이동해서 kube-proxy 로그 확인

  15. 새로운 터미널을 열고 한개의 Node로 Session Manager 연결

    aws ssm start-session --target \
    $(kubectl get node -o jsonpath='{.items[0].spec.providerID}{"\n"}' | grep -oE "i-[a-z0-9]+")
  16. Iptable의 모든 규칙 확인

    sudo iptables-save
  17. Iptable의 NAT 규칙 확인

    sudo iptables -L -t nat
  18. KUBE-SERVICES 규칙 확인

    sudo iptables -t nat -L KUBE-SERVICES -n  | column -t
  19. 생성된 Service의 Cluster IP로 연결된 규칙 값을 환경변수로 저장

    export SERVICE_CHAIN=$(sudo iptables -t nat -L KUBE-SERVICES -n  | column -t | grep "default/nginx" | grep -oE "^KUBE-SVC-[A-Z0-9]+")
    echo $SERVICE_CHAIN
  20. Service의 Cluster IP로 연결된 규칙의 상세내용 확인

    sudo iptables -t nat -L $SERVICE_CHAIN -n  | column -t
  21. 위의 명령어로 나온 결과중의 한개의 Chain 규칙 확인

    sudo iptables -t nat -L $(sudo iptables -t nat -L $SERVICE_CHAIN -n  | column -t | grep -oE "^KUBE-SEP-[A-Z0-9]+" | head -1) \
    -n  | column -t
  22. 첫번째 터미널로 이동해서 생성된 Pod의 IP주소 확인

    kubectl get pod -o wide -l app=nginx
  23. 생성된 Deployment의 Replica 갯수를 6개로 조정

    kubectl scale deployment nginx --replicas=6
  24. 두번째 터미널에서 kube-proxy 로그 확인

  25. 세번째 터미널로 이동해서 20번 명령어 재실행

  26. 첫번째 터미널로 이동해서 CoreDNS 설정 파일 확인

    kubectl -n kube-system get cm coredns -o yaml | yq e '.data' -
  27. log 플러그인 활성화 - https://coredns.io/plugins/log

    cat <<EOF | kubectl apply -f -
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: coredns
      namespace: kube-system
      labels:
        eks.amazonaws.com/component: coredns
        k8s-app: kube-dns
    data:
      Corefile: |
        .:53 {
            errors
            health
            kubernetes cluster.local in-addr.arpa ip6.arpa {
              pods insecure
              fallthrough in-addr.arpa ip6.arpa
            }
            prometheus :9153
            forward . /etc/resolv.conf
            cache 30
            loop
            reload
            loadbalance
            log
        }
    EOF
  28. CoreDNS Pod 재배포

    {
        kubectl -n kube-system scale deployment coredns --replicas=0
        sleep 60
        kubectl -n kube-system scale deployment coredns --replicas=2
        sleep 10
        kubectl -n kube-system get pod -l k8s-app=kube-dns
    }
  29. 두번째 터미널에서 CoreDNS 로그 확인

    kubectl -n kube-system logs deploy/coredns -f
  30. 첫번째 터미널로 이동해서 Pod안에 설정된 DNS 설정 파일 확인

    kubectl exec curl -- cat /etc/resolv.conf
  31. CoreDNS 주소 확인

    kubectl -n kube-system get svc kube-dns
  32. CURL 명령어로 Service 이름 호출

    kubectl exec curl -- curl -s nginx
  33. 두번째 터미널에서 CoreDNS 로그 확인 - 새로운 로그 출력되지 않으면 32번 명령어를 다시 수행

  34. 첫번째 터미널로 이동해서 새로운 Namespace 생성

    kubectl create ns web
  35. 생성한 Namespace 안에 Deployment 생성

    kubectl -n web create deployment httpd --image=httpd --port=80
  36. Service 생성

    kubectl -n web expose deployment httpd
  37. CURL 명령어로 Service 이름 호출

    kubectl exec curl -- curl -s httpd
  38. 두번째 터미널에서 CoreDNS 로그 확인 - 새로운 로그 출력되지 않으면 37번 명령어를 다시 수행

  39. CURL 명령어로 Service 호출 - service.namespace

    kubectl exec curl -- curl -s httpd.web
  40. CURL 명령어로 Service 호출 - service.namespace.svc

    kubectl exec curl -- curl -s httpd.web.svc
  41. CURL 명령어로 Service 호출 - service.namespace.svc.cluster

    kubectl exec curl -- curl -s httpd.web.svc.cluster
  42. CURL 명령어로 Service 호출 - FQDN

    kubectl exec curl -- curl -s httpd.web.svc.cluster.local
  43. 생성한 리소스 삭제

    {
        kubectl delete ns web
        kubectl delete pod curl
        kubectl delete svc nginx
        kubectl delete deploy nginx
    }

NodePort

  1. Deployment 생성

    kubectl create deployment nginx --image=nginx --port=80 --replicas=3
  2. Service 생성

    kubectl expose deployment nginx --type=NodePort
  3. 생성된 Service 확인

    kubectl get svc nginx -o wide
  4. Node의 공인 IP 주소 확인

    kubectl get node -o wide
  5. 웹 브라우저를 열고 NODE_EXTERNAL_IP:NODEPORT 주소로 접속 시도 - 아래의 명령어로 주소 확인 가능

    echo $(kubectl get node -o=jsonpath='{.items[0].status.addresses[?(@.type=="ExternalIP")].address}')\
    :$(kubectl get svc nginx -o=jsonpath='{.spec.ports[0].nodePort}')
  6. 접속이 안될 경우에는 Node의 보안그룹 확인

    aws ec2 describe-security-groups --group-ids \
    $(aws ec2 describe-instances --instance-ids \
    $(kubectl get node -o jsonpath='{.items[0].spec.providerID}{"\n"}' | grep -oE "i-[a-z0-9]+") \
    --query 'Reservations[0].Instances[0].SecurityGroups[*].GroupId' --output text) \
    --query "SecurityGroups[*].IpPermissions"
  7. 보안그룹에 Service에 명시된 포트에 대한 인바운드 규칙이 없을 경우에 아래의 명령어로 규칙 추가

    aws ec2 authorize-security-group-ingress --group-id \
    $(aws ec2 describe-instances --instance-ids \
    $(kubectl get node -o jsonpath='{.items[0].spec.providerID}{"\n"}' | grep -oE "i-[a-z0-9]+") \
    --query 'Reservations[0].Instances[0].SecurityGroups[0].GroupId' --output text) \
    --protocol tcp \
    --port $(kubectl get svc nginx -o=jsonpath='{.spec.ports[0].nodePort}') \
    --cidr 0.0.0.0/0
  8. 보안그룹에 인바운드 규칙이 추가되었는지 확인

    aws ec2 describe-security-groups --group-ids \
    $(aws ec2 describe-instances --instance-ids \
    $(kubectl get node -o jsonpath='{.items[0].spec.providerID}{"\n"}' | grep -oE "i-[a-z0-9]+") \
    --query 'Reservations[0].Instances[0].SecurityGroups[*].GroupId' --output text) \
    --query "SecurityGroups[*].IpPermissions"
  9. 웹 브라우저를 열고 NODE_EXTERNAL_IP:NODEPORT 주소로 접속 시도 - 아래의 명령어로 주소 확인 가능

    echo $(kubectl get node -o=jsonpath='{.items[0].status.addresses[?(@.type=="ExternalIP")].address}')\
    :$(kubectl get svc nginx -o=jsonpath='{.spec.ports[0].nodePort}')
  10. 새로운 터미널을 열고 한개의 Node로 Session Manager 연결

    aws ssm start-session --target \
    $(kubectl get node -o jsonpath='{.items[0].spec.providerID}{"\n"}' | grep -oE "i-[a-z0-9]+")
  11. Iptable의 모든 규칙 확인

    sudo iptables-save
  12. KUBE-SERVICES 규칙 확인

    sudo iptables -t nat -L KUBE-SERVICES -n  | column -t
  13. KUBE-NODEPORTS 규칙 확인

    sudo iptables -t nat -L KUBE-NODEPORTS -n  | column -t
  14. 생성된 Service의 NodePort로 연결된 규칙 값을 환경변수로 저장

    export NODEPORT_CHAIN=$(sudo iptables -t nat -L KUBE-NODEPORTS -n  | column -t | grep "default/nginx" | grep -oE "^KUBE-SVC-[A-Z0-9]+")
    echo $NODEPORT_CHAIN
  15. KUBE-SERVICES 규칙 중에서 NodePort로 연결된 규칙 확인

    sudo iptables -t nat -L KUBE-SERVICES -n  | column -t | grep $NODEPORT_CHAIN
  16. 첫번째 터미널로 이동해서 Service의 Cluster IP 확인

    kubectl get svc nginx
  17. 다른 터미널로 이동해서 NodePort로 연결된 규칙의 상세내용 확인

    sudo iptables -t nat -L $NODEPORT_CHAIN -n  | column -t
  18. 위의 명령어로 나온 결과중의 한개의 Chain 규칙 확인

    sudo iptables -t nat -L \
    $(sudo iptables -t nat -L $NODEPORT_CHAIN -n  | column -t | grep -oE "^KUBE-SEP-[A-Z0-9]+" | head -1) \
    -n  | column -t
  19. 첫번째 터미널로 이동해서 생성된 Pod의 IP주소 확인

    kubectl get pod -o wide -l app=nginx
  20. 다른 터미널로 이동해서 Node에 열려있는 포트 정보 확인

    sudo netstat -tlnp
  21. CURL 명령어로 Service 호출

    curl localhost:NODEPORT
  22. 첫번째 터미널로 이동해서 보안그룹에 추가한 인바운드 규칙 삭제

    aws ec2 revoke-security-group-ingress --group-id \
    $(aws ec2 describe-instances --instance-ids \
    $(kubectl get node -o jsonpath='{.items[0].spec.providerID}{"\n"}' | grep -oE "i-[a-z0-9]+") \
    --query 'Reservations[0].Instances[0].SecurityGroups[0].GroupId' --output text) \
    --protocol tcp \
    --port $(kubectl get svc nginx -o=jsonpath='{.spec.ports[0].nodePort}') \
    --cidr 0.0.0.0/0
  23. 인바운드 규칙이 삭제되었는지 확인

    aws ec2 describe-security-groups --group-ids \
    $(aws ec2 describe-instances --instance-ids \
    $(kubectl get node -o jsonpath='{.items[0].spec.providerID}{"\n"}' | grep -oE "i-[a-z0-9]+") \
    --query 'Reservations[0].Instances[0].SecurityGroups[*].GroupId' --output text) \
    --query "SecurityGroups[*].IpPermissions"
  24. 생성한 리소스 삭제

    {
        kubectl delete deploy nginx
        kubectl delete svc nginx
    }

LoadBalancer

  1. Deployment 생성

    kubectl create deployment nginx --image=nginx --port=80 --replicas=3
  2. Service 생성

    kubectl expose deployment nginx --type=LoadBalancer
  3. 생성된 Service 확인

    kubectl get svc nginx -o wide
  4. 생성된 Service 객체에 발생한 Event 확인

    kubectl describe svc nginx
  5. 웹 브라우저를 열고 Service의 External IP 주소로 접속 - 아래의 명령어로 주소 확인 가능

    kubectl get svc nginx -o jsonpath='{.status.loadBalancer.ingress[0].hostname}{"\n"}' 
  6. 생성된 Service 상세 내용 확인

    kubectl get svc nginx -o=jsonpath='{.spec}' | jq
  7. 생성된 ELB 이름 확인

    kubectl get svc nginx -o jsonpath='{.status.loadBalancer.ingress[0].hostname}' | grep -o -E '^[a-z0-9]+' 
  8. ELB 상세 내용 확인

    aws elb describe-load-balancers --load-balancer-names \
    $(kubectl get svc nginx -o jsonpath='{.status.loadBalancer.ingress[0].hostname}' | grep -o -E '^[a-z0-9]+' )
  9. ELB의 Listener 설정 확인

    aws elb describe-load-balancers --load-balancer-names \
    $(kubectl get svc nginx -o jsonpath='{.status.loadBalancer.ingress[0].hostname}' | grep -o -E '^[a-z0-9]+' ) \
    --query 'LoadBalancerDescriptions[*].ListenerDescriptions'
  10. ELB의 보안그룹 확인

    aws elb describe-load-balancers --load-balancer-names \
    $(kubectl get svc nginx -o jsonpath='{.status.loadBalancer.ingress[0].hostname}' | grep -o -E '^[a-z0-9]+' ) \
    --query 'LoadBalancerDescriptions[*].SecurityGroups'
  11. 노드에 부여된 보안그룹에 ELB 보안그룹에 대한 새로운 인바운드 규칙이 추가 됐는지 확인

    aws ec2 describe-security-groups --group-ids \
    $(aws ec2 describe-instances --instance-ids \
    $(kubectl get node -o jsonpath='{.items[0].spec.providerID}{"\n"}' | grep -oE "i-[a-z0-9]+") \
    --query 'Reservations[0].Instances[0].SecurityGroups[*].GroupId' --output text) \
    --query "SecurityGroups[*].IpPermissions"
  12. 새로운 터미널을 열고 한개의 Node로 Session Manager 연결

    aws ssm start-session --target \
    $(kubectl get node -o jsonpath='{.items[0].spec.providerID}{"\n"}' | grep -oE "i-[a-z0-9]+")
  13. KUBE-NODEPORTS 규칙 확인

    sudo iptables -t nat -L KUBE-NODEPORTS -n  | column -t
  14. 첫번째 터미널로 이동해서 생성한 리소스 삭제

    {
        kubectl delete deploy nginx
        kubectl delete svc nginx
    }

Network Load Balancer

  1. Deployment 생성

    kubectl create deployment tcp-echo --image=istio/tcp-echo-server:1.2 --port=9000
  2. Pod 생성 확인

    kubectl get pod -l app=tcp-echo
  3. Service 생성

    cat <<EOF | kubectl apply -f -
    apiVersion: v1
    kind: Service
    metadata:
      name: tcp-echo
      annotations:
        service.beta.kubernetes.io/aws-load-balancer-type: nlb
    spec:
      selector:
        app: tcp-echo
      ports:
        - protocol: TCP
          port: 9000
          targetPort: 9000
      type: LoadBalancer
    EOF
  4. Service 상태 확인

    kubectl describe svc tcp-echo
  5. 생성된 ELB 상세 내용 확인

    aws elbv2 describe-load-balancers --names \
    $(kubectl get svc tcp-echo \
    -o jsonpath='{.status.loadBalancer.ingress[0].hostname}' \
    | grep -o -E '^[a-z0-9]+')
  6. Pod 생성

    kubectl run netcat --image=youngwjung/netcat -- sleep 3600
  7. Pod 생성 확인

    kubectl get pod netcat
  8. 생성한 Pod에서 NLB로 TCP 연결

    kubectl exec -it netcat -- \
    nc -v -q 1 $(kubectl get svc tcp-echo -o jsonpath='{.status.loadBalancer.ingress[0].hostname}') 9000
  9. 연결에 성공했다는 메시지가 나오면 터미널에 아무 글자나 입력해서 응답이 오는지 확인

    $ kubectl exec -it netcat -- nc -v -q 1 $(kubectl get svc tcp-echo -o jsonpath='{.status.loadBalancer.ingress[0].hostname}') 9000
    Connection to a0db8c37386d148afbd97efc9dc15a8f-744e5fa4f97a926c.elb.ap-northeast-2.amazonaws.com 9000 port [tcp/*] succeeded!
    kubernetes
    hello kubernetes
    aws
    hello aws
    world
    hello world
  10. 생성한 리소스 삭제

    {
        kubectl delete deploy tcp-echo
        kubectl delete svc tcp-echo
        kubectl delete pod netcat
    }

Kubectl Proxy & Port-forwarding

  1. Deployment 생성

    kubectl create deployment nginx --image=nginx --port=80 --replicas=1
  2. 생성된 Pod 확인

    kubectl get po -l app=nginx
  3. Service 생성

    kubectl expose deployment nginx
  4. 생성된 Service 확인

    kubectl get svc nginx
  5. Kubectl proxy 구동

    kubectl proxy --port=8080 --accept-hosts=.* --address=0.0.0.0 
  6. 새로운 터미널을 열고 아래의 주소로 접근 시도

    curl -L localhost:8080/api/v1/namespaces/default/services/nginx:80/proxy
  7. 생성된 Pod 이름을 환경변수로 저장

    {
        export POD_NAME=$(kubectl get pod -l app=nginx -o=jsonpath='{.items[0].metadata.name}')
        echo $POD_NAME
    }
  8. 아래의 주소로 접근 시도

    curl -L localhost:8080/api/v1/namespaces/default/pods/$POD_NAME:80/proxy
  9. 첫번째 터미널로 이동해서 실행중인 kubectl proxy 프로세스 종료

  10. 생성된 Pod 이름을 환경변수로 저장

    {
        export POD_NAME=$(kubectl get pod -l app=nginx -o=jsonpath='{.items[0].metadata.name}')
        echo $POD_NAME
    }
  11. 로컬포트를 Pod의 포트로 포워딩

    kubectl port-forward $POD_NAME 8080:80 --address=0.0.0.0
  12. 다른 터미널로 이동해서 Pod에 배포된 NGINX 서버로 접근 시도

    curl localhost:8080
  13. 첫번째 터미널로 이동해서 실행중인 kubectl port-forward 프로세스 종료

  14. 로컬포트를 Service의 포트로 포워딩

    kubectl port-forward svc/nginx 8080:80 --address=0.0.0.0
  15. 다른 터미널로 이동해서 Service로 접근 시도

    curl localhost:8080
  16. 첫번째 터미널로 이동해서 실행중인 kubectl port-forward 프로세스 종료

  17. 생성한 리소스 삭제

    {
        kubectl delete deploy nginx
        kubectl delete svc nginx
    }

ExternalName

  1. Service 생성

    cat <<EOF | kubectl apply -f -
    apiVersion: v1
    kind: Service
    metadata:
      name: k8s
    spec:
      type: ExternalName
      externalName: kubernetes.io
    EOF
  2. Service 상태 확인

    kubectl describe svc k8s
  3. Pod 생성

    kubectl run curl --image=curlimages/curl --command -- sleep 3600
  4. 위에서 생성한 Service 호출

    kubectl exec curl -- curl -sL k8s
  5. 위에서 생성한 Service 호출 - 호스트 명시

    kubectl exec curl -- curl -sL -H "Host: kubernetes.io" k8s
  6. 위에서 생성한 Service 호출 - 호스트 명시하고 새로운 경로 호출

    kubectl exec curl -- curl -sL -H "Host: kubernetes.io" k8s/docs
  7. 리소스 삭제

    {
        kubectl delete svc k8s
        kubectl delete pod curl
    }

Last updated