Setup Ingress with Traefik
Ingress Controller 를 설치(Helm으로 Traefik 설치하기)했으니 이제 Ingress를 설정해서 실제 cluster 외부로부터의 http/https 메시지를 nginx pod에 전달되게 해 본다.
Ingress
Ingress는 Cluster 외부에서 접근하는 http/https request에 대한 라우팅을 제어하는 기능을 제공한다. Ingress | Kubernetes
ingress.yaml 파일을 다음과 같이 작성한다. . 아래는 두 가지 rule을 설정하고 있는데 host가 ‘mini1’이고, URL path가 /ost
면 podcast-nginx라는 서비스로 전달하게 하는 것과 host는 상관없이 path가 /ost
면 역시 같은 podcast-nginx로 보내는 것이다.
kind: Ingress
apiVersion: extensions/v1beta1
metadata:
name: "test"
namespace: default
spec:
rules:
- host: mini1
http:
paths:
- path: /ost
backend:
serviceName: podcast-nginx
servicePort: 8099
- http:
paths:
- path: /ost
backend:
serviceName: podcast-nginx
servicePort: 8099
Kubectl 명령을 이용해 적용해 본다.
$ kubectl apply -f ingress.yaml
ingress.extensions/test created
확인은 여느 resource와 마찬가지로 get
명령어 사용
$ kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
test <none> mini1 80 8s
상세 내용을 보려면 역시 describe
명령을 사용한다.
$ kubectl describe ingress test
Name: test
Namespace: default
Address:
Default backend: default-http-backend:80 (<error: endpoints "default-http-backend" not found>)
Rules:
Host Path Backends
---- ---- --------
mini1
/ost podcast-nginx:8099 ()
*
/ost podcast-nginx:8099 ()
Annotations: Events: <none>
YAML 파일에 기술한 대로 2가지 rule이 설정되었다.
{mini1, /ost} -> podcast-nginx:8099
{*,/ost} -> podcast-nginx:8099
404 Not Found
이전에는 NodePort에 설정한 IP 주소와 NodePort 조합으로 http://192.168.0.100:8099
로 접근했는데 이번에는 http://192.168.0.100/ost
로 접근을 시도했다.
그렇지만 별로 만나고 싶은 않은 404 에러만 덩그러니…
404 Not Found
nginx/1.19.0
Pod logs
그래도 nginx 에러가 나왔다는 건 적어도 Traefik을 거쳐 nginx가 동작하고 있는 pod까지는 request가 왔다는 걸로 보인다. 즉 이건 Ingress 설정이나 Traefik 동작에는 문제가 없다는 거.
그래서 nginx가 동작하고 있는 Pod의 로그를 보기로 했다. GitHub - derailed/k9s: 🐶 Kubernetes CLI To Manage Your Clusters In Style!를 이용해서 attach 명령을 이용하면 편리하게 로그를 볼 수 있다(심지어? kubeconfig 파일을 이용해서 다른 머신에서 cluster에 원격으로 접속할 수 있다는. k9s --kubeconfig ~/.kube/config_mini1
Unable to use a TTY - container nginx did not allocate one
If you don't see a command prompt, try pressing enter.
10.244.51.100 - - [30/Mar/2021:14:11:54 +0000] "GET /ost HTTP/1.1" 404 153 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.3 Safari/605.1.15" "192.168.0.100"
2021/03/30 14:11:54 [error] 28#28: *793087 open() "/usr/share/nginx/html/ost" failed (2: No such file or directory), client: 10.244.51.100, server: localhost, request: "GET /ost HTTP/1.1", host: "192.168.0.100"
혹시나 했는데 예상대로 요청하는 html 파일의 경로가 /usr/share/nginx/html/ost
다. 하지만 nginx는 모두 subpath 없이 /
에 파일을 두고 있으므로 /
를 찾도록 redirect 시켜야 하는데.
Ingress | Kubernetes 를 보면 rewrite-target
이라는 annotation을 사용하는 듯 한데, 해당 annotation의 prefix를 보니 아무래도 nginx
만 지원이되는 게 아닌가 싶다.
$ kubectl describe ingress test
Name: test
Namespace: default
Address: 178.91.123.132
Default backend: default-http-backend:80 (10.8.2.3:8080)
Rules:
Host Path Backends
---- ---- --------
foo.bar.com
/foo service1:80 (10.8.0.90:80)
Annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ADD 35s loadbalancer-controller default/test
그래서 Traefik이 path rewriting을 지원하는 지 검색해 보니 당연하게도 동일한 기능을 제공한다고. docker - Rewriting paths with Traefik - Stack Overflow
위 글에 있는 예제는 http://monitor.app.com/service-one
를 http://service-one/monitor
로 rewriting하는 경우이다.
apiVersion: v1
kind: Service
metadata:
name: service-one
spec:
selector:
k8s-app: service-one-app
ports:
- port: 80
targetPort: 8080
---
kind: Ingress
metadata:
name: monitor.app
annotations:
kubernetes.io/ingress.class: traefik
traefik.ingress.kubernetes.io/rewrite-target: /monitor # set path to result request
spec:
rules:
- host: monitor.app.com
http:
paths:
- path /service-one # path for routing, it will be removed because of PathPrefixStrip settings
backend:
serviceName: service-one
servicePort: 80
그런데 또 찾아 보니 위의 내용은 Traefik v1에만 해당하는 거라고. v2에서는 PathPrefixStrip
기능이 Middleware
의 기능으로 옮겨졌다고 한다.
In the v2, the “modifiers” became middleware: https://docs.traefik.io/v2.0/middlewares/stripprefix/ >
Source : https://github.com/traefik/traefik/issues/5004
Middleware
`Middleware라니 이건 또 뭔가.
Overview - Traefik | Site | v2.0
Attached to the routers, pieces of middleware are a mean of tweaking the requests before they are sent to your service (or before the answer from the services are sent to the clients)
Route 동작 중에 수행할 수 있는 여러가지 작업을 정의한 것이 Middleware라고 이해된다. 확장성을 위해 단순히 경로를 차는 Routing과 경로를 조작(?)하는 등의 작업을 분리해서 Middleware라고 부르는 것 같다.
Middleware를 위한 CRD가 정의되어 있는데, Helm으로 설치하면 이미 middleware가 설치되어 있다
k get CustomResourceDefinition |grep traefik
ingressroutes.traefik.containo.us 2021-01-25T13:25:26Z
ingressroutetcps.traefik.containo.us 2021-01-25T13:25:26Z
ingressrouteudps.traefik.containo.us 2021-01-25T13:25:26Z
middlewares.traefik.containo.us 2021-01-25T13:25:26Z
serverstransports.traefik.containo.us 2021-01-25T13:25:26Z
tlsoptions.traefik.containo.us 2021-01-25T13:25:26Z
tlsstores.traefik.containo.us 2021-01-25T13:25:27Z
traefikservices.traefik.containo.us 2021-01-25T13:25:27Z
이제 원하는 작업인 /ost
를 request path에서 제거하려면 stripPrefix
기능을 이용하면 된다.
StripPrefix - Traefik | Site | v2.0
위 페이지에 있는 예제인데 쉽게 예상되는 것처럼 /foobar
, /filibar
라는 경로가 있으면 제거하라는 의미이다.
# Strip prefix /foobar and /fiibar
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: test-stripprefix
spec:
stripPrefix:
prefixes:
- /foobar
- /fiibar
적용해 보기
위 예제를 참조해서 다음과 같이 Middleware 를 설정한다.
$ cat traefik-pathstrip.yaml
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: stripprefix
spec:
stripPrefix:
prefixes:
- /ost
$ kubectl apply -f traefik-pathstrip.yaml
middleware.traefik.containo.us/stripprefix created
다만, middleware를 route rule에 적용하려면 kubernetes의 기본 object인 ingress
가 아니라 ingressRoute
를 사용해야 하는 듯 하다. IngressRoute는 또 뭔지.
IngressRoute vs. Ingress
Ingress
is a standard kubernetes object while IngressRoute
is CRD of Traefik
An ingressRoute is specific to Traefik. It’s not native to Kubernetes. It is a Custom Resource Definition which allows you to take advantage of Traefik features not exposed in the Kubernetes ingress resource
Source : What is the difference between a Kubernetes Ingress and a IngressRoute? - Stack Overflow
IngressRoute 예제의 내용에서 Routing rule과 Middleware를 내가 필요한 대로 수정한다.
$ cat ingress-route.yaml
kind: IngressRoute
apiVersion: traefik.containo.us/v1alpha1
metadata:
name: ingressroutebar
namespace: default
spec:
entryPoints:
- web
routes:
#- match: Host(`bar.com`) && PathPrefix(`/stripit`)
- match: PathPrefix(`/ost`)
kind: Rule
services:
- name: podcast-nginx
port: 8099
middlewares:
- name: stripprefix
namespace: default
그 결과는
흠…
일단 웹 페이지 자체는 잘 보이니 routing은 잘 된 듯 한데, 스타일이 이상한 걸 보니 CSS 파일들이 제대로 적용되지 않은 듯 하다. 그리고 제일 위 쪽에 이미지가 보여지지 않는 걸 보니 CSS 파일 외에 다른 파일들의 경로가 안 맞는 듯 하다. 위 페이지에서 링크를 클릭하면 링크도 제대로 동작하지 않는다는. 결국 `URL/ost/index.html’만 제대로 라우팅이 되서 화면에 보이고 나머지는 모두 제대로 동작하지 않는 모양이ㅏㄷ.
이미지 파일의 경로들을 이전에 잘 동작할 때와 지금 상황을 비교하니 이렇다.
# 이전
http://192.168.0.100:8099/
http://192.168.0.100:8099/images/logo.png
http://192.168.0.100:8099/podcast/cinema-2021-03-30/
# 지금
http://192.168.0.100/
http://192.168.0.100/images/logo.png
http://192.168.0.100/podcast/cinema-2021-03-30/
즉 8099 포트 지정하는 부분만 달라진 형태다.
그런데 생각해 보니 위 두 번째 경로들은 다음과 같아야 할 것 같다.
경로에 /ost
가 있어야 nginx pod로 전달이 될 텐데 그게 없어서 nginx pod로 전달이 되지 않아서 web browser에 표시가 안된 것이다.
http://192.168.0.100/ost
http://192.168.0.100/ost/images/logo.png
http://192.168.0.100/ost/podcast/cinema-2021-03-30/
아무래도 이건 nginx에서 설정을 변경해야 하는 것 같은데…
$ wget http://192.168.0.100/ost/index.html
--2021-03-30 23:50:44-- http://192.168.0.100/ost/index.html
Connecting to 192.168.0.100:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 34351 (34K) [text/html]
Saving to: ‘index.html’
index.html 100%[================================================================================================>] 33.55K --.-KB/s in 0s
2021-03-30 23:50:44 (155 MB/s) - ‘index.html’ saved [34351/34351]
$ wget http://192.168.0.100:8099/index.html
--2021-03-30 23:50:53-- http://192.168.0.100:8099/index.html
Connecting to 192.168.0.100:8099... connected.
HTTP request sent, awaiting response... 200 OK
Length: 34351 (34K) [text/html]
Saving to: ‘index.html.1’
index.html.1 100%[================================================================================================>] 33.55K --.-KB/s in 0s
2021-03-30 23:50:53 (179 MB/s) - ‘index.html.1’ saved [34351/34351]
$ diff index.html index.html.1
$
해결
예상대로 해결책은 nginx 의 설정을 변경하는 간단한 수정으로 충분했다.
nginx가 hosting하는 사이트는 SSG(Static Site Generator)인 hugo를 이용해서 생성한 파일들로 구성되는데, 그 site의 root에 /ost
를 추가하는 것이다. 즉 hugo 설정 파일에서 baseURL에 /ost
를 추가하는 거
$ cat config.yaml
---
...
baseURL: "http://sosa0sa.com/ost/" << 이전 값 "http://sosa0sa.com:8099"
새로 site 파일을 빌드해서 nginx에 밀어넣었더니 다음과 같이 제대로 경로가 바뀌었다.
http://192.168.0.100/ost
http://192.168.0.100/ost/images/logo.png
http://192.168.0.100/ost/podcast/cinema-2021-03-30/
짜잔. 이젠 잘 동작한다.
당연히 집 내가 아니라 외부에서도 접속이 잘 되고.