티스토리 뷰

개요

 

처음 쿠버네티스 환경 구축을 하며 Istio를 사용했습니다.
자연스럽게 Istio ingress gateway를 도입해서 라우팅을 하였습니다.
하지만 Istio는 arm을 지원하지 않는다는 문제가 생겼습니다.

Istio ingress gateway를 사용하기 때문에 Istio를 사용하지 않으면 프로젝트가 올바르게 동작하지 않기 때문에 개발환경 구축에 큰 차질이 생긴 것입니다.
그래서 Istio ingress gateway를 traefik으로 마이그레이션 하여 Istio의존성을 낮추기로 했습니다.
개발환경에서는 Istio없이 구축하고 프로덕션에서는 Istio를 사용하는 방향으로 변경했습니다.

 


Traefik 설치

helm으로 traefik을 설치할때 사용할 values.yaml을 만들어줍니다.

디폴트값은 아래주소에서 확인할 수 있습니다. 각자 상황에 맞는 설정을 해줍시다.

# traefik의 dashboard를 생성하지 않습니다.
ingressRoute:
  dashboard:
    enabled: false
    
# traefik의 라우팅 설정을 할때 traefik과 다른 네임스페이스의 서비스를 이용할 수 있게 합니다.
providers:
  kubernetesCRD:
    allowCrossNamespace: true 

# traefik 서비스에 annotaion을 추가합니다.
service:
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-type: nlb
    
# traefik 서비스의 포트설정을 합니다.
# 이때 사용된 포트이름(여기서는 db)은 entrypoint가 됩니다.(나중에 다시 설명함)
ports:
  db:
    port: 3306
    expose: true
    exposedPort: 3306
    protocol: TCP
  app-debug:
    port: 2006
    expose: true
    exposedPort: 2006
    protocol: TCP

 

 

traefik을 설치합시다. 

# traefik에서 사용할 namespace 생성  
kubectl create ns traefik  

helm repo add traefik https://helm.traefik.io/traefik
helm repo update  
helm install -f values.yaml traefik traefik/traefik -n traefik

 

 

Istio Gateway -> Traefik

아래는 istio ingress gateway의 설정파일 중 일부를 가져왔습니다.

Service와 Gateway에서 80번 3306번 포트를 개방하고 있습니다.

사실 이 설정의 마이그레이션은traefik 설치할 때 만든 values.yaml의 ports부분에서 하고 있습니다. (80, 443번은 traefik에서 기본적으로 개방하고 있습니다.)

때문에 따로 수정해야할 부분은 없습니다.

apiVersion: v1
kind: Service
metadata:
  name: istio-ingressgateway
  namespace: istio-system
spec:
  ports:
    - name: http2
      port: 80
      protocol: TCP
      targetPort: 8080
    - name: db
      port: 3306
      targetPort: 3306
      protocol: TCP

	...

---
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: ingress-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "*"
  - port:
      number: 3306
      name: db
      protocol: TCP
    hosts:
    - "*"
	
    ...

 

VirtualService -> IngressRoute, Middleware

Istio VertualService를 마이그레이션해봅시다.

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: app-vs
spec:
  hosts:
  - "*"
  gateways:
  - ingress-gateway
  http:
  - match:                       # [1]
    - uri:
        prefix: /api                     
    route:                       
    - destination:               
        host: app-service
        port:
          number: 8080
    rewrite:                     # [2]
      uri: /
    corsPolicy:                  # [3]
      allowOrigins:
        - regex: ".*"
      allowMethods:
        - POST
        - GET
        - OPTIONS
        - PUT
        - DELETE
      allowHeaders:
        - Accept
        - Authorization
        - Content-Type
        - DNT
        - Host
        - Keep-Alive
        - Origin
        - Referer
        - User-Agent
        - X-User-App-Xsrf-Token
        - X-User-Login-Xsrf-Token
        - X-Requested-With
      maxAge: 1h

  tcp:                             # [4]
    - match:
        - port: 2006
      route:
        - destination:
            host: app-service
            port:
              number: 2006

 

#[1] url path에 따른 서비스 route

/admin-api/ 경로로 들어오는 리퀘스트는 app-service:8080으로 전달되게 됩니다.

entryPoints는 traefik 서비스의 포트명이라고 생각하면 이해하기 쉽습니다.

기본적으로 web(80), websecure(443)이 있고 values.yaml에서 db(3306)을 추가했습니다.

kubectl describe deploy traefik -n traefik

의 Args항목에서 확인할 수 있습니다.

 

traefik에서는 아래와 같이 작성합니다.

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: ingress-route
  namespace: traefik
spec:
  entryPoints:
    - web
  routes:
  - kind: Rule
    match: PathPrefix(`/api/`)
    services:
    - name: app-service
      port: 8080
      namespace: default

 

#[2]  rewrite -> StripPrefix

rewrite 설정은 URL path의 prefix를 실제 컨테이너에 보낼때는 수정하는 기능입니다.

아래 예제에서는 prefix를 제거하는 역할만 하기때문에 stripPrefix를 이용했습니다.

수정이 필요하다면 replacePath를 사용할 수 있습니다.

 

공식문서를 참고하십시오. 휴먼

https://doc.traefik.io/traefik/v2.3/middlewares/replacepath/

https://doc.traefik.io/traefik/v2.3/middlewares/stripprefix/

 

ex)

유저의 요청 : yourdomain.com/api/login 

rewrite : /api/login -> /login

컨테이너 : app-service:8080/login

 

traefik에서는 아래와 같이 작성합니다.

Middleware를 생성하고 route rule에 적용시킵니다.

apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
  name: strip-prefix-api
  namespace: traefik
spec:
  stripPrefix:
    prefixes:
    - /api

---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: ingress-route
  namespace: traefik
spec:
  entryPoints:
    - web
  routes:
  - kind: Rule
    match: PathPrefix(`/api/`)
    middlewares:               # 여기!!
    - name: strip-prefix-api   # 여기!!
      namespace: traefik       # 여기!!
    services:
    - name: app-service
      port: 8080
      namespace: default

 

 

#[3] CORS설정

traefik에서는 아래와 같이 작성합니다.

Middleware를 생성하고 route rule에 적용시킵니다.

apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
  name: cors
  namespace: traefik
spec:
  headers:
    accessControlAllowHeaders:
    - Accept
    - Authorization
    - Content-Type
    - DNT
    - Host
    - Keep-Alive
    - Origin
    - Referer
    - User-Agent
    - X-User-App-Xsrf-Token
    - X-User-Login-Xsrf-Token
    - X-Requested-With
    accessControlAllowMethods:
    - POST
    - GET
    - OPTIONS
    - PUT
    - DELETE
    accessControlAllowOriginList:
    - "*"
    accessControlMaxAge: 3600


---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: ingress-route
  namespace: traefik
spec:
  entryPoints:
    - web
  routes:
  - kind: Rule
    match: PathPrefix(`/api/`)
    middlewares:
    - name: strip-prefix-api
      namespace: traefik
    - name: cors           # 여기!!
      namespace: traefik   # 여기!!
    services:
    - name: app-service
      port: 8080
      namespace: default

 

 

#[4] TCP -> IngressRouteTCP

TCP의 경우는 IngressRoute로 설정할 수 없습니다. 전용으로 만들어진 IngressRouteTCP를 살펴봅시다.

IngressRouteTCP에 middleware를 추가하고 싶다면 MiddlewareTCP를 생성하시면 됩니다.

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRouteTCP
metadata:
  name: ingress-route-tcp-app-debug
  namespace: traefik
spec:
  entryPoints:
    - app-debug
  routes:
  - match: HostSNI(`*`)
    services:
    - name: app-service
      port: 2006
      namespace: default

 

 

외부인증 설정

외부인증이란 api요청을 할때 정당한 유저인지 확인하는 별도의 인증 서버를 설정하는 것입니다.

Istio에서는 envoyExtAuthzHttp라는 것을 이용합니다.

Istio의 설정법은 아래 주소에 있습니다.

https://istio.io/latest/docs/tasks/security/authorization/authz-custom/

 

traefik에서는 이 기능을 ForwardAuth라고 합니다.

아래 URL에 있는 이미지를 보면 이해하기 쉽습니다.

https://doc.traefik.io/traefik/v2.3/middlewares/forwardauth/

 

Middleware를 생성하고 적용하면 끝!

apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
  name: forward-auth
  namespace: traefik
spec:
  forwardAuth:
    address: http://auth-service.default.svc.cluster.local:8004/auth # 인증서버의 주소
    authRequestHeaders:
      - X-ADMIN-Authorization # 인증토큰이 들어간 헤더

---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: ingress-route
  namespace: traefik
spec:
  entryPoints:
    - web
  routes:
  - kind: Rule
    match: PathPrefix(`/api/`)
    middlewares:
    - name: cors
      namespace: traefik
    - name: strip-prefix-api
      namespace: traefik
    - name: forward-auth         # 여기!!
      namespace: traefik         # 여기!!
    services:
    - name: app-service
      port: 8080
      namespace: default

 

 

소감

하루 빨리 Istio의 arm대응이 되길 바랍니다. 

istio ingress gateway보다 traefik이 더많은 기능을 제공한다고 하는데 실제로 사용하는 부분에는 큰 차이를 못 느끼고 있습니다.

물론 traefik이 좀더 간편하게 설정할 수 있는 느낌이 들었습니다. middleware가 참 좋더군요.

다만 traefik이 쿠버네티스에서만 사용되는 것이 아니기때문에 검색하거나 공식문서를 읽는 것도 고통스러웠습니다.

 

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/07   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
글 보관함