Deis/routerでwhitelistでIP制限する方法
Security Considerations - Deis Workflow Documentationで公式にIP制限する方法が紹介されてるが、403が出る。
なんで403になっちゃうのかをここを調べてみた。
公式通りにやっても403
公式ページにもあっさりこうすればできると書いてあるが、確かに403になってしまう。
$ kubectl --namespace=deis annotate deployments/deis-router router.deis.io/nginx.enforceWhitelists=true $ kubectl --namespace=deis annotate deployments/deis-router router.deis.io/nginx.defaultWhitelist="0.0.0.0/0"
deis/routerが生成するnginx.conf
deis/routerくんはただのnginxなので、生成されたnginx.confを見てみる。
・・中略 server { listen 8080; server_name deis.35.189.144.204.nip.io; server_name_in_redirect off; port_in_redirect off; set $app_name "deis/deis-controller"; allow 1.2.3.4; deny all; vhost_traffic_status_filter_by_set_key deis/deis-controller application::*; location / { proxy_buffering off; proxy_buffer_size 4k; proxy_buffers 8 4k; proxy_busy_buffers_size 8k; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-Proto $access_scheme; proxy_set_header X-Forwarded-Port $forwarded_port; proxy_redirect off; proxy_connect_timeout 10; proxy_send_timeout 1200; proxy_read_timeout 1200; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_pass http://10.3.243.160:80; } } ・・・略
単に、virtual hostでallow 1.2.3.4;
してるだけ。
アクセスログを見てみると、clientのIPがこちらのIPになってない。ここが問題のようだ。
2017/04/03 10:40:27 [error] 81#0: *739 access forbidden by rule, client: 10.146.0.2, server: deis.35.189.144.204.nip.io, request: "GET /v2/ HTTP/1.1", host: "deis.35.189.144.204.nip.io" [2017-04-03T10:40:27+00:00] - deis/deis-controller - 10.146.0.2 - - - 403 - "GET /v2/ HTTP/1.1" - 406 - "-" - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36" - "deis.35.189.144.204.nip.io" - - - deis.35.189.144.204.nip.io - - - 0.000
Client IPを保存するには??
kubenetes v1.5から、beta機能として、loadbalancerがclient IPをpreserveするような機能がついたので、その設定をいけば、client ipがrealなものになる。 やり方は、
$ kd annotate services/deis-router service.beta.kubernetes.io/external-traffic="OnlyLocal"
403になる原因としては、client ipがLoadbalancerのものか、kubernetesの何かのものになってしまったため。Deisの問題でもなく、GCPの問題でもなく、kubernetesの問題だった。以前からissueにあがっており、1.5からGCPとAzureのみ対応できた模様。AWSのELBに関しては、proxy protocolが使えるのであまり問題になっていなかった模様。
LoadbalancerにGCPのfirewall指定すればいいのでは?
この方法もkubernetesのannotateをすることで実施することができた。
単にfirewall設定をするだけでいけた。
https://kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/ をみると、loadBalancerSourceRanges
で設定できるとある。
When using a Service with spec.type: LoadBalancer, you can specify the IP ranges that are allowed to access the load balancer by using spec.loadBalancerSourceRanges.
annotateで指定してあげると、即座にfirewallにsource rangeが反映される。
$ kd annotate services/deis-router service.beta.kubernetes.io/load-balancer-source-ranges="5.6.7.8/32"
これを打つと、annotationsにこれが追加される。
そうすると、もともとあったfirewall ruleが更新される。
試しに、この状態で、service.beta.kubernetes.io/external-traffic=“OnlyLocal"を削除したら、接続できなくなった。 これがないとどちらにしろ、LBでfirewallを指定しても、deis-routerのnginxでIP制限したとしてもIP制限は働かないということになる。
まとめ
- GKE上のDeisでIP制限するにはGCPのfirewallを使うか、deis/routerのnginxでIP制限するかの2通りのやり方がある
service.beta.kubernetes.io/external-traffic="OnlyLocal
これがないとClientIPが保存されない
deis-routerなしでKubernetesのIngressでDeisを動かす
Clusterを作る時にデフォルトでついてくるLBを外す
gloucd container clusters create
をするときに、--disable-addons "HttpLoadBalancing"
をつける。これをしないとGLBCがIngress Controllerとなってしまうため。コマンドラインからしか外せない。
cluster作成後どうなってるか
このときはkube-systemのnamesapce配下にkubernetesが動くために必要なものが起動されてる。addonを外したので、l7-default-backend
などは存在しない。
フラグ付きでDeisをインストール
$ helm install deis/workflow --namespace deis \ --set global.experimental_native_ingress=true \ --set controller.platform_domain=example.com
global.experimental_native_ingress=true
がポイント。
deis/routerの代わりにingressが作成されている。
$ kd describe ing Name: controller-api-server-ingress-http Namespace: deis Address: Default backend: default-http-backend:80 (<none>) Rules: Host Path Backends ---- ---- -------- deis.example.com / deis-controller:80 (<none>) Annotations: Events: <none>
この段階でGCP側にこの辺が追加になる。
Ingress Controllerをインストール
今は、addonで外しているのでIngress Controllerがkubernetes上にいない状態。helmコマンドでIngress controllerをインストールする。今回は、treafikというLBのソフトウェアを利用する。
$ helm install stable/traefik --name deis-ingress-001 --namespace kube-system
これをすると
あとは、このとき作成されたLBのExternal IPとdeis.example.comをひけるAレコードを作成する。
Deisでアプリケーションをdeploy
通常通りregisterして、アプリケーションをdeployしたりすると以下のような動きをしてルーティングが行われる。
- アプリケーションのnamespaceが追加
- 該当のnamespaceにアプリケーションのdeploymentが追加
- 該当のnamespaceにClusterIP型のserviceが追加
- 該当のnamespaceにIngressも追加されて、そのClusterIP型のserviceを向く
internet | [ LB ] | [ Traefik ] ____|____________________ | | [ deis/controller ] [ App ]
cluster作成時に作られるaddonのGLBCでやってみたが
これがうまくいかなかった。 まず、さっきと同じようにhelm installしたあとのFirewallとIngressの状態がちょっと違う。 まず、FirewallはGCP内のロードバランサーたちが所属するCIDRから、Nodeへの特定TCPポートを開くルールが作られる。これはhealthcheck用のようだ。
で、Ingressはdeis-controllerサービスが見つかりませんよーというエラーが出てくる。
$ kd describe ing Name: controller-api-server-ingress-http Namespace: deis Address: 130.211.37.103 Default backend: default-http-backend:80 (10.0.2.3:8080) Rules: Host Path Backends ---- ---- -------- deis.example.com / deis-controller:80 (<none>) Annotations: forwarding-rule: k8s-fw-deis-controller-api-server-ingress-http--90b3b4269724c70 target-proxy: k8s-tp-deis-controller-api-server-ingress-http--90b3b4269724c70 url-map: k8s-um-deis-controller-api-server-ingress-http--90b3b4269724c70 backends: {"k8s-be-31752--90b3b4269724c7ab":"Unknown"} Events: FirstSeen LastSeen Count From SubObjectPath Type Reason Message --------- -------- ----- ---- ------------- -------- ------ ------- 3m 3m 1 loadbalancer-controller Normal ADD deis/controller-api-server-ingress-http 2m 2m 1 loadbalancer-controller Normal CREATE ip: 130.211.37.103 2m 2m 3 loadbalancer-controller Warning Service Could not find nodeport for backend {ServiceName:deis-controller ServicePort:{Type:0 IntVal:80 StrVal:}}: Could not find matching nodeport from service. 2m 2m 3 loadbalancer-controller Normal Service no user specified default backend, using system default
deis-controllerはtype:ClusterIP
というクラスター内部IPのみで接続できるサービスとして公開されるようになってるが、このClusterIPとIngressとGLBCだと相性が悪く接続に失敗するようだった。ドキュメントにちゃんと書いとけよ的なissueもあがってた。
- Ingress with ClusterIP services #26508
- ingress user guide should mention that services need to be of the NodePort type #26579
- https://issuetracker.google.com/issues/35906963
なので、現状は、GLBCをIngress ControllerとしたGKE上ではNative Ingressの利用は難しそうだった。。
まとめ
やってみるとまだ対応されてない(grafanaとかのルーティングがない)ところがあって、フラグについてるExperimentalは伊達じゃないと感じた。なので、やっぱりdeis/routerを使う方法にすることにした。
GKEだとデフォルトでIngress Controller(=GLBC)がいる
おまえ、そこにいたのか
kubernetesでIngressでやる場合、Ingress Controllerが必要なんだけど、GKEの場合はマスターノード、つまりGCPのマネージドな領域でクラスター作成時に一緒に作られるようになってた。
で、これをGLBC(GCE Load-Balancer Controller) Cluster Addonという。
Ingress Controllerを作るときはgceかnginxのclassが標準で用意されてたけど、このgceっていうやつはGLBCのことで、ただ、GLBCはGKEだと最初からaddonされるから作らなくてよいということだった。
自分で作りたい場合は、cluster作成時に、コマンドとかAPI経由でのみ、外せる。GUIコンソールからだと無理だった。
GLBCとは
なんとなく、GCPにおいてあるロードバランサーのことだろって思ってたけど違う
これはkubernetes側が勝手に名前をつけたやつで、GCPのリソースを組み合わせてL7のロードバランサー相当のものを作る命令のあつまりみたいなもの。まさにcontroller。あと、ルーティングしたときにどこにもあてはまらないリクエストがきたときにデフォルトの404ページを出してくれるだけのバックエンドのセット。
Ingressを作ると、GLBCがたたかれて、GLBCがGCPのAPIをたたいて、L7のロードバランサーを実現するために、GCPでL7ロードバランサーをするための設定をしてくれる。
で、そのGLBCはどこにいるかっていうとGKEの場合は、cluster作成時にマスターノード
に作られていたって話でした。kube-systemっていうnamespaceが基本的にcluster作成時にできるものなんだけど、ここにGLBC相当のものがいないのではまった。ただ、さっき言った404出してくれるl7-default-backend
はNodeの方にいるのでこの管理画面に表示されてるのが分かる。
Deis Workflow v2.13.0でKubernetesのIngressがサポートされた件
Deisがverupした
本日、Deis Workflowがverupしたんですが、Changelogを見てるとIngressというものがなんか導入されてDeis/routerなくてもいけるみたいなことが。
そもそもWhat is Ingress?
Kubernetesのたくさんあるリソースのタイプのうちの一つのIngress。 これについて学習したその記録を残す。
Kubernetesのリソース Service
まず、Ingressを理解する前にKubernetesにおけるServiceを理解する必要がある。ServiceもKubernetesのリソースのタイプのうちの一つで、簡単に言うとclusterと外部を接続を抽象化したもの。例えば、このserviceのtypeをLoadBalancer
と書けば、kubernetesがいい感じにバックエンドのクラウドプロバイダーを見て勝手にLBを作ってくれる。
バックエンドがAWSならELB、GCPならGoolge Load Balancingという具合に。
こういう概念になる。
internet | ------------ [ Service ] (例: ELBなど) | [ App ]
:point_up: ここでは分かりやすさのためにAppって書いてるけど、本当はKubernetesの場合、コンテナのセットのPodという単位が基本。本当はそのPodを集合したReplicaSet、それを司るDeploymentとかがいるんだけど、その辺は割愛。まぁアプリケーションが動いているコンテナがいると思ってくれればOK。
他に増えたらルーティングどうするの
さっきの例だと一つのServiceとあるバックエンドのアプリケーションという感じだった。これを複数のアプリケーション立ち上げようとするとどうなるかっていうと、Serviceをたくさん増やしてあげればいいんだけど、そうするとその分、外部から接続するためのIPアドレスがたくさん生成されるし、DNSレコードの管理とか面倒になってくる。DNSだとキャッシュとかあるし、迅速で柔軟な変更が難しいよね(って話がどっかに書いてあったんだけど忘れてしまった・・)
internet | [ dns ] |-----------|-----------| ------------------------------------ IP:1.2.3.4 IP:5.6.7.8 IP:9.1.2.3 [ Service ] [ Service ] [ Service ] | | | [ App ] [ App ] [ App ]
じゃあDeis君はルーティングどうしてたのか
Deis/routerっていうcomponentがあって、それがLBと振り分けを行うnginxで構成されてた。GCP上で作るとこうなる。Load Balancerは1つなのでIPアドレスも一つ。
internet | [ dns ] | ------------------------------------- IP:1.2.3.4 [ Service ] <- Google LoadBalnacing | [ Deis/router ] <- 簡単に言えばただのnginx。virtual hostでbackendに流す | ------------------------ | | | [ App ] [ App ] [ App ]
Deis/routerの代わりにKubernetesのリソース Ingress
Ingressは各Serviceへのルーティングのルールセットを抽象化したようなもの。L7のルーティングができるやつ。そのルールの書き方は、host baseだったり、pathベースだったりで書ける。また、SSL終端などの設定も書くことができる。 例:
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: test-ingress spec: rules: - http: paths: - path: /testpath backend: serviceName: test servicePort: 80
ただ、Ingressはルールを抽象化しただけのobjectなのでこいつ自身がルーティングとか何かの処理を受けるということではなく、ルーティングしたりする実際の処理を行うIngress Controllerという実体へ命令するだけである。 なので、Ingressへルールを書くと、何が起きるかというと、そのルールを見て、バックエンドにいるIngress ControllerへAPIを発行するなり、configを突っ込んだりするなどの命令を出すだけの存在。なので、terraform的なものに近いのかもしれない。
Ingress Controllerとは
で、Ingress Controllerってなんなのかっていうと、結局は、LoadBalancerの実装である。標準で用意されているIngress ControllerはNginxとGCEという2つがあり、Nginxは単にnginxでできたLBの実装である。 もちろん、自分でIngress Controllerを作ることもできる。例として、traefikというGolangでできたReverse Proxy的なやつをIngress Controllerとする例がDeisの公式にはのっていた。
GCEの場合は、Google Loadbalancing、URL MapなどGCPのリソースでそれを実現するようになってる。
なので、Ingressを使った場合はこのようになる。下の図の外部と接続するServiceからAppと接続するための内部用Serviceあたりまでを多分管理してくれる。
internet | [ dns ] | ------------------------------------- IP:1.2.3.4 [ Service ] <- Google LoadBalnacing | [ HTTP TargetProxy や URL map ] <- GCPの振り分けしてくれるやーつ | ------------------------ | | | [ Service ] [ Service ] [ Service ] <- 内部IPだけのNodePortというtypeのサービス | | | [ App ] [ App ] [ App ]
まとめ
なので、Ingressを使えば、Deis/routerはいらなくなるっていう話。Deis/routerは設定が色々面倒なので、Ingressを利用した方が色々とすっきりしそうだし、わざわざこれが作られるってことは今後はDeis/routerからIngressベースのものになっていくのではと予想している。 というか、Deis君が実装しているものはどんどんKubernetesが吸収していき、いつかDeis君はいなくなるのではという未来が見えてきた。
あと、KubernetesはIngressやServiceのように現実世界のある何かを一つのものに抽象化して、裏側でよしなに実装がせっせと書いてあるという仕組みになっている。ほんと発想がすごい なので、Kubernetesやるときは、あんまりTerraformの出番がない。ないけど、あんまり困らない。なぜかっていうとKubernetesもTerraformみたいなものでもあるから。
【AWSしかやったことない人向け】AWSとGCPのネットワークの違いを理解してみよう
背景
- AWSでVPC作ったりしたことあるけど、GCPやったことないって人は色々違いに戸惑う
- アカウントの関係性、ネットワークの概念の違いなどを理解したのでまとめた
AWSとGCPのアカウントの考え方の違い
AWSの場合、ある人間に対して色々なAWSアカウントが付与される。
(人間) -> 個人で発行されたアカウント -> 会社で発行されたアカウント
GCPの場合、ある人間は色々なプロジェクト
というものに属することができる。
そして、その人間が使うアカウントはGmailとかで使ってるようなGoogleアカウントである。
(人間 with Googleアカウント) -> プロジェクト 会社のやつ -> プロジェクト 何の関係もない個人のやつ
GCPの方が始めるのはすごく簡単な気がする。アカウント管理もGoogleアカウントさえやっときゃいいみたいな感じなので、Googleにロックインされる感はある。
まずはAWSのネットワークについて説明するよ
VPCとsubnetについて
AWSではこの2つが基本となる考え方。VPC
は各region内における仮想的なネットワークで、subnet
はそれらをさらに分割した論理的な単位。
VPCはregionをまたぐことはできず、regionごとに作ることしかできない。region内で複数VPCを作ることは可能。
subnetはVPCに属しているのでVPCで決めたネットワーク範囲内(下の図だと172.16.0.0/16)の範囲でのみ作成できる。
この上の図は、AWSでインフラ作るときに、ごく一般的な構成を図示している。各regionごとに、VPCを作り物理的にはavailability-zone
で分かれていてその中にsubnetを作っていくみたいなやつ。
subnetをpublic subnet
とprivate subnet
と便宜的に呼び、public subnetには、NAT Gateway
とpublicなIPアドレスを持ったインスタンスを置く。private subnetにはpublicなIPアドレスを持たないインスタンスをおいておく。
private subnetが外部と通信する場合は、NAT Gateway経由で外に出て行き、private subnet内のインスタンスに接続するには、public subnetにある踏み台インスタンスなど経由で接続をする。
security groupについて
AWSでは、各インスタンスの通信の制限を基本的にsecurity groupで行う。ACLもあるけどね
security groupの考え方は、特定のインスタンスや、特定のIPアドレスからの特定のプロトコルを受け付けるというものを作成して、それをインスタンスに付与していく。
上の図でいえば、例としてsg-1とsg-2、sg-3が作成されている。
sg-1はpublic subnetにあるi-01のインスタンスからのみsshを受けるというルールで、private subnet内にあるi-02とi-03にルールを付与するというやり方をとる。俗に言う踏み台とかbastionと呼ばれるインスタンスのやり方。 こうすると、private subnet内のインスタンスは踏み台経由でないとsshログインできないということになる。
sg-2も同様に別のavailability zoneにおける踏み台のsecurity groupを表現している。 sg-3は、i-01とi-04のインスタンスへ外部からsshアクセスできるということ。
こんな風にまずは、セキュリティグループを作り、それを各インスタンスにつけていくという流れをとるのがAWS流の基本的なやり方。
ここまでを踏まえて、次でGCPのネットワークについて説明します。
GCPのネットワーク
ネットワーク
とサブネットワーク
という概念
GCPにおいて、各プロジェクトはネットワークというものを複数作成することができる。さらに、ネットワークは複数のサブネットワークを持つことができる。
まず、ネットワークという単位には、CIDRはない。なんとなくVPCと対比で考えるとCIDRがあって欲しいところだけどない。あくまでも論理的なオブジェクトでしかない。
このネットワークに対して、サブネットワークというものを切ることができる。このサブネットワークはCIDRを持っている。ここがポイント。
この辺を図で説明してみる。
この図はGCPにおけるネットワーク構成。AWSのVPC的なネットワーク構成とだいぶ異なっている。なおこの図では、プロジェクトを作ると必ず作成されるデフォルトネットワーク
と呼ばれるものを示している。
デフォルトネットワーク
だと、必ずリージョンごとにサブネットワークが一つ作成される。GCPだと、AWSのVPCのようにregionごとのネットワークではなく、なんと、最初から全リージョンをまたいだネットワークが作成されてるのだ。つまり、全リージョンまたいだインスタンスそれぞれに内部IPアドレスでアクセスできるということを示している。
じゃあ、なんでサブネットワークなんてものがあるのかというと、単に名前をつけたいというぐらいのものであると思って欲しい。 たとえば、全世界のリージョンにインスタンスがあるけれど、sshをするのは日本のリージョンだけとしたいみたいなときに、CIDRをつけられるサブネットワークがないと、日本のインスタンスたちが属するIPアドレスの範囲が分からず、IPアドレスガチャ状態になってしまう。
Nat Gatewayなんてものは基本的にない
GCPはとても男らしくて、基本的に全インスタンスに外部IPをつけようとする。 で、外部IPがつけられたインスタンスが外部に通信しにいくときは、そのインスタンスにつけられた外部IPをsourceIPとして接続しにいく。 逆に外部からそのインスタンスに通信しにいくときもこの外部IPを使って接続しにいく。
GCPの場合、sshなどもGoogleアカウントと統合されてるので基本的に自分で.ssh/authorized_keys
に書き込んだりはしない。Googleアカウント側を2段階認証などで守ればそれでOKみたいという考えだろうか。まぁどんな環境だろうと必ずどこかは穴を開けないといけないので同じっちゃ同じ。
もちろん、外部IPをなしにすることもできる。その場合、このインスタンスは外部への通信も外部からの通信も受けることができない。ただ、内部IPはあるので、ネットワーク内のインスタンスであれば通信することは可能である。
どうしても、NAT Gatewayのようなことがやりたければ、通常のインスタンスをたててNATの役割をさせて、すべてのインスタンスの外部IPをなくして、ルートテーブルを修正して、NATインスタンス経由で外に出て行くようにすればいい。 NATの役割をする場合は、インスタンスを作成するときにルーティング可能にできるオプションを選択するだけでよい。
Firewall
GCPにはFirewallと呼ばれるAWSのSecurityGroup相当のものがある。このFirewallという機能がGCPとAWSで随分と違う部分。
GCPの場合は、各インスタンスにタグ
と呼ばれるものを好きなだけ貼ることができる。このタグをベースにネットワークの制限をつけていく。
ここで再びさっきの上の図を詳しく見ていく。
firewallルールのrule2を見ると、3.4.5.6からのTag:a
へのHTTP接続を受け付けるというルールを作成してある。この場合、Tag:aがついているすべてのインスタンスは、外部からhttp接続できるということである。
rule3を見ると、10.146.0.0/20からTag:b
へのHTTP接続を受け付けるというルールを作成してある。この場合、tokyo regionのサブネットワーク内にあるVMインスタンスすべて(VM1,2,3)からus regionにあるTag:b
がついているインスタンスはHTTP接続を受け付けるということである。
さらに、rule1で、すべてのインスタンスは10.0.0.0/8からのSSH接続を受け付けるというルールを設定しておく。そうすると、このネットワーク内のインスタンスは10.0.0.0/8に属する(10.0.0.1 ~ 10.255.255.254)ので、お互いにssh接続ができるという仕組み。このように特定のタグではなく、すべてのターゲットという指定もできる。
Firewallのソースフィルタ
rule1のような、特定のIPアドレス範囲から受け付けるという部分をソースフィルタという。これも結構変わった考え方で面白い。どういうことかというと、CIDRで例えばクラスBとクラスCのアドレス同士でも設定できるということ。
ここで出てくるのがさっき説明したサブネットワークだが、デフォルトネットワーク以外であれば、サブネットワークには好きなCIDRをつけられる。
|サブネットワークA| 172.20.0.0/20 |インスタンス A1| 172.20.10.5 <------ | |サブネットワークB| 192.168.100.0/24 | HTTP | |インスタンス B1| 192.168.100.99 -----
とした場合、通常は別ネットワークとなるがFirewallのソースフィルタでは単なる名前でしかないので関係なく指定することができる。 サブネットワークAにインスタンスA1、サブネットワークBにインスタンスB1がいたとして、Firewallとしてはソースフィルタに、192.168.100.0/24を指定してhttpを許可したとしてタグを作成して、そのタグをA1につければ、A1はB1からhttp接続を受け付けられるようになる。
これはAWSにはなかった概念だと思う。
まとめ
AWSとGCPの違いを人に説明しようと思ってみたけど説明しようとすると自分でもよくわかってない部分にぶちあたるという感じになった。
GCPも調べてみると色々利点があり、(安い、全世界またがったネットワークが強い、googleアカウントとの統合がうまい、LBの温め不要)ちょっと好きになってきた。
両者の違いをかなり個人的な感想だけどこんなイメージ。
- AWSさんはベーシックなネットワーク構成をクラウド上に再現して顧客のためにどんどん使いやすいようにがんばってくれる優等生
- GCPはVPC作って、subnet作ってとかそういうのめんどくさいから、もうVMインスタンス主役でちゃっちゃとグーグルアカウントでやっちゃおうぜ、あ、俺らが使ってるplatformそのまま貸してあげるけど俺らの新しい概念についてきてね!
みたいなスタンスの差を感じた。
Kubernetsに出てくる用語:PVCとは?
PVCとは?
KubernetesのPersistentVolumeClaimsの略である。 https://kubernetes.io/docs/user-guide/persistent-volumes/#persistentvolumeclaims
A persistentVolumeClaim volume is used to mount a PersistentVolume into a pod. PersistentVolumes are a way for users to “claim” durable storage (such as a GCE PersistentDisk or an iSCSI volume) without knowing the details of the particular cloud environment.
KubernetesのVolume
まず、PVCを理解するには、そもそもkubernetesにはVolumeという概念があることを知らないといけない。
https://kubernetes.io/docs/concepts/storage/volumes/
Volumeはdockerの-v
でvolumeをマウントするような感じで、色々なVolume typeをサポートしていて、例として、nodeのDiskを利用してpodが削除されたら一緒に消えるemptyDir
、GCEのpersistent diskを利用するgcePersistentDisk
、AWSのEBSを利用するawsElasticBlockStore
、gitのrepositoryを利用するgitRepo
などがある。
例えば、volume typeでGCPのgcePersistentDisk
を利用したければ、先にgcloudコマンドなどでGoogle persistent diskを作成しておいて、このvolume typeでgcePersistentDisk
を指定してあげるという流れになるが、それをkubernetesがdiskも作成してくれるという方法がある。
PersistentVolume
それがPersistentVolume
という仕組み。podと同じような感じでyamlで記述できて、容量(10GB)とか、読み書き権限とか、どこのプロバイダーで作るかみたいなものを記述する。こんな感じ。kindがPersistentVolume
。
apiVersion: v1 kind: PersistentVolume metadata: name: pv0003 spec: capacity: storage: 5Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Recycle storageClassName: slow nfs: path: /tmp server: 172.17.0.2
やっとPersistentVolumeClaimsにたどり着いた
でも、PersistentVolumeだと容量を動的に変えたいとか、GCPじゃなくてAWSにやっぱり作りたいとかそもそもいらない、みたいな感じで動的に作成することはできない。
そのためにあるのが、PersistentVolumeClaims
です。これは最近できた?やつっぽくて、StorageClass
でGCPとかAWSとか指定しておけば、あとは、設定値とかで必要になったタイミングで作成してくるというもの。
Deisの場合、install時にあるcomponentをcluster外に自分で作るか、cluster内に作ってもらうか選べる。そんなときに、PersistentVolumeClaims
で指定しておけば、ユーザーがcluster内にあるcomponetをたてたい、しかも、diskをpersistentしたいってときに、動的にサイズを指定しつつそのproviderにあったディスクをたて、mountまでしてくれるというもの。
なので、多分、podのmountのとこに、volumeType: PersistentVolumeClaims
みたいに書いてあるはず。
claimは苦情をつける、注文をつけるみたいな意味なので、Persistent Volumeを注文するみたいな風にとらえればよい。
まとめ
何か分からない用語が出てくると、deisの概念なのか、kubernetesの概念なのか、GCPの概念なのかで小一時間理解に時間がかかる:joy:
Deisのpostgresをoff-clusterにする(postgresql on GCEを利用)
やること
前回はCloud SQLを使ったが、Cloud SQLはデフォルトネットワーク外にあるので、Cloud SQL Proxyをたてて通信するか、外部IPを許可するしかなかった。Deisの場合だと、proxyたてるパターンを使えず、外部IPを許可する方法にしたけど、これだとNodeのIPが変わったり増えたときに対応できない。 なので、素直にGCE上にpostgresqlをたてることにした。
Cloud Launcher
postgreSQLをinstallとかめんどくさいなーって思ってたら、Cloud Launcherなるものを発見した。ぽちぽちっとやるだけで、いい感じにインストールまでしてくれる。本当の本当の本番ならこれはよくないかもしれないけど、今回はこれを使うことにした。
こんな感じで選んで、
できた。
単なるVMインスタンスとして出来上がっているので、まぁあとから修正は好きなように加えられるだろう。
sshするには
外部IPが振られているNode経由で、ログインできる。
$ gcloud compute ssh --ssh-flag="-A" <NODE_INSTANCE_NAME> # gcloudコマンドでmponユーザーとしてGoogleの認証がうまいことやってくれてる # さらに内部のインスタンスへはインスタンス名を入れるだけでつなげる。 # この辺がGCPのすごいところ。 mpon@gke-xxxxxxx-p-default-pool-d02cceda-15xb ~ $ ssh deis-postgres-vm The programs included with the Debian GNU/Linux system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law. ___ _ _ _ | _ |_) |_ _ _ __ _ _ __ (_) | _ \ | _| ' \/ _` | ' \| | |___/_|\__|_|_|\__,_|_|_|_|_| *** Welcome to the Bitnami PostgreSQL 9.6.2-0 *** *** Service accessible using hostname 10.146.0.5 port 5432 *** *** Documentation: https://docs.bitnami.com/google/infrastructure/postgresql/ *** *** https://docs.bitnami.com/google/ *** *** Bitnami Forums: https://community.bitnami.com/ *** mpon@deis-postgres-vm:~$
あとは、configuring-postgresの内容でdeis君用のdatabaseとuserを作るだけ。
helm install
deis-postgres-vmの内部IPは、例によってコマンドでとれる。
def sql_instance_address res = `gcloud compute instances describe deis-postgres-vm` YAML.load(res)["networkInterfaces"].first["networkIP"] end
これで持って、helm installすると・・・・
$ kd get pods NAME READY STATUS RESTARTS AGE deis-builder-1364651073-9kcjd 1/1 Running 0 28m deis-controller-2711454920-5v8p5 1/1 Running 0 28m deis-logger-176328999-qmdqv 1/1 Running 5 28m deis-logger-fluentd-9frz3 1/1 Running 0 28m deis-logger-fluentd-hkkcl 1/1 Running 0 28m deis-logger-fluentd-xlrfz 1/1 Running 0 28m deis-logger-redis-304849759-wqb0f 1/1 Running 0 28m deis-monitor-grafana-432627134-1f8qr 1/1 Running 0 28m deis-monitor-influxdb-2729788615-qlmc4 1/1 Running 0 28m deis-monitor-telegraf-l8ttq 1/1 Running 2 28m deis-monitor-telegraf-sscvx 1/1 Running 1 28m deis-monitor-telegraf-svpxc 1/1 Running 1 28m deis-nsqd-3597503299-rcjr8 1/1 Running 0 28m deis-registry-169338602-2jkwm 1/1 Running 0 28m deis-registry-proxy-6m6fx 1/1 Running 0 28m deis-registry-proxy-mqwm8 1/1 Running 0 28m deis-registry-proxy-vtn3v 1/1 Running 0 28m deis-router-2126433040-9jrs7 1/1 Running 0 28m deis-workflow-manager-2528409207-jt8fq 1/1 Running 0 28m
無事動いたでござる
まとめ
GCPのネットワークは、AWSのVPC的な考えとは結構違うのでそこに慣れる必要がある。
追記:これで解決
Deisのpostgresをoff-clusterにする(Cloud SQLを利用)
やること
postgresをoff-clusterする。 で、そのpostgresをどこに立てるかというとGCEにたてるかGCPのmangaedなCloud SQL(RDSみたいなやつ)があるので、どっちにするかということで、今回はCloud SQLを使ってみた。
Cloud SQL PostgreSQL beta
Cloud SQLのポスグレはまだbeta版。なので、terraformにも来てない。けど、GCPは全体的に、公式docにGUIでconsoleでやるか、CLIでやるかっていうのが並列で揃ってて、とても親切。AWSみたいに、AWS Consoleで突然何かが色々できてしまうってことがない感じ。
作成は、rakeタスクにまとめるとこんな感じ。簡単
namespace :gcp do task :create_postgresql do sh %Q(gcloud beta sql instances create deis-cloudsql-postgres \ --database-version=POSTGRES_9_6 \ --activation-policy=ALWAYS \ --backup-start-time=16:00 \ --gce-zone=asia-northeast1-a \ --maintenance-window-day=SUN \ --maintenance-window-hour=17 \ --tier=db-n1-standard-1 \ --storage-type=SSD \ --storage-size=10GB \ --storage-auto-increase \ --region=asia-northeast1 ) end end
deis君からCloud SQLに接続するには
Cloud SQLに接続するには、何通りか方法があるけど、基本的にcloud sql proxyというのをたてて、それ経由でアクセスするっていうのがいい方法のようだ。 関係ないけど、Kubernetsとかにも言えるけどこういうのうまいなって思う。
cloud sql proxyを起動したマシン上で、localhostに対してDB接続しにいくと、つながるようになってる。
で、GKEの場合どうするかっていうと、sidecarパターンというやり方で、同一Pod内にcloud sql proxyのdocker image(imageが用意されてるところも憎い!)を起動させてそれをmountしてlocalhostをproxyとして接続できるようになる。うまい。
ただ、Deis君の場合は既にpodは固定されていて、ちょっと個別にpodを書き換えたりするのは面倒・・・っていうかやり方分からない。forkして、自分で追加したりしないといけないのかもしれない。なので、cloud sql proxyのパターンは使えない。もしかしたら、clusterたてるときに各nodeに初期処理入れてcloud sql proxyのinstallとかできるのかな。。
Cloud SQLは外部からアクセスする際に、IPアドレスを指定しておけば、そこからのアクセスは受け付けるようになる。なので、今回は、GKEのnodeのIPアドレスを指定してあげたら接続できた。 AWSだとNAT Gatewayがいたりするんだけど、GCPの場合はそういうのなさそう?やるなら、自分でNAT instance立てろ的な感じかもしれない。
nodeのIPアドレスたちは、kubectlコマンド使ってとれるようになってる。便利。この情報は、kubectl Cheat Sheetに書いてあった。
kubectl get nodes -o jsonpath='{.items[*].status.addresses[?(@.type=="ExternalIP")].address}'
deis用のユーザーとdatabaseの作成
GCPは、cloud shellっていうコンソールからssh接続できる風なやつが用意されてて、それ経由で作成してもOK。(AWSにも欲しい・・)
ただ、これもCLIが用意されてるのでそっちのがいい。ので、そうした。
task :create_database do sh %Q(gcloud beta sql users set-password postgres no-host \ --instance=deis-cloudsql-postgres --password=#{ENV["POSTGRES_PASSWORD"]} ) sh %Q(gcloud beta sql users create deis no-host \ --instance=deis-cloudsql-postgres --password=#{ENV["POSTGRES_DEIS_PASSWORD"]} ) sh %Q(gcloud beta sql databases create deis \ --instance=deis-cloudsql-postgres ) end
off-clusterにしてhelm install
さっき作ったdbの情報をvalues.yamlに書く。
cloud sqlのIPアドレスは、gcloudコマンドでとれる。結果はYAML形式でかえってくるので、rubyだといい感じに処理できる。それを--set database.postgres.host
で渡してあげればOK。passwordとかも、環境変数に入れておいてinstallをする。
namespace :helm do task :install do sh %Q(helm install deis/workflow --namespace deis -f values.yml \ --set gcs.key_json="$(cat gcloud-service-key.json | base64)" \ --set database.postgres.password=#{ENV["POSTGRES_DEIS_PASSWORD"]} \ --set database.postgres.host=#{sql_instance_address} ) end def sql_instance_address res = `gcloud sql instances describe deis-cloudsql-postgres` YAML.load(res)["ipAddresses"].first["ipAddress"] end end
動いているようだ
$ kd get pods NAME READY STATUS RESTARTS AGE deis-builder-1364651073-83r7x 1/1 Running 0 43m deis-controller-2711454920-g32nn 1/1 Running 0 43m deis-logger-176328999-06nwq 1/1 Running 2 43m deis-logger-fluentd-fbg4m 1/1 Running 0 43m deis-logger-fluentd-nt0tq 1/1 Running 0 43m deis-logger-fluentd-ttlwl 1/1 Running 0 43m deis-logger-fluentd-zc6hd 1/1 Running 0 43m deis-logger-redis-304849759-njc4w 1/1 Running 0 43m deis-monitor-grafana-432627134-b12zt 1/1 Running 0 43m deis-monitor-influxdb-2729788615-6pl28 1/1 Running 0 43m deis-monitor-telegraf-5rhmv 1/1 Running 1 43m deis-monitor-telegraf-ckfvc 1/1 Running 1 43m deis-monitor-telegraf-pdhj8 1/1 Running 1 43m deis-monitor-telegraf-q0d2h 1/1 Running 1 43m deis-nsqd-3597503299-sxcss 1/1 Running 0 43m deis-registry-169338602-4hzmk 1/1 Running 0 43m deis-registry-proxy-7h5f2 1/1 Running 0 43m deis-registry-proxy-k8vv4 1/1 Running 0 43m deis-registry-proxy-np9ks 1/1 Running 0 43m deis-registry-proxy-xcsx8 1/1 Running 0 43m deis-router-2126433040-7js0d 1/1 Running 0 43m deis-workflow-manager-2528409207-55vjg 1/1 Running 0 43m
うまくいってないと、STATUSがCrashになってたり、RESTARTSが増え続ける。
ちなみに、kd
はkubectl --namespace=deis
のalias。Tipsが公式に書いてあた
追記:これで解決
deisでminioを置き換えるだけをやってみる
公式ページを参考に
本当にここを変えただけ。bucketはGCSであらかじめ作っておく。権限とかもなんもしてない。
diff --git a/values.yml b/values.yml index c25cfb2..1d94aca 100644 --- a/values.yml +++ b/values.yml @@ -7,7 +7,7 @@ global: # - azure: Store persistent data in Azure's object storage # - gcs: Store persistent data in Google Cloud Storage # - minio: Store persistent data on in-cluster Minio server - storage: minio + storage: gcs # Set the location of Workflow's PostgreSQL database # @@ -75,9 +75,9 @@ gcs: # key_json is expanded into a JSON file on the remote server. It must be # well-formatted JSON data. key_json: <base64-encoded JSON data> - registry_bucket: "your-registry-bucket-name" - database_bucket: "your-database-bucket-name" - builder_bucket: "your-builder-bucket-name" + registry_bucket: "my-registry" + database_bucket: "my-database" + builder_bucket: "my-builder"
deisをinstallする
適当にRakeタスク作って、コマンド実行。--set
でsecrety keyを渡せるのいいね:100:
namespace :helm do task :install do sh %Q(helm install deis/workflow --namespace deis -f values.yml \ --set gcs.key_json="$(cat gcloud-service-key.json | base64)" ) end end
状態
確かにminioはいなくなった。
$ helm status nobby-gibbon LAST DEPLOYED: Tue Mar 28 20:41:00 2017 NAMESPACE: deis STATUS: DEPLOYED RESOURCES: ==> v1/ServiceAccount NAME SECRETS AGE deis-nsqd 1 9m deis-workflow-manager 1 9m deis-router 1 9m deis-registry 1 9m deis-database 1 9m deis-builder 1 9m deis-logger-fluentd 1 9m deis-controller 1 9m deis-logger 1 9m deis-monitor-telegraf 1 9m ==> v1/Service NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE deis-monitor-influxui 10.3.254.23 <none> 80/TCP 9m deis-logger-redis 10.3.249.48 <none> 6379/TCP 9m deis-registry 10.3.250.48 <none> 80/TCP 9m deis-database 10.3.242.10 <none> 5432/TCP 9m deis-monitor-influxapi 10.3.241.35 <none> 80/TCP 9m deis-workflow-manager 10.3.242.232 <none> 80/TCP 9m deis-builder 10.3.244.107 <none> 2222/TCP 9m deis-logger 10.3.253.37 <none> 80/TCP 9m deis-monitor-grafana 10.3.245.167 <none> 80/TCP 9m deis-router 10.3.252.162 35.190.228.247 80:32439/TCP,443:30793/TCP,2222:30898/TCP,9090:30627/TCP 9m deis-nsqd 10.3.246.21 <none> 4151/TCP,4150/TCP 9m deis-controller 10.3.241.43 <none> 80/TCP 9m ==> extensions/v1beta1/Deployment NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE deis-monitor-grafana 1 1 1 1 9m deis-controller 1 1 1 1 9m deis-logger 1 1 1 1 9m deis-nsqd 1 1 1 1 9m deis-database 1 1 1 1 9m deis-builder 1 1 1 1 9m deis-workflow-manager 1 1 1 1 9m deis-router 1 1 1 1 9m deis-registry 1 1 1 1 9m deis-logger-redis 1 1 1 1 9m deis-monitor-influxdb 1 1 1 1 9m ==> extensions/v1beta1/DaemonSet NAME DESIRED CURRENT READY NODE-SELECTOR AGE deis-monitor-telegraf 4 4 4 <none> 9m deis-registry-proxy 4 4 4 <none> 9m deis-logger-fluentd 4 4 4 <none> 9m ==> v1/Secret NAME TYPE DATA AGE deis-router-dhparam Opaque 1 9m objectstorage-keyfile Opaque 4 9m minio-user Opaque 2 9m ==> v1/ConfigMap NAME DATA AGE dockerbuilder-config 2 9m slugbuilder-config 2 9m slugrunner-config 1 9m
GCSのbucketの中になんか入ってる
databaseにだけ入ってた。これがなんか状態を保存してるやつなんだろうな。
deisのアンインストール
なんとなく分かったのでアンインストール。
$ helm list NAME REVISION UPDATED STATUS CHART NAMESPACE nobby-gibbon 1 Tue Mar 28 20:41:00 2017 DEPLOYED workflow-v2.12.0 deis $ helm delete nobby-gibbon
これだけだと、secret情報が消えなかったので次に再度helm installするときに、エラーになってしまう。こんな感じで残っちゃうようだ。
$ kubectl get secrets -n deis NAME TYPE DATA AGE builder-key-auth Opaque 1 18m builder-ssh-private-keys Opaque 3 18m database-creds Opaque 2 18m default-token-vdgrd kubernetes.io/service-account-token 3 19m deis-workflow-manager Opaque 1 17m deploy-hook-key Opaque 1 18m django-secret-key Opaque 1 18m logger-redis-creds Opaque 1 18m
なので、コマンドラインで一気に消す。今までのぼくなら1個ずつ手動入力してたけどlazy nightに参加したのでがんばって怠惰になるためにワンライナーでやる。
$ kubectl get secrets -n deis | awk '{print $1}' | tail -n +2 | xargs kubectl delete secret -n deis
追記
ただ、helm deleteだけだと、完全には消えなかったので、helm delete --purge
をつける必要があった。
Deisをproduction運用するための設定の仕方調査
背景
Deisはhelmコマンドでインストールすれば簡単に入るけど、そのままだとデータ保存先がephemeralなものになってしまうのでダメ。他にもproduction運用のためにした方が設定があるのでまとめる。
調べ方
- ほとんどdeisの公式ページに書いてあった
- installing-workflow
- production-deployments
- cloud sql postgres/connect-container-engine
変えなきゃいけなさそうなところ
- kubernetesのバージョン
- クラスターインスタンスの推奨スペック
- object storage はminioから
GCS
へ - postgres は
Cloud SQL for postgresql
orpostgresql on GCE
- docker registryは
GCR
へ - firewallの設定。そのままだと0.0.0.0/0からつながってしまう。
- deis registerできるのをadminだけにする。controllerの設定
- Grafanaのsign upをdisableにする。
- SSLの設定。そのままだとオレオレ認証のまま?
- monitorのinfluxDBの設定。そのままだとmetricsが永続化されない。
- DNS
- routerをscaleさせた方がいいとある -> 今回はいらないかも?
変え方
kubernetsの色んなリソースをまとめたものをChartという。まぁざっくりいうとyumとかhomebrew的なもの。 実はChartには海図という意味があり、kubernetesがギリシャ語で船長みたいな意味で、helmが舵という意味なので、kubernetesがchartをもとにhelmをとると考えればなんとなく意味が分かる。
Chartはある決まったstructureをしてるんだけど、それのうちパラメータを設定できるのがvalues.ymlというもの。CLI経由で--set
で一つ一つパラメータを渡すこともできるけどめんどいから基本やらない。ただ、--set
でoverrideするとか追加するとかはやりそうな気がする。
で、DeisもChartで管理されてるので、当然values.yml経由でパラメータを変更する。
values.ymlの持ってきかたは、helm inspect
サブコマンドで取得できる。valuesをつけなければ、values以外の基本的な情報を取得できたりする。ちなみに、当然だけど、deis/workflow以外のものの場合も同様で、deis/workflow
の部分をstable/mysql
とかにすれば、情報がとれる。
helm inspect values deis/workflow | sed -n '1!p' > values.yml
values.ymlの内容はこれ
global: # Set the storage backend # # Valid values are: # - s3: Store persistent data in AWS S3 (configure in S3 section) # - azure: Store persistent data in Azure's object storage # - gcs: Store persistent data in Google Cloud Storage # - minio: Store persistent data on in-cluster Minio server storage: minio # Set the location of Workflow's PostgreSQL database # # Valid values are: # - on-cluster: Run PostgreSQL within the Kubernetes cluster (credentials are generated # automatically; backups are sent to object storage # configured above) # - off-cluster: Run PostgreSQL outside the Kubernetes cluster (configure in database section) database_location: "on-cluster" # Set the location of Workflow's logger-specific Redis instance # # Valid values are: # - on-cluster: Run Redis within the Kubernetes cluster # - off-cluster: Run Redis outside the Kubernetes cluster (configure in loggerRedis section) logger_redis_location: "on-cluster" # Set the location of Workflow's influxdb cluster # # Valid values are: # - on-cluster: Run Influxdb within the Kubernetes cluster # - off-cluster: Influxdb is running outside of the cluster and credentials and connection information will be provided. influxdb_location: "on-cluster" # Set the location of Workflow's grafana instance # # Valid values are: # - on-cluster: Run Grafana within the Kubernetes cluster # - off-cluster: Grafana is running outside of the cluster grafana_location: "on-cluster" # Set the location of Workflow's Registry # # Valid values are: # - on-cluster: Run registry within the Kubernetes cluster # - off-cluster: Use registry outside the Kubernetes cluster (example: dockerhub,quay.io,self-hosted) # - ecr: Use Amazon's ECR # - gcr: Use Google's GCR registry_location: "on-cluster" # The host port to which registry proxy binds to host_port: 5555 # Prefix for the imagepull secret created when using private registry secret_prefix: "private-registry" s3: # Your AWS access key. Leave it empty if you want to use IAM credentials. accesskey: "" # Your AWS secret key. Leave it empty if you want to use IAM credentials. secretkey: "" # Any S3 region region: "us-west-1" # Your buckets. registry_bucket: "your-registry-bucket-name" database_bucket: "your-database-bucket-name" builder_bucket: "your-builder-bucket-name" azure: accountname: "YOUR ACCOUNT NAME" accountkey: "YOUR ACCOUNT KEY" registry_container: "your-registry-container-name" database_container: "your-database-container-name" builder_container: "your-builder-container-name" gcs: # key_json is expanded into a JSON file on the remote server. It must be # well-formatted JSON data. key_json: <base64-encoded JSON data> registry_bucket: "your-registry-bucket-name" database_bucket: "your-database-bucket-name" builder_bucket: "your-builder-bucket-name" swift: username: "Your OpenStack Swift Username" password: "Your OpenStack Swift Password" authurl: "Swift auth URL for obtaining an auth token" # Your OpenStack tenant name if you are using auth version 2 or 3. tenant: "" authversion: "Your OpenStack swift auth version" registry_container: "your-registry-container-name" database_container: "your-database-container-name" builder_container: "your-builder-container-name" # Set the default (global) way of how Application (your own) images are # pulled from within the Controller. # This can be configured per Application as well in the Controller. # # This affects pull apps and git push (slugrunner images) apps # # Values values are: # - Always # - IfNotPresent controller: app_pull_policy: "IfNotPresent" # Possible values are: # enabled - allows for open registration # disabled - turns off open registration # admin_only - allows for registration by an admin only. registration_mode: "admin_only" database: # The username and password to be used by the on-cluster database. # If left empty they will be generated using randAlphaNum username: "" password: "" # Configure the following ONLY if using an off-cluster PostgreSQL database postgres: name: "database name" username: "database username" password: "database password" host: "database host" port: "database port" redis: # Configure the following ONLY if using an off-cluster Redis instance for logger db: "0" host: "redis host" port: "redis port" password: "redis password" # "" == no password fluentd: syslog: # Configure the following ONLY if using Fluentd to send log messages to both # the Logger component and external syslog endpoint # external syslog endpoint url host: "" # external syslog endpoint port port: "" monitor: grafana: user: "admin" password: "admin" # Configure the following ONLY if you want persistence for on-cluster grafana # GCP PDs and EBS volumes are supported only persistence: enabled: false # Set to true to enable persistence size: 5Gi # PVC size influxdb: # Configure the following ONLY if using an off-cluster Influx database url: "my.influx.url" database: "kubernetes" user: "user" password: "password" # Configure the following ONLY if you want persistence for on-cluster influxdb # GCP PDs and EBS volumes are supported only persistence: enabled: false # Set to true to enable persistence size: 20Gi # PVC size registry-token-refresher: # Time in minutes after which the token should be refreshed. # Leave it empty to use the default provider time. token_refresh_time: "" off_cluster_registry: hostname: "" organization: "" username: "" password: "" ecr: # Your AWS access key. Leave it empty if you want to use IAM credentials. accesskey: "" # Your AWS secret key. Leave it empty if you want to use IAM credentials. secretkey: "" # Any S3 region region: "us-west-2" registryid: "" hostname: "" gcr: key_json: <base64-encoded JSON data> hostname: "" router: dhparam: "" # Any custom router annotations(https://github.com/deis/router#annotations) # which need to be applied can be specified as key-value pairs under "deployment_annotations" deployment_annotations: #<example-key>: <example-value> # Any custom annotations for k8s services like http://kubernetes.io/docs/user-guide/services/#ssl-support-on-aws # which need to be applied can be specified as key-value pairs under "service_annotations" service_annotations: #<example-key>: <example-value> # Enable to pin router pod hostPort when using vagrant host_port: enabled: false # Service type default to LoadBalancer # service_type: LoadBalancer workflow-manager: versions_api_url: https://versions.deis.com doctor_api_url: https://doctor.deis.com
このvalues.ymlの内容をproductionのための設定に変えていって、helm installとやる予定。
Terraform0.9.0からremote configがdeprecatedになる
remote config
がdeprecatedになる
terraform0.9.0からterraformコマンド実行するとdeprecated warningがでてきます。
💁 3行
remote config
コマンドがなくなってinit
コマンドが導入されるbackend
という概念が導入されterraform.tfstateファイルを保存する設定をtfファイル側に書くようになってlocalのtfstateは更新されなくなる- ざっくりmigrationする際は、tfstateは一応バックアップしといて、tfファイルにbackendの設定書いて
terraform init
すればOK
設定の書き方
https://www.terraform.io/docs/backends/types/index.html ここの左ペインにStandard Backendsに色々なタイプがあるのでそこを見る。
例: S3
terraform { backend "s3" { bucket = "mybucket" key = "path/to/my/key" region = "us-east-1" } }
例: local
terraform { backend "local" { path = "relative/path/to/terraform.tfstate" } }
そもそもなんでbackendというものを導入しようとしたのか、メリット的なものについて詳しく :pencil2:
該当のPR#11286に詳しく書いてある
remote config
をより一般的な考え方にするために、backend
という概念を導入した- 今ってterraform applyってやるタイミングでインフラ担当一人って感じだけど本当はいろんな箇所から複数同時に実行されることだってあるはず、将来はそうなるはず、そんな時のために、stateをlockしてくれる機能も自動的についてくる
- remote configはコマンドラインベースでオプションを渡す形で設定していたのでわかりにくい、それをファイルベースで明示的に書くことでより基本的な設定とした
init
コマンドに統合してmoduleのdownloadとかも一気にやってくれるようになる- 今まではremote configを見に行くコマンドと見に行かないコマンドがあったけど全部共通して
backend
を通してコマンドを実行するようになる - localにキャッシュされてたtfstateファイルにsecret情報が書かれてしまってたがそもそもlocalにキャッシュされてたtfstateファイルはもう更新されなくなるのでgitに含めなくてOK
- なので.gitignoreに
.terraform/
を追加しよう:exclamation: - localのtfstateのserialがremoteより高いとダメみたいなことが起きなくなる
Lineage
というUUID的なものが導入されてこの値が変わると別のinfraとみなされエラーが出るようになる。具体的なユースケースは間違って別環境のものでapplyしようとしたときとかだろうか 😐
terraform0.9.1からplanレベルでsecurity_groupのcidr_blocksのvalidateが入るようになった
0.9.1 changlog :tada:
https://github.com/hashicorp/terraform/blob/master/CHANGELOG.md#091-march-17-2017
provider/aws: Validate CIDR Blocks in SG and SG rule resources (#12765)
planで未然に防げる
つい間違ってcidr_blocksの方にsecurity_groupのidを指定しまったことがあったけどそれが防げるようになる💯
terraform consoleっていうREPLみたいなやつがあるの知らなかった
v0.8から導入された模様。俗に言うREPL。今のtfstateをもとにsyntaxを試すことができる。planやapplyなどを発行することはできないので安全。単にこういう時はterraformではどう書くんだろう??みたいなのを試したいときに便利。
例1: moduleのoutputを呼び出して要素を取得する
> "${module.base_network.private_subnet_001_ids}" [ subnet-xxxxxxxxx, subnet-yyyyyyyyy ] > "${module.base_network.private_subnet_001_ids[0]}" subnet-xxxxxxxxx > "${module.base_network.private_subnet_001_ids[1]}" subnet-yyyyyyyyy
例2: 組み込み関数が何を返すか調べる
> cidrsubnet("172.24.0.0/16", 10, 1) 172.24.0.64/26 > cidrsubnet("172.24.0.0/16", 10, 0) 172.24.0.0/26 > cidrsubnet("172.24.0.0/16", 26, 0) cidrsubnet: insufficient address space to extend prefix of 16 by 26 in: > cidrsubnet("172.24.0.0/16", 10, 4) 172.24.1.0/26 > cidrsubnet("172.24.0.0/16", 10, 5) 172.24.1.64/26 > cidrsubnet("172.24.0.0/16", 10, 6) 172.24.1.128/26 > cidrsubnet("172.24.0.0/16", 10, 8) 172.24.2.0/26
H/A とは
H/Aとかよく出てくるけどうまくググれなかったので。 多分 High Availability(高可用性)の略
自分で立てたdeisにアプリをdeployするまで
quickstartのConfigure DNSとregister an admin user and deploy your first app.をやっただけ。
ロードバランサーの確認
$ kubectl --namespace=deis describe svc deis-router | grep LoadBalancer Type: LoadBalancer LoadBalancer Ingress: 104.198.90.182
これがロードバランサーのIP。
でも、これがいつできたのがわからない :scream:
On Google Container Engine, Deis Workflow will automatically provision and attach a Google Cloud Loadbalancer to the router copmonent.
Deis Workflowは自動的にGCPのロードバランサーを作ってアタッチするっていってるけど、一体これはいつ行われたんだ・・ :thinking:
helm install
したときか?該当のコードをdeisのorganization配下でgcpとかload balancerとかgclbとかいろいろ検索してみたけど、わからず・・
kubernetesのserviceでtype:LoadBalancerとしてるから
そもそも、k8sにserviceというcomponentがあって、serviceは色んなタイプがあるけれどLoadBalancerを選ぶと、k8sがよしなにバックエンドのcloud providerを見てロードバランサーを作ってくれるってことですね。GKEの場合は、それは、Google cloud load balancerを使って実現すると。 なので、多分k8sのコードにそういうことが書いてあるはず(まだ見てないけど)。
deis/workflowがやるのはpodを作成するってことだけだと思いこんでしまっていて、podはcontainerを包含した単位なのに、なぜ上位のGCPの操作の仕方まで知っているんだろう?というところがつまづいてしまった原因でした:scream: そもそもk8sは何ができるのかを分かったようで分かってなかったってことですね。
ロードバランサーのIPをもとにnip.ioというサービスを利用したときのhostを確認する
$ host 104.198.90.182.nip.io 104.198.90.182.nip.io has address 104.198.90.182
これで deis.<GCPのロードバランサーのIPアドレス>.nip.io で手元でアクセスできるようになる。
$ curl http://deis.104.198.90.182.nip.io/v2/ && echo {"detail":"Authentication credentials were not provided."}
手元のdeisコマンドでユーザー登録する
$ deis register http://deis.104.198.90.182.nip.io username: admin password: password (confirm): email: xx@bb Registered admin Logged in as admin Configuration file written to /Users/mpon/.deis/client.json
既存のやつが上書きされちゃうっぽい。ってことは複数のdeis workflowに対して何かやりたいときは、deis registerをやり直さないといけないのか??ちょっとめんどいかもしれない :rolling_eyes:
$ deis register --help Registers a new user with a Deis controller. Usage: deis auth:register <controller> [options] Arguments: <controller> fully-qualified controller URI, e.g. 'http://deis.local3.deisapp.com/' Options: --username=<username> provide a username for the new account. --password=<password> provide a password for the new account. --email=<email> provide an email address. --login=true logs into the new account after registering. --ssl-verify=true enables/disables SSL certificate verification for API requests
deis registerのhelpを見てみても複数に切り替える的なやつはなさげだ。まぁいっか :dancer:
アプリケーションの器をdeis上に作る
$ deis create --no-remote Creating Application... done, created jangly-sailfish If you want to add a git remote for this app later, use `deis git:remote -a jangly-sailfish`
作ったとこにサンプルアプリケーションをpullする
$ deis pull deis/example-go -a jangly-sailfish Creating build... done
アクセスする
$ curl http://jangly-sailfish.104.198.90.182.nip.io Powered by Deis
コンフィグを上書きする
この間、勝手にローリングデプロイが行われるのでdown timeは0 💯
$ deis config:set POWERED_BY="Docker Images + Kubernetes" -a jangly-sailfish Creating config... done === jangly-sailfish Config POWERED_BY Docker Images + Kubernetes $ curl http://jangly-sailfish.104.198.90.182.nip.io Powered by Docker Images + Kubernetes
スケーリング
コマンドでさくっとできる。
$ deis scale cmd=2 -a jangly-sailfish Scaling processes... but first, coffee! done in 10s === jangly-sailfish Processes --- cmd: jangly-sailfish-cmd-2108971595-1vxqg up (v3) jangly-sailfish-cmd-2108971595-b7xhf up (v3)