Got Some \W+ech?

Could be Japanese. Could be English. Android, セキュリティ, 機械学習などをメインに、たまにポエムったり雑感記載したりします。

Github + CircleCI + DockerでGCEを動かす - デプロイ編

  • 今日はデプロイするところまで.
  • 基本的にはKubernetesのチュートリアルを参考にしつつ作った.
  • 説明はしないスタイルで。

Kubernetes関連用語

  • 説明はしないと言ったな。アレは嘘だ。
  • Kubernetesはコンテナ化されたアプリをClusterにデプロイしたり、配布をスケジュール化したりする。今風に言うとオーケストレーションツール?
  • Cluster -> 複数のリソース群が1つのユニットとして接続されたもの。2種類のリソースから構成される 
    • Master: クラスター内部を管理する(coordinates). 監視したり、スケールしたり、更新したり
    • Nodes: アプリを走らせるVM。MasterとはKubernetes APIで通信する。Physical Host
  • Pod: 正直捉えづらかった。現在進行系で捉えきれてない。デプロイのタイミングで作られるコンテナの集合体 + 共通リソースの集合体。Logical Host. PodはNodeの上で走る。
  • Services: Podsの集合。Podsの外部ネットワークへ公開、ロードバランス、サービスディスカバリを出来るようにする
  • Labels: そのまんま。PodやServiceにラベリングできる。環境、バージョン、サービスタイプ(front, backend,db)などの情報を負荷できる

Gophishのデプロイ

> kubectl run gophish-deploy --image=asia.gcr.io/${PROJCET_ID}/gophish:latest --port=3333 # gophishアプリをClusterにデプロイ(ポート3333ではしらせる)。デプロイノードは1つ
> export POD_NAME=$(kubectl get pods -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}') # Podの名前を取得
> kubectl expose deployment/gophish-deploy --type="NodePort" --port 3333 # 今回は1インスタンスしか立てない
> export NODE_PORT=$(kubectl get services/gophish-deploy -
ate='{{(index .spec.ports 0).nodePort}}') # Portを取得

さて、ここまでやれば外部公開されているはずなのだが、curl "$NODE_IP":"$NODE_PORT"してもtime outする。nmapしたところfilterとの結果が帰ってきたのでFirewall系とあたりをつける。

Firewallの設定

なのでコンピュートサービス > ネットワーキング > ファイアウォールルールで見ると、任意のIPから対象のノード:$NODE_PORTへのアクセス許可設定がされていなかったので、以下で設定

> gcloud compute --project "gophish-150317" firewall-rules create "external2gophish" --allow tcp:NODE_PORT --network "default" --source-ranges "0.0.0.0/0" --target-tags "gke-gophish-cluster-bc6565eb-node"

これで、curl "$NODE_IP":"$NODE_PORT"したら無事アクセスできた。でも、毎回NODE_PORT指定するのダルいなぁ...と思ったので、kubectl exposeでオプションがないか探したが見つからなかった(targetPortオプションは使ってみたが駄目だった)。ただ、yamlファイルでの方法なら指定が可能らしいのでyamlファイルを作成。

http://kubernetes.io/docs/user-guide/services/#type-nodeport

apiVersion: v1
kind: Service
metadata:
  labels:
    name: gophish
  name: gophish
spec:
  ports:
  - port: 3333
    #targetPort: 3333
    protocol: TCP
    nodePort: 30333
  selector:
    name: gophish
  type: NodePort

一旦、過去のサービスを消して再設定. 又、今回は指定したポートを指定してFirewallに穴を開ける。無事通る

% kubectl delete svc/gophish
% kubectl create -f gophish-service.yaml
% gcloud compute --project "gophish-150317" firewall-rules create "external2gophish" --allow tcp:30333 --network "default" --source-ranges "0.0.0.0/0" --target-tags "gke-gophish-cluster-bc6565eb-node"
% curl 104.199.208.112:30333                                                                                  
<a href="/login">Found</a>.

ブラウザ側からも大丈夫 f:id:kengoscal:20161127180234p:plain

NodePortじゃなくてLoadBalancingも試す

yamlを書き換えるだけ

apiVersion: v1
kind: Service
metadata:
  labels:
    name: gophish
  name: gophish
spec:
  ports:
  - port: 3333
    targetPort: 3333 <- ★
    protocol: TCP
  selector:
    name: gophish
  type: LoadBalancer <- ★

ロードバランサーが作成される過程でFirewallの穴あけもやってくれるらしいので、ロードバランサーに公開IPが付与され次第、アクセスできる。NodePortは手動でやらなきゃいけないからメンドクサイ。 f:id:kengoscal:20161127180846p:plain

[Kengo@Mac] ~/workspace/docker_gophish
% kubectl get svc                                                                                             
NAME         CLUSTER-IP     EXTERNAL-IP       PORT(S)    AGE
gophish      10.3.249.184   104.155.214.128   3333/TCP   3m
kubernetes   10.3.240.1     <none>            443/TCP    4d
[Kengo@Mac] ~/workspace/docker_gophish
% curl 104.155.214.128:3333                                                                                   
<a href="/login">Found</a>.

スケールアップ

折角ロードバランサー形態にしたので、スケールアップしてみる。おk。

# Before
% kubectl get deploy
NAME                 DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
gophish-deployment   1         1         1            1           1h

% kubectl scale deployment gophish-deployment --replicas=2

# After
NAME                 DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
gophish-deployment   2         2         2            2           1h

余談 - お金の話

24日の記事を含めて、このコンピュートエンジンを立ち上げたのが約1週間前。それから立ち上げっぱなしで、利用料金はトータルで1102円。為替とかはもろもろ無視すると、ロードバランサー・ストレージもあるものの、90%がCompute Engineにかかった費用と考えられる。内訳は以下の通り。

f:id:kengoscal:20161127183644p:plain

でも、あれれ?GCEって5node/clusterまで無料じゃなかったっけ?って思ったら、それはCluster管理の価格だった。ノード料金はそのままかかる。個人だと結構いたいかなあ。こまめに管理しないと。

Google Container Engine Pricing and Quotas  |  Container Engine Documentation  |  Google Cloud Platform

下記で計算もできる。 cloud.google.comf:id:kengoscal:20161127184716p:plain

次は

  • CircleCIでデプロイしようと思う。一旦サービスはおとそう。

デバッグ

> kubectl cluster-info #
> kubectl get nodes # Cluster内でアプリをホストできるノード
> kubectl get deployment
> kubectl proxy & # ローカルでいながらClusterのAPIに接続できる -> ブラウザからhttp://localhost:8001/uiで管理コンソールを開ける。便利。
> kubectl get pods # 存在しているpodsをリスト
> export POD_NAME=$(kubectl get pods -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}') # Podの名前を取得
> curl http://localhost:8001/api/v1/proxy/namespaces/default/pods/$POD_NAME # 接続テスト
> kubectl describe pods # podsの情報(構成情報・イベント)を取得
> kubectl logs ${POD_NAME} # 対象Podのログを取得
> % kubectl exec -it $POD_NAME COMMAND #対象Pod上でCommandを実行。docker execみたいなもん。
> kubectl describe svc/gophish-deploy # サービスの情報

参考資料

Kubernetes - kubectl Overview * 安定の本家ドキュメント GKEで半年運用してみた * お金を調べてるうちにみつけた...最初からこれをみつけていたかった...