# 실습

## Ingress-NGINX Controller

### Introduction

1. Helm 차트 리포지토리 추가&#x20;

   ```
   {
       helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
       helm repo update
   }
   ```
2. Ingress-NGINX  Controller 설치&#x20;

   ```
   helm install ingress-nginx ingress-nginx/ingress-nginx -n kube-system \
   --set controller.service.annotations.service\\.beta\\.kubernetes\\.io/aws-load-balancer-type=nlb
   ```
3. 배포된 구성요소 확인&#x20;

   ```
   kubectl -n kube-system get all -l app.kubernetes.io/name=ingress-nginx
   ```
4. 생성된 Service 확인

   ```
   kubectl -n kube-system get svc ingress-nginx-controller
   ```
5. 생성된 NLB 상세 내용 확인

   ```
   aws elbv2 describe-load-balancers --names \
   $(kubectl -n kube-system get svc ingress-nginx-controller \
   -o jsonpath='{.status.loadBalancer.ingress[0].hostname}' \
   | grep -o -E '^[a-z0-9]+' ) --no-cli-pager
   ```
6. 웹 브라우저를 열고 Service의 External IP 주소로 접속 - *아래의 명령어로 주소 확인 가능*&#x20;

   ```
   kubectl -n kube-system get svc ingress-nginx-controller \
   -o jsonpath='{.status.loadBalancer.ingress[0].hostname}{"\n"}' 
   ```
7. 생성된 NGINX Ingress Controller Pod에서 실행중인 프로세스 확인&#x20;

   ```
   kubectl -n kube-system exec deploy/ingress-nginx-controller -- \
   ps aux
   ```
8. NGINX 설정 파일 리뷰&#x20;

   ```
   kubectl -n kube-system exec deploy/ingress-nginx-controller -- \
   cat /etc/nginx/nginx.conf
   ```
9. 생성된 NLB 주소로 접속했을때 404 Not Found가 나오는 이유 확인

   ```
   kubectl -n kube-system exec deploy/ingress-nginx-controller -- \
   cat /etc/nginx/nginx.conf | grep 404 -B 9 -A 2
   ```

### Virtual hosting

1. Deployment 생성&#x20;

   ```
   {
       kubectl create deployment nginx --image=nginx --port=80
       kubectl create deployment httpd --image=httpd --port=80
   }
   ```
2. Service 생성&#x20;

   ```
   {
       kubectl expose deploy nginx 
       kubectl expose deploy httpd
   }
   ```
3. 생성된 Service 확인&#x20;

   ```
   kubectl get svc -l app
   ```
4. Ingress 생성&#x20;

   ```
   cat <<EOF | kubectl apply -f -
   apiVersion: networking.k8s.io/v1
   kind: Ingress
   metadata:
     name: nginx
   spec:
     rules:
     - host: nginx.example.com
       http:
         paths:
         - path: /
           pathType: Prefix
           backend:
             service:
               name: nginx
               port:
                 number: 80
   ---
   apiVersion: networking.k8s.io/v1
   kind: Ingress
   metadata:
     name: httpd
   spec:
     rules:
     - host: httpd.example.com
       http:
         paths:
         - path: /
           pathType: Prefix
           backend:
             service:
               name: httpd
               port:
                 number: 80
   EOF
   ```
5. 생성된 Ingress 확인 &#x20;

   ```
   kubectl get ing
   ```
6. NGINX Ingress Controller 로그 확인

   ```
   kubectl logs -n kube-system deploy/ingress-nginx-controller
   ```
7. 생성된 IngressClass 확인

   ```
   kubectl get ingressclass
   ```
8. Ingress 수정 - *IngressClass 명시*

   ```
   cat <<EOF | kubectl apply -f -
   apiVersion: networking.k8s.io/v1
   kind: Ingress
   metadata:
     name: nginx
   spec:
     ingressClassName: nginx
     rules:
     - host: nginx.example.com
       http:
         paths:
         - path: /
           pathType: Prefix
           backend:
             service:
               name: nginx
               port:
                 number: 80
   ---
   apiVersion: networking.k8s.io/v1
   kind: Ingress
   metadata:
     name: httpd
   spec:
     ingressClassName: nginx
     rules:
     - host: httpd.example.com
       http:
         paths:
         - path: /
           pathType: Prefix
           backend:
             service:
               name: httpd
               port:
                 number: 80
   EOF
   ```
9. Ingress 객체에 발생한 Event 확인 &#x20;

   ```
   kubectl describe ing
   ```
10. NGINX Ingress Controller 엔드포인트 확인 &#x20;

    ```
    kubectl -n kube-system get svc ingress-nginx-controller
    ```
11. NGINX Ingress Controller 로그 확인

    ```
    kubectl logs -n kube-system deploy/ingress-nginx-controller
    ```
12. Ingress에 명시한 Host 주소를 HTTP 헤더값에 추가하고 NGINX Ingress Controller 엔드포인트 호출

    ```
    curl -H "Host: nginx.example.com" \
    $(kubectl -n kube-system get svc ingress-nginx-controller \
    -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
    ```

    ```
    curl -H "Host: httpd.example.com" \
    $(kubectl -n kube-system get svc ingress-nginx-controller \
    -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
    ```
13. NGINX 설정 파일에 위에서 명시한 Host들에 대한 설정들이 추가 되었는지 확인&#x20;

    ```
    kubectl -n kube-system exec deploy/ingress-nginx-controller -- \
    cat /etc/nginx/nginx.conf \
    | grep "server_name nginx.example.com" -B 1 -A 130
    ```

    ```
    kubectl -n kube-system exec deploy/ingress-nginx-controller -- \
    cat /etc/nginx/nginx.conf \
    | grep "server_name httpd.example.com" -B 1 -A 130
    ```
14. Ingress 삭제

    ```
    kubectl delete ing nginx httpd
    ```
15. NGINX 설정 파일에 위에서 삭제한 Ingress 명시한 Host들에 대한 설정들이 삭제 되었는지 확인

    ```
    kubectl -n kube-system exec deploy/ingress-nginx-controller -- \
    cat /etc/nginx/nginx.conf \
    | grep "server_name nginx.example.com" -B 1 -A 130
    ```

    ```
    kubectl -n kube-system exec deploy/ingress-nginx-controller -- \
    cat /etc/nginx/nginx.conf \
    | grep "server_name httpd.example.com" -B 1 -A 130
    ```
16. 리소스 삭제

    ```
    {
        kubectl delete svc nginx httpd
        kubectl delete deploy nginx httpd
    }
    ```

### Path based routing

1. 리소스 생성

   ```
   {
       kubectl create deployment nginx --image=nginx --port=80
       kubectl create deployment httpd --image=httpd --port=80
       kubectl expose deploy nginx 
       kubectl expose deploy httpd
   }
   ```
2. 생성된 리소스 확인

   ```
   kubectl get all -l app
   ```
3. Ingress 생성

   ```
   cat <<EOF | kubectl apply -f -
   apiVersion: networking.k8s.io/v1
   kind: Ingress
   metadata:
     name: my-app
   spec:
     ingressClassName: nginx
     rules:
     - host: myapp.example.com
       http:
         paths:
         - path: /nginx
           pathType: Prefix
           backend:
             service:
               name: nginx
               port:
                 number: 80
         - path: /httpd
           pathType: Prefix
           backend:
             service:
               name: httpd
               port:
                 number: 80
   EOF
   ```
4. Ingress 객체에 발생한 Event 확인 &#x20;

   ```
   kubectl describe ing
   ```
5. NGINX Ingress Controller 로그 확인

   ```
   kubectl logs -n kube-system deploy/ingress-nginx-controller
   ```
6. Ingress에 명시한 Host 주소를 HTTP 헤더값에 추가하고 각각의 경로로 NGINX Ingress Controller 엔드포인트 호출

   ```
   curl -H "Host: myapp.example.com" \
   $(kubectl -n kube-system get svc ingress-nginx-controller \
   -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')/nginx
   ```

   ```
   curl -H "Host: myapp.example.com" \
   $(kubectl -n kube-system get svc ingress-nginx-controller \
   -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')/httpd
   ```
7. NGINX Ingress Controller 로그 확인

   ```
   kubectl logs -n kube-system deploy/ingress-nginx-controller
   ```

   e.g.

   ```
   52.78.3.76 - - [24/Jul/2022:08:16:10 +0000] "GET /nginx HTTP/1.1" 404 153 "-" "curl/7.79.1" 86 0.003 [default-nginx-80] [] 192.168.44.219:80 153 0.004 404 b69bb70369b94d0208af4cf26d5f19a5
   52.78.3.76 - - [24/Jul/2022:08:16:21 +0000] "GET /httpd HTTP/1.1" 404 196 "-" "curl/7.79.1" 86 0.001 [default-httpd-80] [] 192.168.88.56:80 196 0.000 404 efdfacfbf5858ebc27a01dcb815da8d9
   ```
8. Ingress 수정 - <https://kubernetes.github.io/ingress-nginx/examples/rewrite/>&#x20;

   ```
   cat <<EOF | kubectl apply -f -
   apiVersion: networking.k8s.io/v1
   kind: Ingress
   metadata:
     name: my-app
     annotations:
       nginx.ingress.kubernetes.io/rewrite-target: /
   spec:
     ingressClassName: nginx
     rules:
     - host: myapp.example.com
       http:
         paths:
         - path: /nginx
           pathType: Prefix
           backend:
             service:
               name: nginx
               port:
                 number: 80
         - path: /httpd
           pathType: Prefix
           backend:
             service:
               name: httpd
               port:
                 number: 80
   EOF
   ```
9. NGINX Ingress Controller 로그 확인

   ```
   kubectl logs -n kube-system deploy/ingress-nginx-controller
   ```
10. Ingress에 명시한 Host 주소를 HTTP 헤더값에 추가하고 각각의 경로로 NGINX Ingress Controller 엔드포인트 호출

    ```
    curl -H "Host: myapp.example.com" \
    $(kubectl -n kube-system get svc ingress-nginx-controller \
    -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')/nginx
    ```

    ```
    curl -H "Host: myapp.example.com" \
    $(kubectl -n kube-system get svc ingress-nginx-controller \
    -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')/httpd
    ```
11. 새로운 리소스 생성

    ```
    {
        kubectl create deployment v1 --image=youngwjung/nginx:v1 --port=80
        kubectl create deployment v2 --image=youngwjung/nginx:v2 --port=80
        kubectl expose deploy v1 
        kubectl expose deploy v2
    }
    ```
12. 새로 배포한 애플리케이션 호출

    ```
    kubectl exec deploy/v1 -- curl -s localhost
    ```

    ```
    kubectl exec deploy/v2 -- curl -s localhost
    ```
13. Ingress 수정

    ```
    cat <<EOF | kubectl apply -f -
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: my-app
      annotations:
        nginx.ingress.kubernetes.io/rewrite-target: /
    spec:
      ingressClassName: nginx
      rules:
      - host: myapp.example.com
        http:
          paths:
          - path: /nginx
            pathType: Prefix
            backend:
              service:
                name: nginx
                port:
                  number: 80
          - path: /httpd
            pathType: Prefix
            backend:
              service:
                name: httpd
                port:
                  number: 80
          - path: /nginx/v1
            pathType: Exact
            backend:
              service:
                name: v1
                port:
                  number: 80
          - path: /httpd/v2
            pathType: Exact
            backend:
              service:
                name: v2
                port:
                  number: 80
    EOF
    ```
14. NGINX Ingress Controller 로그 확인

    ```
    kubectl logs -n kube-system deploy/ingress-nginx-controller
    ```
15. Ingress에 명시한 Host 주소를 HTTP 헤더값에 추가하고 새롭게 명시한 경로들로 NGINX Ingress Controller 엔드포인트 호출

    ```
    curl -H "Host: myapp.example.com" \
    $(kubectl -n kube-system get svc ingress-nginx-controller \
    -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')/nginx/v1
    ```

    ```
    curl -H "Host: myapp.example.com" \
    $(kubectl -n kube-system get svc ingress-nginx-controller \
    -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')/httpd/v2
    ```
16. 리소스 삭제

    ```
    {
        kubectl delete svc nginx httpd v1 v2
        kubectl delete deploy nginx httpd v1 v2
        kubectl delete ing my-app
    }
    ```

### TLS/SSL

1. CFSSL 설치

   ```
   {
       VERSION=$(curl --silent "https://api.github.com/repos/cloudflare/cfssl/releases/latest" | grep '"tag_name"' | sed -E 's/.*"([^"]+)".*/\1/')
       VNUMBER=${VERSION#"v"}
       wget https://github.com/cloudflare/cfssl/releases/download/${VERSION}/cfssl_${VNUMBER}_linux_amd64 -O cfssl
       chmod +x cfssl
       sudo mv cfssl /usr/local/bin
   }
   ```
2. CA 인증서 및 CA 사설키 생성

   ```
   cat > ca.json <<EOF
   {
     "CN": "mycompany",
     "key": {
       "algo": "rsa",
       "size": 2048
     },
     "names": [
       {
         "C": "KR",
         "O": "mycompany",
         "OU": "devops"
       }
     ]
   }
   EOF
   cfssl gencert -initca ca.json | cfssljson -bare ca
   ```
3. CA 설정파일 생성

   ```
   cat > ca-config.json <<EOF
   {
     "signing": {
       "default": {
         "expiry": "8760h"
       },
       "profiles": {
         "mycompany": {
           "usages": ["signing", "key encipherment", "server auth"],
           "expiry": "8760h"
         }
       }
     }
   }
   EOF
   ```
4. 인증서 생성요청 설정파일 생성

   ```
   cat > mycompany-csr.json <<EOF
   {
     "CN": "mycompany",
     "key": {
       "algo": "rsa",
       "size": 2048
     },
     "names": [
       {
         "C": "KR",
         "O": "mycompany",
         "OU": "devops"
       }
     ]
   }
   EOF
   ```
5. 인증서 및 사설키 생성

   ```
   cfssl gencert \
   -ca=ca.pem \
   -ca-key=ca-key.pem \
   -config=ca-config.json \
   -hostname=mycompany.com \
   -profile=mycompany \
   mycompany-csr.json | cfssljson -bare mycompany
   ```
6. Secret 생성

   ```
   kubectl create secret tls mycompany-com \
   --cert=mycompany.pem \
   --key=mycompany-key.pem
   ```
7. 데모 웹사이트 배포

   ```
   {
       kubectl create deployment nginx --image=nginx --port=80
       kubectl expose deploy nginx 
   }
   ```
8. 생성된 리소스 확인

   ```
   kubectl get all -l app=nginx
   ```
9. Ingress 생성

   ```
   cat <<EOF | kubectl apply -f -
   apiVersion: networking.k8s.io/v1
   kind: Ingress
   metadata:
     name: nginx
   spec:
     ingressClassName: nginx
     tls: 
     - hosts:
       - mycompany.com
       secretName: mycompany-com
     rules:
     - host: mycompany.com
       http:
         paths:
         - path: /
           pathType: Prefix
           backend:
             service:
               name: nginx
               port:
                 number: 80
   EOF
   ```
10. Ingress 생성 확인 - *ADDRESS에 NGINX Ingress Controller 엔드포인트가 업데이트 되는지 확인*

    ```
    kubectl get ing nginx -w
    ```
11. Ingress에 명시한 Host 주소를 호출하면 NGINX Ingress Controller 엔드포인트로 연결되도록 하고 프로토콜로 데모 웹사이트 호출

    ```
    curl -v --cacert ca.pem https://mycompany.com \
    --connect-to mycompany.com:443:\
    $(kubectl -n kube-system get svc ingress-nginx-controller \
    -o jsonpath='{.status.loadBalancer.ingress[0].hostname}'):443
    ```
12. 리소스 삭제

    ```
    {
        kubectl delete ing nginx
        kubectl delete deploy nginx
        kubectl delete svc nginx
        kubectl delete secret mycompany-com
        rm ca*
        rm mycompany*
    }
    ```

### Clean up

1. NGINX Ingress Controller 삭제&#x20;

   ```
   kubectl delete -f \
   https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/aws/deploy.yaml
   ```

## AWS Load Balancer Controller

### Introduction

1. EKS 클러스터가 생성되어 있는 AWS 계정번호 확인하고 환경변수로 저장

   ```
   {
       export ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
       echo $ACCOUNT_ID
   }
   ```
2. Node에 부여된 Label을 통해서 EKS 클러스터 이름 확인하고 환경변수로 저장

   ```
   {
       export CLUSTER_NAME=$(kubectl get node \
       -o=jsonpath='{.items[0].metadata.labels.alpha\.eksctl\.io\/cluster-name}')
       echo $CLUSTER_NAME
   }
   ```
3. IAM OIDC 제공자 생성&#x20;

   ```
   eksctl utils associate-iam-oidc-provider \
   --region ap-northeast-2 \
   --cluster $CLUSTER_NAME \
   --approve
   ```
4. AWS Load Balancer Controller에 부여할 IAM 권한이 명시된 JSON 파일 다운로드

   ```
   curl -o aws-loadbalancer-controller-policy.json \
   https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/main/docs/install/iam_policy.json
   ```
5. 다운받은 IAM 정책 JSON 파일 리뷰

   ```
   cat aws-loadbalancer-controller-policy.json
   ```
6. IAM 정책 생성&#x20;

   ```
   aws iam create-policy \
   --policy-name AWSLoadBalancerControllerIAMPolicy \
   --policy-document file://aws-loadbalancer-controller-policy.json
   ```
7. 이미 IAM 정책이 존재할 경우 정책 문서 업데이트&#x20;

   ```
   {
     NON_DEFAULT_VERSIONS=$(aws iam list-policy-versions \
     --policy-arn arn:aws:iam::${ACCOUNT_ID}:policy/AWSLoadBalancerControllerIAMPolicy \
     --query 'Versions[?IsDefaultVersion==`false`].VersionId' \
     --output text)
     
     for version in $NON_DEFAULT_VERSIONS
     do
       aws iam delete-policy-version \
       --policy-arn arn:aws:iam::${ACCOUNT_ID}:policy/AWSLoadBalancerControllerIAMPolicy \
       --version-id $version
     done
     
     aws iam create-policy-version \
     --policy-arn arn:aws:iam::${ACCOUNT_ID}:policy/AWSLoadBalancerControllerIAMPolicy \
     --policy-document file://aws-loadbalancer-controller-policy.json \
     --set-as-default
   }
   ```
8. ServiceAccount 생성&#x20;

   ```
   eksctl create iamserviceaccount \
   --cluster $CLUSTER_NAME \
   --namespace=kube-system \
   --name=aws-load-balancer-controller \
   --attach-policy-arn=arn:aws:iam::${ACCOUNT_ID}:policy/AWSLoadBalancerControllerIAMPolicy \
   --override-existing-serviceaccounts \
   --approve
   ```
9. Helm이 설치되어 있지 않을 경우에는 아래의 명령어로 Helm 설치

   ```
   curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
   ```
10. EKS 리포지토리 추가&#x20;

    ```
    helm repo add eks https://aws.github.io/eks-charts
    ```
11. 위에서 추가한 리포지토리가 추가되었는지 확인

    ```
    helm repo list
    ```
12. 위에서 추가한 리포지토리에 있는 Helm 차트 목록 확인

    ```
    helm search repo eks
    ```
13. AWS Load Balancer Controller 설치

    ```
    helm install aws-load-balancer-controller eks/aws-load-balancer-controller \
    --namespace kube-system \
    --set clusterName=$CLUSTER_NAME \
    --set replicaCount=1 \
    --set serviceAccount.create=false \
    --set serviceAccount.name=aws-load-balancer-controller
    ```
14. AWS Load Balancer Controller 로그 확인

    ```
    kubectl -n kube-system logs deploy/aws-load-balancer-controller
    ```
15. 데모 웹사이트 배포

    ```
    {
        kubectl create deployment nginx --image=nginx --port=80
        kubectl expose deploy nginx 
    }
    ```
16. 생성된 리소스 확인

    ```
    kubectl get all -l app=nginx
    ```
17. Ingress 생성

    ```
    cat <<EOF | kubectl apply -f -
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: nginx
    spec:
      ingressClassName: alb
      rules:
      - http:
          paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: nginx
                port:
                  number: 80
    EOF
    ```
18. 생성된 Ingress 확인

    ```
    kubectl get ing nginx
    ```
19. 위에서 생성한 Ingress에 발생한 Event 확인

    ```
    kubectl describe ingress nginx
    ```
20. AWS Load Balancer Controller 로그 확인

    ```
    kubectl -n kube-system logs deploy/aws-load-balancer-controller
    ```
21. 에러 로그 발생원인 확인 - <https://github.com/kubernetes-sigs/aws-load-balancer-controller/issues/1695>
22. Ingress 수정

    ```
    cat <<EOF | kubectl apply -f -
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: nginx
      annotations:
        alb.ingress.kubernetes.io/target-type: ip
    spec:
      ingressClassName: alb
      rules:
      - http:
          paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: nginx
                port:
                  number: 80
    EOF
    ```
23. Ingress 상태 확인

    ```
    kubectl get ing nginx
    ```
24. Ingress에 발생한 Event 확인

    ```
    kubectl describe ingress nginx
    ```
25. AWS Load Balancer Controller 로그 확인

    ```
    kubectl -n kube-system logs deploy/aws-load-balancer-controller
    ```
26. 아래의 명령어를 실행해서 생성된 ALB 엔드포인트를 확인하고 웹브라우저를 통해서 접근이 되는지 확인

    ```
    echo $(kubectl get ing nginx -o=jsonpath='{.status.loadBalancer.ingress[0].hostname}')
    ```
27. 생성된 ALB 이름을 확인하고 환경변수로 저장

    ```
    {
        export LoadBalancerName=$(aws elbv2 describe-load-balancers | \
        jq -r '.LoadBalancers[] | 
        select(.DNSName == "'"$(kubectl get ing nginx -o=jsonpath='{.status.loadBalancer.ingress[0].hostname}')"'") | 
        .LoadBalancerName')

        echo $LoadBalancerName
    }
    ```
28. ALB의 상세 내용 확인

    ```
    aws elbv2 describe-load-balancers --names $LoadBalancerName --no-cli-pager
    ```
29. ALB의 Scheme 확인

    ```
    aws elbv2 describe-load-balancers --names $LoadBalancerName \
    --query 'LoadBalancers[0].Scheme' --output text
    ```
30. ALB가 생성된 서브넷 확인

    ```
    aws elbv2 describe-load-balancers --names $LoadBalancerName \
    --query 'LoadBalancers[0].AvailabilityZones[*]' --no-cli-pager
    ```
31. ALB가 생성된 서브넷에 부여된 태그 확인

    ```
    aws ec2 describe-subnets --subnet-ids --query 'Subnets[*].Tags' \
    $(aws elbv2 describe-load-balancers --names $LoadBalancerName \
    --query 'LoadBalancers[0].AvailabilityZones[*].SubnetId' --output text) \
    --no-cli-pager
    ```
32. AWS Load Balancer Controller가 ALB를 생성한 서브넷을 선택하는 방법 확인 - <https://kubernetes-sigs.github.io/aws-load-balancer-controller/latest/deploy/subnet_discovery>
33. AWS Load Balancer Controller로 Ingress 생성할때 요구되는 파라미터 및 기본값 확인 - <https://kubernetes-sigs.github.io/aws-load-balancer-controller/latest/guide/ingress/annotations>
34. Ingress 수정

    ```
    cat <<EOF | kubectl apply -f -
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: nginx
      annotations:
        alb.ingress.kubernetes.io/scheme: internet-facing
        alb.ingress.kubernetes.io/target-type: ip
    spec:
      ingressClassName: alb
      rules:
      - http:
          paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: nginx
                port:
                  number: 80
    EOF
    ```
35. Ingress에 발생한 Event 확인

    ```
    kubectl describe ingress nginx
    ```
36. AWS Load Balancer Controller 로그 확인

    ```
    kubectl -n kube-system logs deploy/aws-load-balancer-controller
    ```
37. 아래의 명령어를 실행해서 생성된 ALB 엔드포인트를 확인하고 웹브라우저를 통해서 접근이 되는지 확인

    ```
    echo $(kubectl get ing nginx -o=jsonpath='{.status.loadBalancer.ingress[0].hostname}')
    ```
38. 기존에 생성된 ALB가 존재하는지 확인

    ```
    aws elbv2 describe-load-balancers --names $LoadBalancerName
    ```
39. 새롭게 생성된 ALB의 ARN를 확인하고 환경변수로 저장

    ```
    {
        export LoadBalancerArn=$(aws elbv2 describe-load-balancers | \
        jq -r '.LoadBalancers[] | 
        select(.DNSName == "'"$(kubectl get ing nginx -o=jsonpath='{.status.loadBalancer.ingress[0].hostname}')"'") | 
        .LoadBalancerArn')

        echo $LoadBalancerArn
    }
    ```
40. 아파치 웹서버 배포

    ```
    {
        kubectl create deployment httpd --image=httpd
        kubectl expose deployment httpd --port=80
    }
    ```
41. Ingress 수정

    ```
    cat <<EOF | kubectl apply -f -
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: nginx
      annotations:
        alb.ingress.kubernetes.io/scheme: internet-facing
        alb.ingress.kubernetes.io/target-type: ip
    spec:
      ingressClassName: alb
      rules:
      - host: nginx.example.com
        http:
          paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: nginx
                port:
                  number: 80
      - host: httpd.example.com
        http:
          paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: httpd
                port:
                  number: 80
    EOF
    ```
42. 아래의 명령어를 실행해서 생성된 ALB 엔드포인트를 확인하고 웹브라우저를 통해서 접근이 되는지 확인

    ```
    echo $(kubectl get ing nginx -o=jsonpath='{.status.loadBalancer.ingress[0].hostname}')
    ```
43. cURL 명령어로 **Host** 값을 *nginx.example.com*으로 명시하고 ALB 엔드포인트 호출

    ```
    curl -H "Host: nginx.example.com" \
    $(kubectl get ing nginx -o=jsonpath='{.status.loadBalancer.ingress[0].hostname}') 
    ```
44. cURL 명령어로 **Host** 값을 *httpd.example.com*으로 명시하고 ALB 엔드포인트 호출

    ```
    curl -H "Host: httpd.example.com" \
    $(kubectl get ing nginx -o=jsonpath='{.status.loadBalancer.ingress[0].hostname}') 
    ```
45. ALB의 리스너 ARN를 확인하고 환경변수로 저장

    ```
    {
        export ListnerArn=$(aws elbv2 describe-listeners \
        --load-balancer-arn $LoadBalancerArn \
        --query "Listeners[0].ListenerArn" --output text)
        
        echo $ListnerArn
    }
    ```
46. ALB 리스너 확인

    ```
    aws elbv2 describe-listeners --listener-arns $ListnerArn
    ```
47. ALB 리스너 규칙 확인

    ```
    aws elbv2 describe-rules --listener-arn $ListnerArn --no-cli-pager
    ```
48. ALB에 연동된 대상그룹들의 ARN을 확인하고 환경변수로 저장

    ```
    {
        export TG=$(aws elbv2 describe-target-groups \
        --load-balancer-arn $LoadBalancerArn \
        --query "TargetGroups[*].TargetGroupArn" \
        --output text)
        
        echo $TG
    }
    ```
49. 대상그룹 확인

    ```
    aws elbv2 describe-target-groups --target-group-arns $TG --no-cli-pager
    ```
50. 대상그룹에 포함된 대상 목록 확인

    ```
    for target in $TG
    do 
      aws elbv2 describe-target-health --target-group-arn $target --no-cli-pager
    done
    ```
51. Pod 목록 확인

    ```
    kubectl get pod -o wide -l 'app in (nginx,httpd)'
    ```
52. 아파치 Deployment의 Replica 갯수를 3개로 조정

    ```
    kubectl scale deployment httpd --replicas=3
    ```
53. Pod 목록 확인

    ```
    kubectl get pod -o wide -l 'app in (nginx,httpd)'
    ```
54. 대상그룹에 포함된 대상 목록 확인

    ```
    for target in $TG
    do 
      aws elbv2 describe-target-health --target-group-arn $target --no-cli-pager
    done
    ```
55. Ingress 삭제

    ```
    kubectl delete ing nginx
    ```
56. AWS Load Balancer Controller 로그 확인

    ```
    kubectl -n kube-system logs deploy/aws-load-balancer-controller
    ```
57. ALB가 삭제되었는지 확인

    ```
    aws elbv2 describe-load-balancers --load-balancer-arns $LoadBalancerArn
    ```
58. 리소스 삭제

    ```
    {
        kubectl delete svc httpd nginx 
        kubectl delete deploy httpd nginx
    }
    ```

### IngressGroup

1. Ingress 생성

   ```
   cat <<EOF | kubectl apply -f -
   apiVersion: networking.k8s.io/v1
   kind: Ingress
   metadata:
     name: my-service
     annotations:
       alb.ingress.kubernetes.io/scheme: internet-facing
       alb.ingress.kubernetes.io/target-type: ip
       alb.ingress.kubernetes.io/group.name: my-service
       alb.ingress.kubernetes.io/actions.response-404: >
         {"type":"fixed-response","fixedResponseConfig":{"contentType":"text/plain","statusCode":"404","messageBody":"Not Found"}}
   spec:
     ingressClassName: alb
     defaultBackend:
       service:
         name: response-404
         port:
           name: use-annotation
   EOF
   ```
2. 생성된 Ingress 확인

   ```
   kubectl get ing my-service
   ```
3. 위에서 생성한 Ingress에 발생한 Event 확인

   ```
   kubectl describe ingress my-service
   ```
4. AWS Load Balancer Controller 로그 확인

   ```
   kubectl -n kube-system logs deploy/aws-load-balancer-controller --tail 15
   ```
5. 아래의 명령어를 실행해서 생성된 ALB 엔드포인트를 확인하고 웹브라우저를 통해서 접근이 되는지 확인

   ```
   echo $(kubectl get ing my-service -o=jsonpath='{.status.loadBalancer.ingress[0].hostname}')
   ```
6. Product 서비스 배포

   ```
   cat <<'EOF' | kubectl apply -f -
   apiVersion: apps/v1
   kind: Deployment
   metadata:
     name: product
     labels:
       app: product
   spec:
     selector:
       matchLabels:
         app: product
     template:
       metadata:
         labels:
           app: product
       spec:
         containers:
         - name: product
           image: nginx
           ports:
           - containerPort: 80
           volumeMounts:
           - name: html
             mountPath: /usr/share/nginx/html
         initContainers:
         - name: index
           image: bash
           command:
             - 'bash'
             - '-c'
             - 'echo "<h1>${APP^^}</h1>" > /data/index.html'
           env:
           - name: APP
             valueFrom:
               fieldRef:
                 fieldPath: metadata.labels['app']
           volumeMounts:
           - name: html
             mountPath: /data
         volumes:
         - name: html
           emptyDir: {}
   ---
   apiVersion: v1
   kind: Service
   metadata:
     name: product
     labels:
       app: product
   spec:
     selector:
       app: product
     ports:
     - port: 80
   EOF
   ```
7. 리소스가 정상적으로 생성되었는지 확인

   ```
   kubectl get all -l app=product
   ```
8. */product* 경로로 접속할 경우 위에 배포한 서비스로 연결되도록 Ingress 생성

   ```
   cat <<EOF | kubectl apply -f -
   apiVersion: networking.k8s.io/v1
   kind: Ingress
   metadata:
     name: product
     annotations:
       alb.ingress.kubernetes.io/group.name: my-service
   spec:
     ingressClassName: alb
     rules:
     - http:
         paths:
         - path: /product
           pathType: Prefix
           backend:
             service:
               name: product
               port:
                 number: 80
   EOF
   ```
9. 생성된 Ingress 확인

   ```
   kubectl get ing product
   ```
10. 위에서 생성한 Ingress에 발생한 Event 확인

    ```
    kubectl describe ingress product
    ```
11. AWS Load Balancer Controller 로그 확인

    ```
    kubectl -n kube-system logs deploy/aws-load-balancer-controller --tail 10
    ```
12. Ingress 수정

    ```
    cat <<EOF | kubectl apply -f -
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: product
      annotations:
        alb.ingress.kubernetes.io/group.name: my-service
        alb.ingress.kubernetes.io/target-type: ip
    spec:
      ingressClassName: alb
      rules:
      - http:
          paths:
          - path: /product
            pathType: Prefix
            backend:
              service:
                name: product
                port:
                  number: 80
    EOF
    ```
13. Ingress 확인

    ```
    kubectl get ing product
    ```
14. Ingress에 발생한 Event 확인

    ```
    kubectl describe ingress product
    ```
15. 처음에 생성한 Ingress의 ALB 엔드포인트에 방금 생성한 Ingress에 명시한 경로로 웹브라우저를 통해서 접근이 되는지 확인 - *아래의 명령어로 주소 확인 가능*

    ```
    echo $(kubectl get ing my-service -o=jsonpath='{.status.loadBalancer.ingress[0].hostname}')/product
    ```
16. Product 서비스의 로그 확인

    ```
    kubectl logs deploy/product
    ```
17. Product 서비스의 루트 경로 호출

    ```
    kubectl exec deploy/product -- curl -s localhost
    ```
18. Product 서비스의 */product* 경로 호출

    ```
    kubectl exec deploy/product -- curl -s localhost/product
    ```
19. Product 서비스 수정

    ```
    cat <<'EOF' | kubectl apply -f -
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: product
      labels:
        app: product
    spec:
      selector:
        matchLabels:
          app: product
      template:
        metadata:
          labels:
            app: product
        spec:
          containers:
          - name: product
            image: nginx
            ports:
            - containerPort: 80
            volumeMounts:
            - name: html
              mountPath: /usr/share/nginx/html
          initContainers:
          - name: index
            image: bash
            command:
              - 'bash'
              - '-c'
              - 'mkdir /data/$APP && echo "<h1>${APP^^}</h1>" > /data/$APP/index.html'
            env:
            - name: APP
              valueFrom:
                fieldRef:
                  fieldPath: metadata.labels['app']
            volumeMounts:
            - name: html
              mountPath: /data
          volumes:
          - name: html
            emptyDir: {}
    EOF
    ```
20. Product 서비스의 루트 경로 호출

    ```
    kubectl exec deploy/product -- curl -s localhost
    ```
21. Product 서비스의 */product* 경로 호출

    ```
    kubectl exec deploy/product -- curl -sL localhost/product
    ```
22. 처음에 생성한 Ingress의 ALB 엔드포인트에 */product* 경로로 웹브라우저를 통해서 접근이 되는지 확인 - *아래의 명령어로 주소 확인 가능*

    ```
    echo $(kubectl get ing my-service -o=jsonpath='{.status.loadBalancer.ingress[0].hostname}')/product
    ```
23. Payment 서비스 배포

    ```
    cat <<'EOF' | kubectl apply -f -
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: payment
      labels:
        app: payment
    spec:
      selector:
        matchLabels:
          app: payment
      template:
        metadata:
          labels:
            app: payment
        spec:
          containers:
          - name: payment
            image: nginx
            ports:
            - containerPort: 80
            volumeMounts:
            - name: html
              mountPath: /usr/share/nginx/html
          initContainers:
          - name: index
            image: bash
            command:
              - 'bash'
              - '-c'
              - 'mkdir /data/$APP && echo "<h1>${APP^^}</h1>" > /data/$APP/index.html'
            env:
            - name: APP
              valueFrom:
                fieldRef:
                  fieldPath: metadata.labels['app']
            volumeMounts:
            - name: html
              mountPath: /data
          volumes:
          - name: html
            emptyDir: {}
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: payment
      labels:
        app: payment
    spec:
      selector:
        app: payment
      ports:
      - port: 80
    EOF
    ```
24. 리소스가 정상적으로 생성되었는지 확인

    ```
    kubectl get all -l app=payment
    ```
25. */payment* 경로로 접속할 경우 위에 배포한 서비스로 연결되도록 Ingress 생성

    ```
    cat <<EOF | kubectl apply -f -
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: payment
      annotations:
        alb.ingress.kubernetes.io/group.name: my-service
        alb.ingress.kubernetes.io/target-type: ip
    spec:
      ingressClassName: alb
      rules:
      - http:
          paths:
          - path: /payment
            pathType: Prefix
            backend:
              service:
                name: payment
                port:
                  number: 80
    EOF
    ```
26. 생성된 Ingress 확인

    ```
    kubectl get ing payment
    ```
27. 위에서 생성한 Ingress에 발생한 Event 확인

    ```
    kubectl describe ingress payment
    ```
28. AWS Load Balancer Controller 로그 확인

    ```
    kubectl -n kube-system logs deploy/aws-load-balancer-controller --tail 10
    ```
29. 처음에 생성한 Ingress의 ALB 엔드포인트에 */payment* 경로로 웹브라우저를 통해서 접근이 되는지 확인 - *아래의 명령어로 주소 확인 가능*

    ```
    echo $(kubectl get ing my-service -o=jsonpath='{.status.loadBalancer.ingress[0].hostname}')/payment
    ```
30. 위에서 개별로 생성한 3개의 Ingress들이 동일한 ALB를 사용하는지 확인

    ```
    kubectl get ing my-service product payment
    ```
31. 리소스 삭제

    ```
    {
        kubectl delete ing payment product my-service
        kubectl delete deploy payment product
        kubectl delete svc payment product
    }
    ```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://kubernetes.youngwjung.com/core-concepts/ingress/lab.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
