kubernetes
istio

Istio の Ingress の Path 設定における設定ルール

Istio を用いた Blue Green / Canary Deployment その1

の過程で一つだけ気になったことがある。Ingress Controller の Path 設定がうまくいかない。
この設定のルールとかのドキュメントも見当たらない。せいぜいここぐらい。

https://kubernetes.io/docs/concepts/services-networking/ingress/
https://github.com/kubernetes/kubernetes/blob/master/pkg/apis/extensions/types.go#L705

仕方がないので、いろいろなことを実験したメモを整理しておきたい。

作者注:下記でいろいろ試行錯誤していましたがわかりました!正規表現がOKです。自己解決しました

https://github.com/istio/pilot/blob/6eaac32cff162047795fb6bc5ddf5d1af8357cc3/adapter/config/ingress/conversion_test.go

Istio のイングレスコントローラーのパス設定

こんな感じのnginx のコンテナがあったときの、Ingress の設定。

/index.html
/login.html
/logout.html
/auth/login.html
/auth/logout.html
/web/index.html
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: webservice-ingress
  annotations:
    kubernetes.io/ingress.class: istio
spec:
  rules:
  - http:
      paths:
      - path: /web/.*
        backend:
          serviceName: web-service
          servicePort: 80
      - path: /auth/.*
        backend:
          serviceName: web-service
          servicePort: 80

正規表現なので、単にワイルドカードではありません。先のテストコードを抜粋すると

        {"/api/v1/", false},
        {"/api/v1/.*", true},
        {"/api/.*/resource", true},
        {"/api/v[1-9]/resource", true},
        {"/api/.*/.*", true},

という感じで設定できるみたい。

ここから下は不要ですが、一端パブリッシュしたので、記録のため残しておきます。

作者注:当初は、サンプルのため、簡単な、nginxのコンテナを作って下記のような構成にした。

/index.html
/login.html
/logout.html
/auth/login.html
/auth/logout.html
/web/index.html

様々なパターンを試すためだ。Istio (というより、Kubernetes) の Ingress の設定は次の感じ。ポイントは、paths の下。これは初めにかいたもの。Istio の Ingress にある Path でリクエストが来たら、web-serviceに転送するというもの。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: webservice-ingress
  annotations:
    kubernetes.io/ingress.class: istio
spec:
  rules:
  - http:
      paths:
      - path: /web
        backend:
          serviceName: web-service
          servicePort: 80
      - path: /auth
        backend:
          serviceName: web-service
          servicePort: 80

きれいに全く動かなかった。 rules.http.paths.path に設定するパターンをいろいろ試してみた。
結果としてほとんど動くパターンがない。唯一いけるのは、path 自体を削除すると、すべてのリクエストが、backend に転送される。

|Ingress        |Container        |Result
/web            /web/index.html     404
/index.html     /index.html         404
/web/index.html  /web/index.html    404
設定なし           上記のとおり       200 (全てのパス)

ちなみに、pathを省略する場合の書き方は

  - http:
      paths:
      - backend:
          serviceName: web-service
          servicePort: 80

という感じ。どうやら、フルパスで指定するしかなく、しかも、それが、.とか入っているといけない様子。うーむ。
もっといいようにできないだろうか?(現在MLで問い合わせ中。何かわかればアップデートします)

結局サンプルをhtmlベースで書くのをあきらめてRuby ベースに変更。Ruby じゃなくても、とにかく、パスが、.等が含まれて
いなければいいのかなと想像した。つまり、アプリケーションサーバーでの使用を想定みたいな。HTMLの場合は、さっきのパスを指定しない方法を使ってほしいのかな。

さて、こんなプログラムを書いて Docker にパックした。ほぼ、HTMLを表示するためだけのサンプル。

#!/usr/bin/ruby
#
require 'webrick'

if ARGV.length < 1 then
    puts "usage: #{$PROGRAM_NAME} port"
    exit(-1)
end

port = Integer(ARGV[0])

server = WEBrick::HTTPServer.new :BindAddress => '0.0.0.0', :Port => port

trap 'INT' do server.shutdown end

index = '
<html>
<head>
    <title>Blue Version 1.0.0</title>
</head>
<body bgcolor="#0000FF">
    <H1>This is Blue Version 1.0.0</H1>
</body>
</html>
'

login = '
<html>
<head>
    <title>V2Tester Login</title>
    <meta http-equiv="Set-Cookie" content="NAME=v2tester"> 
</head>
<body>
    <H1>You logged in as a v2 Tester.</H1>
</body>
</html>
'

logout = '
<html>
<head>
    <title>V2Tester Logout</title>
    <meta http-equiv="Set-Cookie" content="NAME=v2tester; expires=Fri, 31-Dec-1999 23:59:59 GMT;"> 
</head>
<body>
    <H1>You logged out as a v2 Tester.</H1>
</body>
</html>

'

server.mount_proc '/webpage' do |req, res|
    res.status = 200
    res.body = index
    res['Content-Type'] = 'text/html'
end

server.mount_proc '/loginpage' do |req, res|
    res.body = login
    res['Content-Type'] = 'text/html'
end

server.mount_proc '/logoutpage' do |req, res|
    res.body = logout
    res['Content-Type'] = 'text/html'
end

server.start

これをDocker にパックして deploy するとうまくいった。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: webservice-ingress
  annotations:
    kubernetes.io/ingress.class: istio
spec:
  rules:
  - http:
      paths:
      - path: /webpage
        backend:
          serviceName: web-service
          servicePort: 80
      - path: /loginpage
        backend:
          serviceName: web-service
          servicePort: 80
      - path: /logoutpage
        backend:
          serviceName: web-service
          servicePort: 80      

しかし、気が利いていない。出来立てだからかな。ちなみに、不思議な挙動があって、実は当初は、webpage -> web, login -> login, logoutpage -> logout だった。web, login は動くがなぜかlogout だけ動かず。予約語か何かだろうか。また、Edge だと、web, log は動くが、chrome だと、/web と打つと、/web/ になぜか変更されてリクエストされるので、404に。 この辺に詳しい人に、なんでそんなことになるのか聞いてみようかな。

横道にそれましたが、次は、Istio のルーティングによる、Canary に取り組みたいと思います。