์ง๋ ํฌ์คํ , 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/ ๋ง ์ธ๋ถ์์ ์ ์ํ ์ ์์ต๋๋ค.

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
Source code on GitHub
ยฉ 2025 kkumtree and contributors All rights reserved.
Licensed under
CC BY-NC-ND 4.0