読者です 読者をやめる 読者になる 読者になる

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にこれが追加される。

f:id:masato47744:20170422024306p:plain

そうすると、もともとあった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

これをすると

  • GCP上に80,443のHTTPを通すFirewallが作られ
  • TCP:80,443のL4ロードバランサーが作られ
  • treafikのimageがdeployされてそのL4 LBと結びつく

あとは、このとき作成された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もあがってた。

なので、現状は、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を作るときはgcenginxのclassが標準で用意されてたけど、このgceっていうやつはGLBCのことで、ただ、GLBCGKEだと最初からaddonされるから作らなくてよいということだった。

自分で作りたい場合は、cluster作成時に、コマンドとかAPI経由でのみ、外せる。GUIコンソールからだと無理だった。

GLBCとは

なんとなく、GCPにおいてあるロードバランサーのことだろって思ってたけど違う

これはkubernetes側が勝手に名前をつけたやつで、GCPのリソースを組み合わせてL7のロードバランサー相当のものを作る命令のあつまりみたいなもの。まさにcontroller。あと、ルーティングしたときにどこにもあてはまらないリクエストがきたときにデフォルトの404ページを出してくれるだけのバックエンドのセット。

Ingressを作ると、GLBCがたたかれて、GLBCがGCPAPIをたたいて、L7のロードバランサーを実現するために、GCPでL7ロードバランサーをするための設定をしてくれる。

f:id:masato47744:20170422023108p:plain

で、そのGLBCはどこにいるかっていうとGKEの場合は、cluster作成時にマスターノードに作られていたって話でした。kube-systemっていうnamespaceが基本的にcluster作成時にできるものなんだけど、ここにGLBC相当のものがいないのではまった。ただ、さっき言った404出してくれるl7-default-backendはNodeの方にいるのでこの管理画面に表示されてるのが分かる。

f:id:masato47744:20170422023135p:plain

Deis Workflow v2.13.0でKubernetesのIngressがサポートされた件

Deisがverupした

本日、Deis Workflowがverupしたんですが、Changelogを見てるとIngressというものがなんか導入されてDeis/routerなくてもいけるみたいなことが。

スクリーンショット 2017-04-06 17.55.34.png

そもそも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とは

github.com

で、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のネットワークの違いを理解してみよう

背景

  • AWSVPC作ったりしたことあるけど、GCPやったことないって人は色々違いに戸惑う
  • アカウントの関係性、ネットワークの概念の違いなどを理解したのでまとめた

AWSGCPのアカウントの考え方の違い

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)の範囲でのみ作成できる。

f:id:masato47744:20170422015409j:plain

この上の図は、AWSでインフラ作るときに、ごく一般的な構成を図示している。各regionごとに、VPCを作り物理的にはavailability-zoneで分かれていてその中にsubnetを作っていくみたいなやつ。 subnetをpublic subnetprivate 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アドレスからの特定のプロトコルを受け付けるというものを作成して、それをインスタンスに付与していく。

f:id:masato47744:20170422015425p:plain

上の図でいえば、例として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を持っている。ここがポイント。

この辺を図で説明してみる。

f:id:masato47744:20170422015716j:plain

この図はGCPにおけるネットワーク構成。AWSVPC的なネットワーク構成とだいぶ異なっている。なおこの図では、プロジェクトを作ると必ず作成されるデフォルトネットワークと呼ばれるものを示している。

デフォルトネットワークだと、必ずリージョンごとにサブネットワークが一つ作成される。GCPだと、AWSVPCのように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という機能がGCPAWSで随分と違う部分。 GCPの場合は、各インスタンスタグと呼ばれるものを好きなだけ貼ることができる。このタグをベースにネットワークの制限をつけていく。

ここで再びさっきの上の図を詳しく見ていく。

f:id:masato47744:20170422020010p:plain

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にはなかった概念だと思う。

まとめ

AWSGCPの違いを人に説明しようと思ってみたけど説明しようとすると自分でもよくわかってない部分にぶちあたるという感じになった。

GCPも調べてみると色々利点があり、(安い、全世界またがったネットワークが強い、googleアカウントとの統合がうまい、LBの温め不要)ちょっと好きになってきた

両者の違いをかなり個人的な感想だけどこんなイメージ。

  • AWSさんはベーシックなネットワーク構成をクラウド上に再現して顧客のためにどんどん使いやすいようにがんばってくれる優等生
  • GCPVPC作って、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を利用するgcePersistentDiskAWSのEBSを利用するawsElasticBlockStore、gitのrepositoryを利用するgitRepoなどがある。

例えば、volume typeでGCPgcePersistentDiskを利用したければ、先に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です。これは最近できた?やつっぽくて、StorageClassGCPとか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を利用)

やること

mpon.hatenablog.com

前回はCloud SQLを使ったが、Cloud SQLはデフォルトネットワーク外にあるので、Cloud SQL Proxyをたてて通信するか、外部IPを許可するしかなかった。Deisの場合だと、proxyたてるパターンを使えず、外部IPを許可する方法にしたけど、これだとNodeのIPが変わったり増えたときに対応できない。 なので、素直にGCE上にpostgresqlをたてることにした。

Cloud Launcher

postgreSQLをinstallとかめんどくさいなーって思ってたら、Cloud Launcherなるものを発見した。ぽちぽちっとやるだけで、いい感じにインストールまでしてくれる。本当の本当の本番ならこれはよくないかもしれないけど、今回はこれを使うことにした。

こんな感じで選んで、

f:id:masato47744:20170422013707p:plain

できた。

f:id:masato47744:20170422013800p:plain

単なるVMインスタンスとして出来上がっているので、まぁあとから修正は好きなように加えられるだろう。

f:id:masato47744:20170422013848p:plain

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のネットワークは、AWSVPC的な考えとは結構違うのでそこに慣れる必要がある。

追記:これで解決

mpon.hatenablog.com