Kubernetes Service(3): Ingress(ingress-nginx) w/k3s

  • kkumtree

2024-10-10T22:12:57+09:00

kans
k3s
ingress
nginx
kubernetes

์ง€๋‚œ ํฌ์ŠคํŒ…, Kubernetes Service(2): LoadBalancer(MetalLB)์— ์ด์–ด Ingress Type์„ ๊ฐ€๋ณ๊ฒŒ ์‚ดํŽด๋ณด๊ณ , Ingress-Nginx๋ฅผ ๊ฐ€๋ณ๊ฒŒ ๋ถ™์—ฌ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

CloudNet@์—์„œ ์ง„ํ–‰ํ•˜๊ณ  ์žˆ๋Š” K8s Advanced Network Study(์ดํ•˜, KANS)๋ฅผ ํ†ตํ•ด ํ•™์Šตํ•œ ๋‚ด์šฉ์„ ์ •๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

1. Ingress Type

์ด์ œ, ์‹ ๊ทœ ๊ธฐ๋Šฅ(New feature)์€ Gateway API์— ์ถ”๊ฐ€๋œ๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

์šฐ์„ , Kubernetes๊ฐ€ ํ—ท๊ฐˆ๋ฆฌ๋Š” ๊ฒƒ ์ค‘ ํ•˜๋‚˜๊ฐ€,

  • Ingress Type ๊ณผ LoadBalancer Type์˜ ๋ช…ํ™•ํ•œ ์ฐจ์ด๊ฐ€ ๋ญ˜๊นŒ...?
    ๋ผ๋Š” ์ ์ด๋ผ๊ณ  ๋ด…๋‹ˆ๋‹ค.

๋ฌผ๋ก , ๊ทธ๊ฑฐ ์™ธ์—๋„ k8s์—๋Š” ์•Œ์ญ๋‹ฌ์ญํ•œ ๊ฒƒ๋“ค์ด ์•„-์ฃผ ๋งŽ์ง€๋งŒ์š”.

์นœ์ ˆํ•œ Docs์— ๋”ฐ๋ฅด๋ฉด,
ํด๋Ÿฌ์Šคํ„ฐ ์™ธ๋ถ€๋กœ ํด๋Ÿฌ์Šคํ„ฐ ๋‚ด๋ถ€ ์„œ๋น„์Šค์— ๋Œ€ํ•œ HTTP ๋ฐ HTTPS ๋ผ์šฐํŒ…์„ ๋…ธ์ถœํ•˜๋Š” ๊ฒƒ์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

Rules์— ์˜ํ•œ ๋‹ค์–‘ํ•œ ๋ฐฑ์—”๋“œ ๋ผ์šฐํŒ… ์™ธ์—๋„ Load Balancing, SSL Termination ๊ทธ๋ฆฌ๊ณ  name-based virtual hosting์„ ์ง€์›ํ•œ๋‹ค๊ณ  ํ•˜๋Š”๋ฐ… ์ด์ฏค๋˜๋ฉด LoadBalancer Type์ด๋ž‘ ๋‹ค๋ฅธ๊ฒŒ ์—†๋Š” ๊ฑฐ๋ผ๊ณ  ์ƒ๊ฐ์„ ํ•˜๊ณค ํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ Ingress๋ฅผ ์žŠ์–ด์•ผํ•œ๋‹ค๋Š” ๋งˆ์Œ์œผ๋กœ, ์ฐจ์ด์ ๋งŒ ์งš์–ด๋ณด๊ณ ์ž ํ–ˆ์Šต๋‹ˆ๋‹ค.

2. Ingress Type vs. LoadBalancer Type

์œ„์˜ ๋งํฌ๊ฐ€ ๋จผ์ € ๋‚˜์™€์„œ ์Šฅ ๋ดค๋Š”๋ฐ, ๊ทธ ์˜คํ•ด๋Š” ์–ด๋””๊นŒ์ง€๋‚˜ CSP์—์„œ ์ œ๊ณตํ•˜๋Š” ALB์— Routing Rule์„ ๋„ฃ๊ณ  SSL์„ ๋‹ฌ์•„์„œ ํ—ท๊ฐˆ๋ฆฐ๊ฒŒ ์•„๋‹๊นŒ ์ƒ๊ฐ์„ ํ•ด๋ดค์Šต๋‹ˆ๋‹ค.

๋น„์šฉ ๊ฐ™์€ ๋‹น์—ฐํ•œ ์ด์•ผ๊ธฐ๋Š” ๋นผ๊ณ  ํ•ด๋‹น ๋งํฌ์—์„œ๋Š” k8s ๊ด€์ ์—์„œ๋งŒ ๋ณด๋ฉด,

  • ์–ด๋””๊นŒ์ง€๋‚˜ LoadBalancer Type์€ Service์˜ ํ™•์žฅ
  • Ingress์™€ ๋‹ฌ๋ฆฌ, LB๋Š” ๋…๋ฆฝ์  ๊ฐ์ฒด(Standalone Object)๊ฐ€ ์•„๋‹˜

์ฐจ์ด๊ฐ€ ์žˆ๋‹ค๋Š” ๊ฑธ ์•Œ๊ฒŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

3. ๊ฐ€๋ฒผ์šด k3s ์‹ค์Šต ์ค€๋น„

์•„์ง Ingress Type์˜ ๊ด€์ง์— ๋ชป์ด ์•ˆ ๋ฐ•ํ˜”๊ธฐ ๋•Œ๋ฌธ์—, ๊ฐ€๋ฒผ์šด ์‹ค์Šต ์ค€๋น„๋ฅผ ํ•ด๋ด…๋‹ˆ๋‹ค.

์ด ๋˜ํ•œ ์Šคํ„ฐ๋””์—์„œ ๋ถ€ํŠธ์ŠคํŠธ๋žฉ์œผ๋กœ ์ œ๊ณต๋˜์—ˆ๊ธฐ์— ์–‘ํ•ด๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

# Install k3s-server
curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC=" --disable=traefik"  sh -s - server --token kanstoken --cluster-cidr "172.16.0.0/16" --service-cidr "10.10.200.0/24" --write-kubeconfig-mode 644 

# Install k3s-agent
curl -sfL https://get.k3s.io | K3S_URL=https://192.168.10.10:6443 K3S_TOKEN=kanstoken  sh -s -

kubeadm์„ ๋งŽ์ด ๋‹ค๋ฃจ์‹  ํ˜„์—… ๋ถ„๋“ค๊ป˜์„œ๋Š” ์ข€ ๋งŽ์ด ์ต์ˆ™ํ•œ ํŒŒ๋ผ๋ฏธํ„ฐ๋“ค์ด ๋ณด์ž…๋‹ˆ๋‹ค.
๋‹ค๋งŒ, --disable=traefik์ด๋ผ๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ k3s server ์„ค์น˜ ์Šคํฌ๋ฆฝํŠธ์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋Š”๋ฐ์š”,
k3s๊ฐ€ Ingress Controller๋กœ Traefik์„ ์‚ฌ์šฉํ•˜๋Š”๋ฐ, Ingress-Nginx๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด Traefik์„ ๋น„ํ™œ์„ฑํ™” ์‹œํ‚ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

cat /etc/rancher/k3s/k3s.yaml
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: LS0tLS1CR(์ค‘๋žต)LS0tLS0K
    server: https://127.0.0.1:6443
  name: default
contexts:
- context:
    cluster: default
    user: default
  name: default
current-context: default
kind: Config
preferences: {}
users:
- name: default
  user:
    client-certificate-data: LS0tLS1C(์ค‘๋žต)LS0tLS0K
    client-key-data: LS0tLS1(์ค‘๋žต)LS0tLQo=

k3s๋Š” SUSE๋ฐ Rancher์—์„œ ๊ฐœ๋ฐœ๋˜์–ด, CNCF Sandbox Project๋กœ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š”,
IoT & Edge Computing์„ ์œ„ํ•œ k8s ๋ฐฐํฌ๋„๊ตฌ์ด๊ธฐ์— rancher ํด๋”๊ฐ€ ์ƒ๊ฒผ์Œ์„ ์œ ์ถ”ํ•ด๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

4. Ingress-Nginx ์ปจํŠธ๋กค๋Ÿฌ ๋ฐฐํฌ (Helm)

์ œ๊ฐ€ ์กฐ์ž‘ํ•˜์ง€ ์•Š๋Š”, Helm์— ๋ฐ์ธ ์ดํ›„๋กœ ์„ ํ˜ธ๋„๊ฐ€ ๊ธ‰?๊ฒฉํ•˜๊ฒŒ ๋–จ์–ด์ง€๊ธด ํ–ˆ๋Š”๋ฐ, ์—ฌํŠผ ํŽธํ•˜๋‹ˆ๊นŒ ํ•ด๋ด…์‹œ๋‹ค.

(a) Helm Values ํŒŒ์ผ ์ž‘์„ฑ ๋ฐ Helm Repo ์ถ”๊ฐ€

  • NodePort๋กœ ํ•ด๋‹น ์„œ๋น„์Šค๋ฅผ ๋…ธ์ถœํ•˜๊ธฐ๋กœ ํ•ด๋ด…์‹œ๋‹ค.
cat <<EOT> ingress-nginx-values.yaml
controller:
  service:
    type: NodePort
    nodePorts:
      http: 30080
      https: 30443
  nodeSelector:
    kubernetes.io/hostname: "k3s-s"
  metrics:
    enabled: true
  serviceMonitor:
      enabled: true
EOT

helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update

insecure warning์ด ๋œจ์ง€๋งŒ, ์ด๊ฒŒ ํ•™์Šต์ด๋ผ ๊ทธ์ € ๋„˜์–ด๊ฐ€๋„๋ก ํ•ฉ์‹œ๋‹ค.

WARNING: Kubernetes configuration file is group-readable. This is insecure. Location: /etc/rancher/k3s/k3s.yaml
WARNING: Kubernetes configuration file is world-readable. This is insecure. Location: /etc/rancher/k3s/k3s.yaml
"ingress-nginx" has been added to your repositories
WARNING: Kubernetes configuration file is group-readable. This is insecure. Location: /etc/rancher/k3s/k3s.yaml
WARNING: Kubernetes configuration file is world-readable. This is insecure. Location: /etc/rancher/k3s/k3s.yaml

(b) ns ์ƒ์„ฑ ๋ฐ Helm Chart ๋ฐฐํฌ

kubectl create ns ingress
helm install ingress-nginx ingress-nginx/ingress-nginx -f ingress-nginx-values.yaml --namespace ingress --version 4.11.2

# Check
kubectl get all -n ingress
kubectl get svc -n ingress ingress-nginx-controller

Warning์€ ์—?๋Ÿฌ๊ฐ€ ์•„๋‹ˆ๋‹ˆ๊นŒ, ๋Œ€๊ฐœ ์ž˜ ์žกํžˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

kubectl create ns ingress
helm install ingress-nginx ingress-nginx/ingress-nginx -f ingress-nginx-values.yaml --namespace ingress --version 4.11.2
namespace/ingress created
WARNING: Kubernetes configuration file is group-readable. This is insecure. Location: /etc/rancher/k3s/k3s.yaml
WARNING: Kubernetes configuration file is world-readable. This is insecure. Location: /etc/rancher/k3s/k3s.yaml
NAME: ingress-nginx
LAST DEPLOYED: Thu Oct 10 23:39:48 2024
NAMESPACE: ingress
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
The ingress-nginx controller has been installed.
Get the application URL by running these commands:
  export HTTP_NODE_PORT=30080
  export HTTPS_NODE_PORT=30443
  export NODE_IP="$(kubectl get nodes --output jsonpath="{.items[0].status.addresses[1].address}")"

  echo "Visit http://${NODE_IP}:${HTTP_NODE_PORT} to access your application via HTTP."
  echo "Visit https://${NODE_IP}:${HTTPS_NODE_PORT} to access your application via HTTPS."

An example Ingress that makes use of the controller:
  apiVersion: networking.k8s.io/v1
  kind: Ingress
  metadata:
    name: example
    namespace: foo
  spec:
    ingressClassName: nginx
    rules:
      - host: www.example.com
        http:
          paths:
            - pathType: Prefix
              backend:
                service:
                  name: exampleService
                  port:
                    number: 80
              path: /
    # This section is only required if TLS is to be enabled for the Ingress
    tls:
      - hosts:
        - www.example.com
        secretName: example-tls

If TLS is enabled for the Ingress, a Secret containing the certificate and key must also be provided:

  apiVersion: v1
  kind: Secret
  metadata:
    name: example-tls
    namespace: foo
  data:
    tls.crt: <base64 encoded cert>
    tls.key: <base64 encoded key>
  type: kubernetes.io/tls
kubectl get all -n ingress
kubectl describe svc -n ingress ingress-nginx-controller

๊ทธ๋ ‡๊ตฐ์š”.

# kubectl get all -n ingress
NAME                                           READY   STATUS    RESTARTS   AGE
pod/ingress-nginx-controller-979fc89cf-lk7th   1/1     Running   0          92s

NAME                                         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
service/ingress-nginx-controller             NodePort    10.10.200.235   <none>        80:30080/TCP,443:30443/TCP   92s
service/ingress-nginx-controller-admission   ClusterIP   10.10.200.100   <none>        443/TCP                      92s
service/ingress-nginx-controller-metrics     ClusterIP   10.10.200.234   <none>        10254/TCP                    92s

NAME                                       READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/ingress-nginx-controller   1/1     1            1           92s

NAME                                                 DESIRED   CURRENT   READY   AGE
replicaset.apps/ingress-nginx-controller-979fc89cf   1         1         1       92s
NAME                       TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
ingress-nginx-controller   NodePort   10.10.200.235   <none>        80:30080/TCP,443:30443/TCP   92s

NodePort๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
IP Addr์ด ๋‹ค๋ฅธ ์ด์œ ๋Š” EC2 ๋„๊ณ  ๋‹ค์‹œ์ผฐ๋”๋‹ˆ, ์˜ค๋ฅ˜๋‚˜์„œ ๋‹ค์‹œ ์˜ฌ๋ ธ์Šต๋‹ˆ๋‹ค.

# kubectl describe svc -n ingress ingress-nginx-controller
(์ „๋žต)
Type:                     NodePort
IP Family Policy:         SingleStack
IP Families:              IPv4
IP:                       10.10.200.180
IPs:                      10.10.200.180
Port:                     http  80/TCP
TargetPort:               http/TCP
NodePort:                 http  30080/TCP
Endpoints:                172.16.0.3:80
Port:                     https  443/TCP
TargetPort:               https/TCP
NodePort:                 https  30443/TCP
Endpoints:                172.16.0.3:443
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>

(c) externalTrafficPolicy: Local

์ปจํŠธ๋กค๋Ÿฌ์— NodePort๋ฅผ ์‚ฌ์šฉํ•˜๊ณ , externalTrafficPolicy: Local์„ ์‚ฌ์šฉํ•˜๋ฉด,
ํด๋ผ์ด์–ธํŠธ์˜ ์š”์ฒญ์ด ๋„์ฐฉํ•œ ๋…ธ๋“œ๋กœ ๋ฐ”๋กœ ์ „๋‹ฌ๋˜์–ด, ๋…ธ๋“œ์˜ ๋กœ์ปฌ IP๋กœ๋ถ€ํ„ฐ ์‘๋‹ต์„ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค๊ณ  ํ•˜๋Š”๋ฐ
์ผ๋‹จ ์ผœ๋ณด๊ณ  ํ™˜๊ฒฝ๊ฐ’ ์ฒดํฌ๋ฅผ ํ•ฉ๋‹ˆ๋‹ค.

kubectl patch svc ingress-nginx-controller -n ingress -p '{"spec":{"externalTrafficPolicy":"Local"}}'
# service/ingress-nginx-controller patched
kubectl get cm -n ingress ingress-nginx-controller
kubectl exec deploy/ingress-nginx-controller -n ingress -it -- cat /etc/nginx/nginx.conf
# (์ƒ๋žต) ํ‰์†Œ์— ๋ณด๋˜ Nginx.conf ๊ฐ€ ์ดํ–ˆ๋‚˜....?  

๋ฒ„์ „ ์ •๋ณด๋„ ํ™•์ธํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

POD_NS=ingress
POD_NAME=$(kubectl get pods -n $POD_NS -l app.kubernetes.io/name=ingress-nginx --field-selector=status.phase=Running -o name)
kubectl exec $POD_NAME -n $POD_NS -- /nginx-ingress-controller --version

์ ๋‹นํžˆ ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค.

-------------------------------------------------------------------------------
NGINX Ingress controller
  Release:       v1.11.2
  Build:         46e76e5916813cfca2a9b0bfdc34b69a0000f6b9
  Repository:    https://github.com/kubernetes/ingress-nginx
  nginx version: nginx/1.25.5

-------------------------------------------------------------------------------

5. ํ…Œ์ŠคํŠธ ์„œ๋น„์Šค ๋ฐฐํฌ (ClusterIP, NodePort)

Ingress ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ClusterIP, NodePosrt ๋ฌด๊ด€ํ•˜๊ฒŒ ์™ธ๋ถ€์— ๋…ธ์ถœ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋Š”์ง€์— ๋Œ€ํ•ด
ํ…Œ์ŠคํŠธ ์‹ค์Šต์„ ํ•ด๋ณผ ๊ฒ๋‹ˆ๋‹ค.

Service Type Port Test App
ClusterIP 9001 nginx
NodePort 9002 kubetnetes-bootcamp
์ •์˜ ์—†์Œ(Default: ClusterIP) 9003 echoserver

(a) ClusterIP Service

cat <<EOT> clusterip-nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy1-websrv
spec:
  replicas: 1
  selector:
    matchLabels:
      app: websrv
  template:
    metadata:
      labels:
        app: websrv
    spec:
      containers:
      - name: pod-web
        image: nginx
---
apiVersion: v1
kind: Service
metadata:
  name: svc1-web
spec:
  ports:
    - name: web-port
      port: 9001
      targetPort: 80
  selector:
    app: websrv
  type: ClusterIP
EOT

(b) NodePort Service

cat <<EOT> nodeport-kbc.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy2-guestsrv
spec:
  replicas: 2
  selector:
    matchLabels:
      app: guestsrv
  template:
    metadata:
      labels:
        app: guestsrv
    spec:
      containers:
      - name: pod-guest
        image: gcr.io/google-samples/kubernetes-bootcamp:v1
        ports:
        - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: svc2-guest
spec:
  ports:
    - name: guest-port
      port: 9002
      targetPort: 8080
  selector:
    app: guestsrv
  type: NodePort
EOT

(c) Default Service

cat <<EOT> default-echoserver.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy3-adminsrv
spec:
  replicas: 3
  selector:
    matchLabels:
      app: adminsrv
  template:
    metadata:
      labels:
        app: adminsrv
    spec:
      containers:
      - name: pod-admin
        image: k8s.gcr.io/echoserver:1.5
        ports:
        - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: svc3-admin
spec:
  ports:
    - name: admin-port
      port: 9003
      targetPort: 8080
  selector:
    app: adminsrv
EOT

(d) ๋ฐฐํฌ ๋ฐ ํ™•์ธ

kubectl apply -f clusterip-nginx.yaml
kubectl apply -f nodeport-kbc.yaml
kubectl apply -f default-echoserver.yaml

(e) taint ์„ค์ • ๋ฐ ์žฌ๋ฐฐํฌ ํ™•์ธ

ํ˜„์žฌ๋Š” Control Plane(Master) Node์— taint ์„ค์ •์ด ์—†์–ด์„œ, pod๊ฐ€ ๋ฐฐํฌ๋œ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

# kubectl get ingress,svc,ep,pod -owide
NAME                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE     SELECTOR
service/kubernetes   ClusterIP   10.10.200.1     <none>        443/TCP          27h     <none>
service/svc1-web     ClusterIP   10.10.200.69    <none>        9001/TCP         3m22s   app=websrv
service/svc2-guest   NodePort    10.10.200.117   <none>        9002:30133/TCP   3m22s   app=guestsrv
service/svc3-admin   ClusterIP   10.10.200.249   <none>        9003/TCP         108s    app=adminsrv

NAME                   ENDPOINTS                                         AGE
endpoints/kubernetes   192.168.10.10:6443                                27h
endpoints/svc1-web     172.16.1.3:80                                     3m22s
endpoints/svc2-guest   172.16.0.5:8080,172.16.3.3:8080                   3m22s
endpoints/svc3-admin   172.16.0.6:8080,172.16.2.3:8080,172.16.3.4:8080   108s

NAME                                    READY   STATUS    RESTARTS   AGE     IP           NODE     NOMINATED NODE   READINESS GATES
pod/deploy1-websrv-5c6b88bd77-w5nph     1/1     Running   0          3m22s   172.16.1.3   k3s-w1   <none>           <none>
pod/deploy2-guestsrv-649875f78b-4tj8d   1/1     Running   0          3m22s   172.16.0.5   k3s-s    <none>           <none>
pod/deploy2-guestsrv-649875f78b-js862   1/1     Running   0          3m22s   172.16.3.3   k3s-w2   <none>           <none>
pod/deploy3-adminsrv-7c8f8b8c87-4q8h6   1/1     Running   0          108s    172.16.3.4   k3s-w2   <none>           <none>
pod/deploy3-adminsrv-7c8f8b8c87-6xwk5   1/1     Running   0          108s    172.16.0.6   k3s-s    <none>           <none>
pod/deploy3-adminsrv-7c8f8b8c87-hvq7n   1/1     Running   0          108s    172.16.2.3   k3s-w3   <none>           <none>

์šฐ๋ฆฐ ์ด๊ฑธ ์šฉ?๋‚ฉํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์—, taint๋ฅผ ๊ฑธ๊ณ  ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋‚˜ ํ™•์ธํ•ด๋ณผ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

kubectl taint nodes k3s-s role=controlplane:NoSchedule
# node/k3s-s tainted

๋Œ€์‹  ๋น ๋ฅธ ์ ์šฉ ํ™•์ธ์„ ์œ„ํ•ด, ๊ฐ Deployment ์ •์˜์— terminationGracePeriodSeconds: 0๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

apiVersion: apps/v1
kind: Deployment
# (์ค‘๋žต)
    spec:
      containers:
      - name: pod-web
        image: nginx
      terminationGracePeriodSeconds: 0
---
# (ํ›„๋žต)

์ดํ›„์— ๋‹ค์‹œ ์ ์šฉ(apply)ํ•˜๊ณ  ํ™•์ธํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

kubectl apply -f clusterip-nginx.yaml
kubectl apply -f nodeport-kbc.yaml
kubectl apply -f default-echoserver.yaml

Control Plane์— ๋Œ€ํ•œ Pod๋งŒ ์žฌ๋ฐฐํฌ ๋  ์ค„ ์•Œ์•˜๋Š”๋ฐ, ์ƒ๊ฐํ•ด๋ณด๋‹ˆ terminationGracePeriodSeconds: 0 spec์ด ์ถ”๊ฐ€๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ deployment ์ „์ฒด๊ฐ€ ์žฌ๋ฐฐํฌ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

kubectl get ingress,svc,ep,pod -owide
NAME                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE   SELECTOR
service/kubernetes   ClusterIP   10.10.200.1     <none>        443/TCP          27h   <none>
service/svc1-web     ClusterIP   10.10.200.69    <none>        9001/TCP         16m   app=websrv
service/svc2-guest   NodePort    10.10.200.117   <none>        9002:30133/TCP   16m   app=guestsrv
service/svc3-admin   ClusterIP   10.10.200.249   <none>        9003/TCP         14m   app=adminsrv

NAME                   ENDPOINTS                                         AGE
endpoints/kubernetes   192.168.10.10:6443                                27h
endpoints/svc1-web     172.16.1.4:80                                     16m
endpoints/svc2-guest   172.16.2.4:8080,172.16.3.6:8080                   16m
endpoints/svc3-admin   172.16.1.5:8080,172.16.2.5:8080,172.16.3.5:8080   14m

NAME                                    READY   STATUS    RESTARTS   AGE   IP           NODE     NOMINATED NODE   READINESS GATES
pod/deploy1-websrv-69cb66b964-nppv5     1/1     Running   0          96s   172.16.1.4   k3s-w1   <none>           <none>
pod/deploy2-guestsrv-cbb5d6665-jhbpm    1/1     Running   0          86s   172.16.3.6   k3s-w2   <none>           <none>
pod/deploy2-guestsrv-cbb5d6665-sb67h    1/1     Running   0          95s   172.16.2.4   k3s-w3   <none>           <none>
pod/deploy3-adminsrv-77b7c78b98-79pgl   1/1     Running   0          94s   172.16.3.5   k3s-w2   <none>           <none>
pod/deploy3-adminsrv-77b7c78b98-vfbv5   1/1     Running   0          93s   172.16.1.5   k3s-w1   <none>           <none>
pod/deploy3-adminsrv-77b7c78b98-zvkgv   1/1     Running   0          95s   172.16.2.5   k3s-w3   <none>           <none>

์—ฌ๊ธฐ๊นŒ์ง€๋Š” ์˜ˆ์ƒ๋œ๋Œ€๋กœ, ์„œ๋น„์Šค ํฌํŠธ 9001, 9002, 9003์ด ๊ฐ๊ฐ ๋ฐฐํฌ๋˜์—ˆ์Œ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์ด ์ƒํƒœ๋กœ๋Š” http://<EC2_PUBLIC_IP>:30133/ ๋งŒ ์™ธ๋ถ€์—์„œ ์ ‘์†ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

only-nodeport-accessible

Ingress๊ฐ€ ClusterIP, NodePort ๋ฌด๊ด€ํ•˜๊ฒŒ ์™ธ๋ถ€์— ์„œ๋น„์Šค๋ฅผ ๋ฐฐํฌํ•˜๊ฒŒ ๋งŒ๋“ค์–ด๋ณผ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

6. Ingress ๋ฆฌ์†Œ์Šค ์ƒ์„ฑ

ALB(L7) Rule์„ ์ •ํ•˜๋Š” ๊ฒƒ๊ณผ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

cat <<EOT> ingress-nginx-rule-1.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-rule-1
  namespace: default
  annotations:
    #nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
  # - host: nginx.minseong.xyz
  #   http:
  #     paths:
  - http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: svc1-web
            port:
              number: 80
      - path: /kbc
        pathType: Prefix
        backend:
          service:
            name: svc2-guest
            port:
              number: 8080
      - path: /guest
        pathType: Prefix
        backend:
          service:
            name: svc3-admin
            port:
              number: 8080
EOT

path ๊ธฐ๋ฐ˜์œผ๋กœ ์„œ๋น„์Šค๋ฅผ ๋ผ์šฐํŒ…ํ•˜๋ ค๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์„œ๋น„์Šค์˜ ํฌํŠธ๊ฐ€ ์•„๋‹Œ ์ด๋ฆ„์œผ๋กœ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

# kubectl get ingress -owide  
NAME                                       CLASS   HOSTS   ADDRESS         PORTS   AGE
ingress.networking.k8s.io/ingress-rule-1   nginx   *       10.10.200.180   80      43s

Rule์ด ์ ์šฉ๋˜์—ˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

# kubectl describe ingress ingress-rule-1
Name:             ingress-rule-1
Labels:           <none>
Namespace:        default
Address:          10.10.200.180
Ingress Class:    nginx
Default backend:  <default>
Rules:
  Host        Path  Backends
  ----        ----  --------
  *           
              /        svc1-web:80 ()
              /kbc     svc2-guest:8080 ()
              /guest   svc3-admin:8080 ()
Annotations:  <none>
Events:
  Type    Reason  Age                From                      Message
  ----    ------  ----               ----                      -------
  Normal  Sync    22m (x2 over 23m)  nginx-ingress-controller  Scheduled for sync

์œ„์˜ ๋ฃฐ์ด ์ปจํŠธ๋กค๋Ÿฌ์— ์–ด๋–ป๊ฒŒ ์ ์šฉ๋˜์–ด์žˆ๋Š”์ง€ ๋ณด๋„๋ก ํ•ฉ์‹œ๋‹ค.

# kubectl exec deploy/ingress-nginx-controller -n ingress -it -- cat /etc/nginx/nginx.conf | grep 'location /' -A5
		location /guest/ {
			
			set $namespace      "default";
			set $ingress_name   "ingress-rule-1";
			set $service_name   "svc3-admin";
			set $service_port   "8080";
--
  		location /kbc/ {
			
			set $namespace      "default";
			set $ingress_name   "ingress-rule-1";
			set $service_name   "svc2-guest";
			set $service_port   "8080";
--
  		location / {
			
			set $namespace      "default";
			set $ingress_name   "ingress-rule-1";
			set $service_name   "svc1-web";
			set $service_port   "80";
--
(ํ›„๋žต)

(a) ์ ‘์† ํ™•์ธ

์•„๋ž˜์˜ ์ถœ๋ ฅ๋œ ๋งํฌ๋ฅผ ๋กœ์ปฌ์˜ ์›น๋ธŒ๋ผ์šฐ์ €๋กœ ์ ‘์†ํ•ด๋ณด๋ฉด ์•„์ฃผ ์ž˜ ์ ‘์†๋ฉ๋‹ˆ๋‹ค.

echo -e "Ingress1 sv1-web URL = http://$(curl -s ipinfo.io/ip):30080"
# Ingress1 sv1-web URL = http://43.202.54.183:30080
echo -e "Ingress1 sv2-guest URL = http://$(curl -s ipinfo.io/ip):30080/guest"
# Ingress1 sv2-guest URL = http://43.202.54.183:30080/guest
echo -e "Ingress1 sv3-admin URL = http://$(curl -s ipinfo.io/ip):30080/kbc"
# Ingress1 sv3-admin URL = http://43.202.54.183:30080/kbc

(b) ๋” ์•Œ์•„๋ณด๊ธฐ

๋กœ์ปฌ ํ™˜๊ฒฝ์—์„œ ์ข€ ๋” ๋ณผ๊นŒ์š”?

EC2_MASTER_PUB_IP=<EC2 Control Plane์˜ Public IP>
# EC2_MASTER_PUB_IP=43.202.54.183
for i in {1..100}; do curl -s $EC2_MASTER_PUB_IP:30080/guest ; done | sort | uniq -c | sort -nr

Nginx ๊ธฐ์ค€, ๋ญ”๊ฐ€ ์ข€ ์ต์ˆ™ํ•œ ๊ฐ’๋“ค์ด ๋ณด์ž…๋‹ˆ๋‹ค.

ํŠนํžˆ Ingress๋ฅผ ํ†ตํ•ด, ์–ด๋””(๋กœ์ปฌ)์—์„œ ์ ‘๊ทผ์„ ํ–ˆ๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    800 
    100 	x-scheme=http
    100 	x-real-ip=<๋กœ์ปฌ ํ™˜๊ฒฝ์˜ ๊ณต์ธ IP>
    100 	x-forwarded-scheme=http
    100 	x-forwarded-proto=http
    100 	x-forwarded-port=80
    100 	x-forwarded-host=43.202.54.183:30080
    100 	x-forwarded-for=<๋กœ์ปฌ ํ™˜๊ฒฝ์˜ ๊ณต์ธ IP>
    100 	user-agent=curl/8.5.0
    100 	server_version=nginx: 1.13.0 - lua: 10008
    100 Server values:
    100 	request_version=1.1
    100 	request_uri=http://43.202.54.183:8080/guest
    100 Request Information:
    100 Request Headers:
    100 Request Body:
    100 	real path=/guest
    100 	query=
    100 Pod Information:
    100 	-no pod information available-
    100 	-no body in request-
    100 	method=GET
    100 	host=43.202.54.183:30080
    100 	client_address=172.16.0.3
    100 	accept=*/*
     34 Hostname: deploy3-adminsrv-77b7c78b98-zvkgv
     33 Hostname: deploy3-adminsrv-77b7c78b98-vfbv5
     33 Hostname: deploy3-adminsrv-77b7c78b98-79pgl
      1 	x-request-id=fda5b56e29f9c0109124762aab619f3d
      1 	x-request-id=fc5161bd78bb6a82f578c854e79a6dd7
      1 	x-request-id=fb98bfdbf78a87071c5ad119c8f01c7c
      1 	x-request-id=f6e07d531bb0a54a029abb4c0657b55b
      1 	x-request-id=f4e66a64fac7e0f21df5577058c623c8
      1 	x-request-id=f050b3f7f7e22b55b1b80c7a794cb659
(ํ›„๋žต)

ํ•„์š”ํ•œ ์ •๋ณด๋งŒ ๋ณด๊ณ  ์‹ถ๋‹ค๋ฉด, ์ด๋ ‡๊ฒŒ ํ•  ์ˆ˜๋„ ์žˆ๊ฒ ๋„ค์š”.

curl -s $EC2_MASTER_PUB_IP:30080/guest | egrep '(client_address|x-forwarded-for)'
	# client_address=172.16.0.3
	# x-forwarded-for=<๋กœ์ปฌ ํ™˜๊ฒฝ์˜ ๊ณต์ธ IP>

๊ทธ๋Ÿผ ์ด client_address๋Š” ์–ด๋””์„œ ํŠ€์–ด๋‚˜์˜จ ๊ฑธ๊นŒ์š”?

์•ž์—์„œ 4.-(a) ์—์„œ helm์œผ๋กœ ์ฒซ ๋ฐฐํฌ ํ›„ ํ™•์ธํ–ˆ์„ ๋•Œ์˜ ์—”๋“œํฌ์ธํŠธ ์ž…๋‹ˆ๋‹ค.

kubectl describe svc -n ingress ingress-nginx-controller | grep Endpoints
# Endpoints:                172.16.0.3:80
# Endpoints:                172.16.0.3:443

kubectl get -n ingress pods -owide
# NAME                                       READY   STATUS    RESTARTS   AGE   IP           NODE    NOMINATED NODE   READINESS GATES
# ingress-nginx-controller-979fc89cf-f24fk   1/1     Running   0          29h   172.16.0.3   k3s-s   <none>           <none>

7. TLS Termination (์ฒ˜๋ฆฌ) ๋ง›๋ณด๊ธฐ

์˜ฌํ•ด ์ดˆ์— ์ž๋™ ๊ฐฑ์‹ ๋˜์–ด๋ฒ„๋ฆฐ ํ…Œ์ŠคํŠธ ๋„๋ฉ”์ธ์„ ์‚ฌ์šฉํ•ด๋ด…์‹œ๋‹ค.

์Œ ํ˜ธ์ŠคํŠธ ์ •๋ณด ์ œ์–ด๋ฅผ ํ†ตํ•ด ํ•ด๋ด…์‹œ๋‹ค.

๊ฐ€์ƒ์˜ ํ˜ธ์ŠคํŠธ kkumtree.xyz๊ฐ€ ์žˆ๋‹ค๊ณ  ํ•ด๋ด…์‹œ๋‹ค.

(a) ๋ฐฐํฌ ์ค€๋น„

TLS ํ†ต์‹ ์„ ์œ„ํ•œ ์ธ์ฆ์„œ๋ฅผ secret์œผ๋กœ ์ €์žฅํ•˜์—ฌ ์“ฐ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

cat <<EOT> tls-echoserver.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-https
  labels:
    app: https
spec:
  containers:
  - name: container
    image: k8s.gcr.io/echoserver:1.6
  terminationGracePeriodSeconds: 0
---
apiVersion: v1
kind: Service
metadata:
  name: svc-https
spec:
  selector:
    app: https
  ports:
  - port: 8080
EOT
cat <<EOT> ssl-termination-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: https
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - kkumtree.abc
    secretName: secret-https
  rules:
  - host: kkumtree.abc
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: svc-https
            port:
              number: 8080
EOT

(b) ๋ฐฐํฌ ๋ฐ ์ธ์ฆ์„œ ์ƒ์„ฑ

์ ์šฉ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•ฉ๋‹ˆ๋‹ค.

  • ํ…Œ์ŠคํŠธ POD ๋ฐฐํฌ
  • ๊ฐ€์ƒ์˜ ๋„๋ฉ”์ธ ์ง€์ •
  • Ingress ๋ฆฌ์†Œ์Šค ์ƒ์„ฑ
  • ์ธ์ฆ์„œ ์ƒ์„ฑ ๋ฐ Secret ์ƒ์„ฑ
  • ํ…Œ์ŠคํŠธ
TEST_DNS=kkumtree.abc
kubectl apply -f tls-echoserver.yaml
kubectl apply -f ssl-termination-ingress.yaml
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=$TEST_DNS/O=$TEST_DNS"
kubectl create secret tls secret-https --key tls.key --cert tls.crt
kubectl get secrets secret-https -o yaml

์ฐธ ์‰ฝ์ฃ ? ์Šคํ„ฐ๋”” ์—†์—ˆ์œผ๋ฉด 99.99% ํ—ค๋ฉค

# (์ „๋žต)
secret/secret-https created
apiVersion: v1
data:
  tls.crt: LS0tLS1C(์ค‘๋žต)LS0tLQo=
  tls.key: LS0tLS1C(์ค‘๋žต)LS0tLS0K
kind: Secret
metadata:
  creationTimestamp: "2024-10-13T08:33:44Z"
  name: secret-https
  namespace: default
  resourceVersion: "81976"
  uid: 3cc3014e-(์ค‘๋žต)-c8422a2197e3
type: kubernetes.io/tls

(c) ํ™•์ธ

๊ฐ€์งœ ๋„๋ฉ”์ธ์€ ์ง์ ‘ ์“ธ ์ˆ˜ ์—†๊ธฐ์— /etc/hosts ๋“ฑ๋ก์ด๋‚˜
๋กœ์ปฌ์—์„œ ์•„๋ž˜์™€ ๊ฐ™์ด ์„ค์ •ํ•˜์—ฌ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

์˜ต์…˜์˜ ๋Œ€์†Œ๋ฌธ์ž ์œ ์˜

EC2_MASTER_PUB_IP=<6.(b)์—์„œ ํ™œ์šฉํ–ˆ์Œ>  
# EC2_MASTER_PUB_IP=43.202.54.183  
TEST_DNS=<ํ…Œ์ŠคํŠธ์šฉ์œผ๋กœ ์ง€์ •ํ•œ ๊ฐ€์งœ ๋„๋ฉ”์ธ>  
# TEST_DNS=kkumtree.abc
curl -Lk -H "host: $TEST_DNS" https://$EC2_MASTER_PUB_IP:30443

๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋‚˜์˜ฌ ๊ฒ๋‹ˆ๋‹ค.

# curl -Lk -H "host: $TEST_DNS" https://$EC2_MASTER_PUB_IP:30443


Hostname: pod-https

Pod Information:
	-no pod information available-

Server values:
	server_version=nginx: 1.13.1 - lua: 10008

Request Information:
	client_address=172.16.0.3
	method=GET
	real path=/
	query=
	request_version=1.1
	request_uri=http://kkumtree.abc:8080/

Request Headers:
	accept=*/*
	host=kkumtree.abc
	user-agent=curl/8.5.0
	x-forwarded-for=<๋กœ์ปฌ ํ™˜๊ฒฝ์˜ ๊ณต์ธ IP>
	x-forwarded-host=kkumtree.abc
	x-forwarded-port=443
	x-forwarded-proto=https
	x-forwarded-scheme=https
	x-real-ip=<๋กœ์ปฌ ํ™˜๊ฒฝ์˜ ๊ณต์ธ IP>
	x-request-id=0b3e51d89dfede6b31e72e8a1d09a25a
	x-scheme=https

Request Body:
	-no body in request-

8. ๋ฑ€๋‹ค๋ฆฌ

  • Ngnix Ingress Annotation ์˜ˆ์ œ๋“ค

๊ฐ€๋”์€ ๋ˆˆ์„ ๊ฐ์„ ์ค„ ์•Œ์•„์•ผํ•˜๋‚˜… ์‹ถ์€…

๋งํฌ: Ingress-Nginx Controller

    #nginx.ingress.kubernetes.io/rewrite-target: /
    #nginx.ingress.kubernetes.io/ssl-redirect: "false"
    #nginx.ingress.kubernetes.io/upstream-hash-by: $remote_addr
    #nginx.ingress.kubernetes.io/affinity: "cookie"
    #nginx.ingress.kubernetes.io/session-cookie-name: "route"
    #nginx.ingress.kubernetes.io/session-cookie-hash: "sha1"
    #nginx.ingress.kubernetes.io/session-cookie-expires: "172800"
    #nginx.ingress.kubernetes.io/session-cookie-max-age: "172800"
    #nginx.ingress.kubernetes.io/session-cookie-path: "/; Secure; HttpOnly"
    #nginx.ingress.kubernetes.io/session-cookie-secure: "true"
    #nginx.ingress.kubernetes.io/session-cookie-samesite: "Strict"
    #nginx.ingress.kubernetes.io/session-cookie-domain: "minseong.xyz"
    #nginx.ingress.kubernetes.io/session-cookie-httponly: "true"
    #nginx.ingress.kubernetes.io/session-cookie-persistent: "true"
    #nginx.ingress.kubernetes.io/session-cookie-change-on-failure: "true"
    #nginx.ingress.kubernetes.io/session-cookie-change-on-edit: "true"
    #nginx.ingress.kubernetes.io/session-cookie-change-on-renew: "true"
    #nginx.ingress.kubernetes.io/session-cookie-change-on-renew-failure: "true"
    #nginx.ingress.kubernetes.io/session-cookie-change-on-renew-edit: "true"
    #nginx.ingress.kubernetes.io/session-cookie-change-on-renew-edit-failure: "true"
    #nginx.ingress.kubernetes.io/session-cookie-change-on-renew-edit-failure-renew: "true"
    #nginx.ingress.kubernetes.io/session-cookie-change-on-renew-edit-failure-renew-edit: "true"
    #nginx.ingress.kubernetes.io/session-cookie-change-on-renew-edit-failure-renew-edit-failure: "true"
    #nginx.ingress.kubernetes.io/session-cookie-change-on-renew-edit-failure-renew-edit-failure-renew: "true"

kkumtree

plumber for infra

kkumtree

Source code on GitHub

ยฉ 2025 kkumtree and contributors All rights reserved.
Licensed under
CC BY-NC-ND 4.0