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です。自己解決しました
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 に取り組みたいと思います。