GCP, AWS와 같은 Cloud 업체에서 제공해주는 Managed K8s 환경을 사용하는 것이 아니라,
Local 환경에서 직접 K8s를 설치하는 경우
Ingress를 이용하기 위해서는 추가적인 설치를 해야 한다.
다른 네트워크 관련된 것들과 마찬가지로
Ingress도 여러가지 중에 선택적으로 설치해서 사용해야 한다.
직접 설치해서 사용하는 경우 일반적으로 Nginx 기반의 Ingress를 선택한다.
그런데, 이 부분에서 고생을 했던 이유가 Nginx 기반 Ingress 자체도 종류가 여러가지라는 것이다.
그 중에서 대표적인 Nginx Ingress Controller는 다음의 2가지 이다.
- kubernetes/ingress-nginx
- nginxinc/kubernetes-ingress
첫번째 것은 Kubernetes 진영에서 배포하고 있는 ingress-nginx 이고,
두번째 것은 Nginx 진영에서 배포하고 있는 nginx-ingress 이다.
두 배포판의 차이점을 정리한 내용은 다음 링크에서 확인해보면 된다.
- https://docs.nginx.com/nginx-ingress-controller/intro/nginx-ingress-controllers
기능적으로 Nginx에서 배포하는 것이 좀 더 다양한 것 같기는 한데,
아무래도 Kubernetes 문서에서 보이는 Ingress 내용들의 기준이 되는 것은
`kubernetes/ingress-nginx`일 것이다.
그런데, 문제는 Kubespray로 Kubernetes를 설치할 때
addon으로 ingress를 선택하게 되면
이 때 설치되는 것이 'kubernetes/ingress-nginx'가 아니다.
(잘못알고 있을 수도 있으니, 정확히 알고 계신 분들 계시면 제보 바랍니다)
그래서,
Kubespray를 이용해서 Kubernetes를 설치할 때
addon 설정할 때 ingress를 선택하지 말고
나중에 직접 Ingress를 설치하는 방법으로 하고자 한다.
Kubernetes는 설치를 마친 상태에서
Ingress 설치를 하는 과정으로 진행해보자.
Reference
- https://github.com/kubernetes/ingress-nginx/
- https://kubernetes.github.io/ingress-nginx/deploy/
다양한 환경에서의 설치 방법이 각각 있지만,
우리가 여기에서 살펴볼 것은 Bare-Metal 환경을 기준으로 하겠다.
- https://kubernetes.github.io/ingress-nginx/deploy/#bare-metal
그리고, 이 방법은 `Nodeport` 방식으로 설정된다.
(LoadBalancer가 있으면 그것을 이용하겠지만, 개인적으로 구축한 K8s 환경에서는...)
사실, 설치 방법은 너무나 쉽다.
단 1줄 !!!
정말 중요한 것은
잘 동작하는지 검증을 해보는 것일 것이다.
Namespace로 작업 공간 확보한 다음
Deployment 만들고 Service 만들어서
Ingress로 접근하도록 해보자.
① 따로 방을 잡아놓기 위해 Namespace 만들고,
apiVersion: v1 kind: Namespace metadata: name: test-ingress
② Deployment를 이용해 Pod를 만들어 놓자
$ nano 02.Deployment.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: web-deploy spec: replicas: 3 selector: matchLabels: app: web template: metadata: name: web-pod labels: app: web spec: containers: - image: whatwant/node-web:1.0 name: web ports: - containerPort: 8080 protocol: TCP
③ Pod들을 연결할 Service를 만들자
apiVersion: v1 kind: Service metadata: name: web-svc spec: ports: - port: 80 targetPort: 8080 selector: app: web
지금까지 만들어 놓은 YAML을 실행하자
$ kubectl create -f ./01.Namespace.yaml $ kubectl create --namespace=test-ingress -f ./02.Deployment.yaml $ kubectl create --namespace=test-ingress -f ./03.Service.yaml
이제, 본론이다!
Ingress를 만들어서 Service를 외부로 오픈해보자.
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: web-ingress annotations: nginx.ingress.kubernetes.io/rewrite-target: / spec: rules: - http: paths: - path: /test pathType: Prefix backend: service: name: web-svc port: number: 80
만들어 놓은 YAML을 실행하자
$ kubectl create --namespace=test-ingress -f ./04.Ingress.yaml
이제 Web-Browser로 확인을 하면 되는데,
ingress-nginx가 지금 어떤 IP의 어떤 Port로 서비스 되고 있는 것일까?
$ kubectl get services --namespace=ingress-nginx NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE ingress-nginx-controller NodePort 10.233.29.64 <none> 80:32035/TCP,443:32407/TCP 11h ingress-nginx-controller-admission ClusterIP 10.233.38.85 <none> 443/TCP 11h
`ingress-nginx`는 지금 `NodePort` 방식으로 서비스 되고 있으므로 IP는 node들의 IP 아무것이나 ...
Port는 http는 32035, https는 32407을 사용하고 있음을 확인할 수 있다.
(당연히 각자의 환경에서 Port는 다를 수 있다)
그러면, 이제 웹브라우저로 확인해보자.
어?! 왜 안되지 ?!
멍청하면 손발이 고생한다고... 이 문제를 해결하려고 3일 넘게 잠도 잘 못자고 정말 고생했다 ㅠㅠ
엄청난 구글링 시도를 했지만 속시원한 해결책을 찾지 못하다가... 결국은 방법을 찾았다.
일단, ingress-nginx의 로그를 확인해야 했었다.
$ kubectl logs --namespace=ingress-nginx ingress-nginx-controller-57ffff5864-p52bb -f
------------------------------------------------------------------------------- NGINX Ingress controller Release: v1.0.0 Build: 041eb167c7bfccb1d1653f194924b0c5fd885e10 Repository: https://github.com/kubernetes/ingress-nginx nginx version: nginx/1.20.1 ------------------------------------------------------------------------------- W0918 04:05:51.466315 6 client_config.go:615] Neither --kubeconfig nor --master was specified. Using the inClusterConfig. This might not work. I0918 04:05:51.466488 6 main.go:221] "Creating API client" host="https://10.233.0.1:443" I0918 04:05:51.476011 6 main.go:265] "Running in Kubernetes cluster" major="1" minor="20" git="v1.20.7" state="clean" commit="132a687512d7fb058d0f5890f07d4121b3f0a2e2" platform="linux/amd64" I0918 04:05:51.723687 6 main.go:104] "SSL fake certificate created" file="/etc/ingress-controller/ssl/default-fake-certificate.pem" I0918 04:05:51.740515 6 ssl.go:531] "loading tls certificate" path="/usr/local/certificates/cert" key="/usr/local/certificates/key" I0918 04:05:51.769911 6 nginx.go:253] "Starting NGINX Ingress controller" I0918 04:05:51.783535 6 event.go:282] Event(v1.ObjectReference{Kind:"ConfigMap", Namespace:"ingress-nginx", Name:"ingress-nginx-controller", UID:"9e277dae-b490-471f-806f-c88f9554da0f", APIVersion:"v1", ResourceVersion:"32531", FieldPath:""}): type: 'Normal' reason: 'CREATE' ConfigMap ingress-nginx/ingress-nginx-controller I0918 04:05:52.972526 6 nginx.go:295] "Starting NGINX process" I0918 04:05:52.972784 6 nginx.go:315] "Starting validation webhook" address=":8443" certPath="/usr/local/certificates/cert" keyPath="/usr/local/certificates/key" I0918 04:05:52.972852 6 leaderelection.go:243] attempting to acquire leader lease ingress-nginx/ingress-controller-leader... I0918 04:05:52.973417 6 controller.go:150] "Configuration changes detected, backend reload required" I0918 04:05:52.985822 6 leaderelection.go:253] successfully acquired lease ingress-nginx/ingress-controller-leader I0918 04:05:52.992811 6 status.go:84] "New leader elected" identity="ingress-nginx-controller-57ffff5864-p52bb" I0918 04:05:53.007665 6 status.go:204] "POD is not ready" pod="ingress-nginx/ingress-nginx-controller-57ffff5864-p52bb" node="worker2" I0918 04:05:53.043798 6 controller.go:167] "Backend successfully reloaded" I0918 04:05:53.043952 6 controller.go:178] "Initial sync, sleeping for 1 second" I0918 04:05:53.044349 6 event.go:282] Event(v1.ObjectReference{Kind:"Pod", Namespace:"ingress-nginx", Name:"ingress-nginx-controller-57ffff5864-p52bb", UID:"6b9e8d63-801f-4ac2-8533-8a0164e792bf", APIVersion:"v1", ResourceVersion:"32685", FieldPath:""}): type: 'Normal' reason: 'RELOAD' NGINX reload triggered due to a change in configuration I0918 05:25:59.272392 6 main.go:101] "successfully validated configuration, accepting" ingress="web-ingress/test-ingress" I0918 05:25:59.278726 6 store.go:361] "Ignoring ingress because of error while validating ingress class" ingress="test-ingress/web-ingress" error="ingress does not contain a valid IngressClass" I0918 05:38:54.461751 6 store.go:336] "Ignoring ingress because of error while validating ingress class" ingress="test-ingress/web-ingress" error="ingress does not contain a valid IngressClass" I0918 05:39:44.049518 6 main.go:101] "successfully validated configuration, accepting" ingress="web-ingress/test-ingress" I0918 05:39:44.053660 6 store.go:361] "Ignoring ingress because of error while validating ingress class" ingress="test-ingress/web-ingress" error="ingress does not contain a valid IngressClass"
그렇다. 원인은 로그에 다 있었다 ㅠㅠ
`IngressClass`가 문제란다.
이걸 해결하면 되는데...
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: web-ingress annotations: nginx.ingress.kubernetes.io/rewrite-target: / ingressclass.kubernetes.io/is-default-class: true spec: rules: - http: paths: - path: /test pathType: Prefix backend: service: name: web-svc port: number: 80
annotation 한 줄 추가해주면 된다.
모든 Ingress에 저렇게 입력하기 싫다면,
기본 IngressClass nginx를 수정하면 된다.
`ingress-nginx` namespace에 있는 ingressclass를 살펴보면 `nginx` 이름으로 존재하고 있다.
$ kubectl get ingressclasses --namespace=ingress-nginx NAME CONTROLLER PARAMETERS AGE nginx k8s.io/ingress-nginx <none> 12h
edit 하면 되는데,
막간을 이용해서 tip 하나 추가하자면,
기본적으로 `kubectl edit`를 하게되면 기본 에디터로 `vi`가 실행된다.
vi를 싫어하는 나같은 사람들을 위해 에디터 변경을 하는 방법이 있다.
$ export KUBE_EDITOR=nano
그리고, 이제 edit를 해보자.
$ kubectl edit ingressclasses nginx --namespace=ingress-nginx
apiVersion: networking.k8s.io/v1 kind: IngressClass metadata: annotations: ingressclass.kubernetes.io/is-default-class: "true" kubectl.kubernetes.io/last-applied-configuration: | {"apiVersion":"networking.k8s.io/v1","kind":"IngressClass","metadata":{"annotations":{},"labels":{"app.kubernetes.io/component":"controller","app.kubernetes.io/instance":"ingress-nginx","app.kubernetes.io/managed-by":"Helm","app.kubernetes.io/name":"ingress-nginx","app.kubernetes.io/version":"1.0.0","helm.sh/chart":"ingress-nginx-4.0.1"},"name":"nginx"},"spec":{"controller":"k8s.io/ingress-nginx"}} creationTimestamp: "2021-09-18T04:05:10Z" generation: 1 labels: app.kubernetes.io/component: controller app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: ingress-nginx app.kubernetes.io/version: 1.0.0 helm.sh/chart: ingress-nginx-4.0.1 name: nginx resourceVersion: "102271" uid: 13fa4354-bb3d-4dee-ae56-5d14600354cb spec: controller: k8s.io/ingress-nginx
나머지는 모르겠고 ... 위에 색으로 칠한 부분만 추가되어 있으면 된다.
문제 해결을 위해 열심히 구글링 하면서 알게된 지식 추가 공유 !
- Ingress 생성할 때, 연결하고자 하는 Service가 있는 namespace에 같이 존재해야 한다
. Ingress Controller는 전체 namespace를 바라보고 있기에 가능하다.
- Ingress와 연결되는 Service는 Cluster IP와 매핑이 된다.
. 그래서 Service는 Nodeport 타입이어도 되고, 아니어도 된다.
이번에는 여기까지~