2016年に買って良かったもの

去年iPhone7に買い換えたことをキッカケにBluetoothのヘッドホンを使い始めたのだけど、今となっては生活必需品になってしまっている。

数年前にジムで音楽聴きたいからと安いBluetoothのヘッドホンを買ったのだけど、音声途切れ気味だったり、ちょっと使っただけですぐ壊れてしまっていてあまり良い印象なかったのだけど、Bose QuietControl 30 wireless headphones : ワイヤレスノイズキャンセリングイヤホン ネックバンド式/Bluetooth対応/コントローラブル・ノイズキャンセレーション機能搭載/リモコン・マイク付き ブラック QuietControl30 WLSS BLK【国内正規品】を使ってもうそういった不満要素ふっとんだ。

簡単にペアリングできる。ネックバンド最高。無くさない。ノイズキャンセリング十分。装着感も良い。こんなに安定しているイヤホンのはなかなかない。

だけどジムで試してみたところ、走っているときにネックバンドが鎖骨に当たって痛かったので、ジム用のものを買ってみた。

ペアリング問題なし。値段のわりに使いやすい。でもネックバンドない。適当に置いておくと無くしそう。

なので、Bluetoothヘッドホンはネックバンドがあったほうが良いという結論。

Webマーケティングに求められるスキル

Webディレクターに求められるスキル - ただふれたものについて書くブログで、Webディレクターに求められるスキルをまとめたけれど、今度はWebマーケティングについて。

Webディレクターも幅が広かったけれど、今回はそれよりもさらに幅が広め。

まずWebマーケティングとは何かを書く前に、言葉の定義や現在のウェブマーケティングの立ち位置についてざっと書く。

ざっくりWebマーケティングとは何か?

デザイナーのためのWeb学習帳(8):5分で絶対に分かる、「Webマーケティング」とは (2/6) - @IT にはこんな風に書かれている。

「Webマーケター」とは、マーケティングの最適化や費用対効果を算出するだけではなく、それぞれのマーケティングの方法にあったWebページの構成やランディングページの構成ができ、その結果がどのようになったのかを分析できる人です。

企業によってWebマーケティングの適応範囲は違う

企業によって定義が違う。というのも複数の役割が組み合わさってできたものになる。

  • 営業
  • 広告
  • 分析
  • 戦略立案
  • 企画
  • 業務管理

またその企業の立ち位置によっても違う。なのでWebマーケティングと言っても人によって考え方が違うので、明確な定義のないまま話込んでしまうと認識の相違が起こる可能性がある。

いろいろな肩書き

マーケティングの範囲が広いため、マーケティング・Webマーケティングにまつわるものには、いろいろな肩書きがある。

  • Webマーケター
  • アナリスト
  • ストラテジックプランナー
  • リサーチャー

どれが具体的にどう違うかは正直よく自分理解していない。ただWebマーケティングマーケティング混ぜるとよくわからなくなりそうな気がしている。

Webマーケティングの流れ

これも デザイナーのためのWeb学習帳(8):5分で絶対に分かる、「Webマーケティング」とは (4/6) - @IT から抜粋。

  1. プレアクセス Webサイトにどのような広告から誘導し、アクセスするか
  2. オンアクセス Webサイトにどのように、また、どのページにアクセスしてもらうか
  3. ポストアクセス Webサイトに訪れた後、どのようにユーザーと関係を持つか

それぞれ、サイト流入数、回遊度、継続率などを数字で追ってその改善を追っていく。

プレアクセスについて

流入、集客にまつわるところ。リスティング広告SEO。最近だとSSO、ASO(App Store Optimization)も入るかもしれない。どこから流入してきたかを計測できる状態にしておく必要がある。

ざっくりとはリファラーで確認できるが、細かく制御したい場合はURLに特定のkeyと値を入れて、流入後にサイトのほうでそのパラメータを送ってもらうような処理を入れる。Google Analyticsで言うならば、utmパラメータ(カスタムキャンペーン)。

計測できる情報からKPIを決めてその最大化を行う。流入数だけではなく、ランディングページへの流入後のアクションにして、適切な流入経路を確保したりする。

オンアクセスについて

最初にユーザーが閲覧するであろうページから顧客の次の行動をを促すようにする。 新築マンションのページならば、資料請求などを数字として追っていく。その目標数字を改善することを、LPO(Landing page optimization)と呼ばれている。

今回の記事では、単純なランディングページだけではなく、Webサービスにまで範囲を広げる。

昔のウェブサービス

昔は、PCのブラウザからのアクセスが主だった。かつアクセスはページ単位で動くことになる。なので、毎回ページを移動するたびにサーバーに問い合わせしてhtmlを取得していた。

f:id:taizo_onexone:20161231234953p:plain

そのため、URLの設計を少し意識するだけで、あまり実装側があまり意識せずにアクセスログから確認することができる

最近のウェブサービス

今はひとつのサービスに対して、クライアントが複数存在する。特にAPIサーバーとクライアントが完全に分離されているため、画面遷移がアプリケーションの仕様に依存する。また、PCサイトでさえも、Single Page Application(SPA)の実装の浸透により、ネイティブアプリケーションに近くなる。

f:id:taizo_onexone:20161231235032p:plain

データはhtmlではなく、JSONであったり、別のフォーマットであったりする。そして画面遷移に依存しない作り方をすることができる。サーバーのログのみでは、ユーザーがどのように画面遷移をしていったか分からない可能性が高い。

そのため意図的に実装側がイベントログをログサーバーに送信するように実装する必要がある。どのようなイベントログを送れば、適切な分析ができるかを設計する必要がある。

ポストアクセスについて

Webサイトに訪れた後のユーザーとどのような関係を持つか。 メールの送信や、アプリのプッシュ通知など。

統計学機械学習

最近のWebマーケティングには統計学機械学習と連携する傾向がある。特にサイトに来訪してからのログから、ユーザーの動向を分析し、どういった傾向があり、そういう人たちに何か自動でレコメンドを行う仕組みを用意したりする。

まとめ: Webマーケターに求められるスキル

以上を踏まえた上で求められるスキル。

  • サイト流入・サイト内ゴール・サイト離脱後のアクションの設計を数字に落とし込み、その状態を可視化できるスキル
  • ユーザーの行動ログから、データの抽出、レポート作成、提案のできるスキル

流入についての最適化だけならば、専門的な知識の範囲は限られていた。

だけど、サイト内での行動ログを細かく取ることによって、統計やら機械学習に活用をしての改善を色々と提案できるようになってきた。なので自分らでCGMサービスであったり、ECなりを持っている場所では、今までのWebマーケターが行っていたこと以上のことが求められるようになってきた。

関係各所の求められるスキルが上がったことに引きづられて、求められるスキルが上がっているというのが自分の印象。

スーパーマリオランやってみた

supermariorun.com

スーパーマリオラン週末から結構やっている。

f:id:taizo_onexone:20161218184141p:plain

家庭用ゲーム機のゲームをそのままスマホに持って来た。

家庭用ゲーム機のゲームバランス

普通にワールドをクリアするのは難しくない。アクションゲームに慣れている人ならば、2時間あれば全コースクリアできる。だが、クリア以外にカラーコインを集めるというやりこみが用意されている。カラーコインは、各コースにそれぞれ、ピンクコイン、バープルコイン、ブラックコインがあり、ブラックコイン集めは難しめ。

このコイン集めが家庭用ゲーム機のゲームバランスをそのまま持って来ている。やり込めばプレイヤーのステータス数字が上がっていずれクリア出来る類ではない。あくまでもプレイヤーのゲームの上達にかかっている。

レベルデザインも他のマリオシリーズと変わらず、いろいろ考え抜かれている。ミスする可能性が上がるがコインがいっぱい取れる進め方などが随所にあるし、コインの位置でどう進むべきかがなんとなく示唆をして難易度をちょうどよく調整しているようにみえる。

1,200円が高いかどうか

1,200円くらいの価値があるかというと、昔ながらのゲームをやり込む人ならば価値があると思う。キノピオラッシュも面白い。だけど、今までのソーシャルゲームのようにパラメータを上げたらクリア出来るゲームではない。ソーシャルゲームならもったいないなどの理由も含めて、平気で1年くらいプレイできるけれど、それに比べれば、飽きは早いと思う。楽しかったねーと1,200円払えるかどうか。

個人的には、このゲーム売り上げ的に成功して、今の課金を前提にしたゲームとは違ったゲームが増えることを願ってる。

レビュー時の議論を避けよう

プルリクエストベースでレビューをしているとたまに、コメントのやり合いが起こることがある。

 

特に設計ベースでレビュアーの考えと修正が違った場合に起きやすい。

 

ただ、レビューの時に議論が起きる時点で開発の仕組みに問題があると思ったほうがいい。議論はレビューの前に終わらせてコードレビューはコード自体の品質に集中できるようにしたほうが無駄な差し戻しがなくなるからだ。

 

よく行う対策にはこんなのがある。

 

  • 設計レビューを実装開始前に行う
  • プルリクエストの大きさを小さくする
  • Work In Progress(WIP) のプルリクエストを初期に出してどのような修正をするかを予め見ておいてもらう
  • プロダクトのissueを適時出しておいて後でその内容をチームで議論する時間を設ける

 

よくよく考えれば、まずissueでアイデアをぶつけてから修正をするみたいなフローもよくあるわけで、コードを直す前にレビュアーと認識はきちんと合わせておいたほうが結果的にスムーズにいくという些細だけど大事って話でした。

 

serverless を試す

API Gateway + Lambda を使ってHTTP APIを作るには、何を使うのが一番良いのだろうと まずは Apex – Serverless Infrastructure を試してみたものの、API Gatewayとlambdaを繋げるところまでがサポートされていなく そこをterraformでやるのは厳しいかなと思って別なものを探していたら、Serverless というそのままの名前のツールがちょうど良さそうだった。

Serverless

serverless.com

AWS Lambda を使ったAPI サーバーの設定などを管理できるビルドツール。

install

npm install -g serverless

Create credentials

まずパッケージで必要なcredentialsを設定する。 これをすると ~/.aws/credntialにファイルを作成してくれる

$ serverless config credentials -p aws -k <aws-key> -s <aws-secret>

テンプレートの作成

$ serverless create -t aws-nodejs

いくつかテンプレートが用意されているので、それを使うと、 handler.jsserverless.yml が作成される。

handler.js

module.exports.hello = (event, context, callback) => {
  const response = {
    statusCode: 200,
    body: JSON.stringify({
      message: 'Go Serverless v1.0! Your function executed successfully!',
      input: event,
    }),
  };
  callback(null, response);
  // Use this code if you don't use the http event with the LAMBDA-PROXY integration
  // callback(null, { message: 'Go Serverless v1.0! Your function executed successfully!', event });
};

serverless.yml

service: aws-nodejs # NOTE: update this with your service name
provider:
  name: aws
  runtime: nodejs4.3
functions:
  hello:
    handler: handler.hello

serverlessにawsの設定などを記載していくことになる。

とりあえずエンドポイントを実行できるようにしてみる

functionsにイベントを記載する

functions:
  hello:
    handler: handler.hello
    events:
      - http:
          path: /
          method: get

http イベントを設定すると、API Gateway と紐づけてくれる。 イベントは他にもいくつかある Serverless - AWS Lambda - Events

あとはデプロイをするだけ。

$ serverless deploy -r ap-northeast-1 -s dev

deploy

devにデプロイしてみる

$ serverless deploy -r ap-northeast-1 -s dev

Serverless: Creating Stack...
Serverless: Checking Stack create progress...
.....
Serverless: Stack create finished...
Serverless: Packaging service...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading service .zip file to S3 (583 B)...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
............................
Serverless: Stack update finished...
Service Information
service: aws-nodejs
stage: dev
region: ap-northeast-1
api keys:
  None
endpoints:
  GET - https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/
functions:
  aws-nodejs-dev-hello: arn:aws:lambda:ap-northeast-1:59XXXXXXXXXX:function:aws-nodejs-dev-hell

色々なものを一気に作ってくれる

role も作ってくれる。 arn:aws:iam::59XXXXXXXXXX:role/aws-nodejs-dev-ap-northeast-1-lambdaRole

アクセスできるようになる

% curl https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/
{"message":"Go Serverless v1.0! Your function executed successfully!","input":{"resource":"/","path":"/","httpMethod":"GET","headers":{"Accept":"*/*","CloudFront-Forwarded-Proto":"https","CloudFront-Is-Desktop-Viewer":"true","CloudFront-Is-Mobile-Viewer":"false","CloudFront-Is-SmartTV-Viewer":"false","CloudFront-Is-Tablet-Viewer":"false","CloudFront-Viewer-Country":"JP","Host":"xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com","User-Agent":"curl/7.49.1","Via":"1.1 25e2bd4c76e5ce50a0e42ea7d68cb8be.cloudfront.net (CloudFront)","X-Amz-Cf-Id":"vNC5HOdFJ9wDxnmXVq9MwGrMwsFGtFHwKCohNx3PGyWbw6mJiXeT3Q==","X-Forwarded-For":"xxx.xxx.xx.xx, xx.xxx.xxx.xx","X-Forwarded-Port":"443","X-Forwarded-Proto":"https"},"queryStringParameters":null,"pathParameters":null,"stageVariables":null,"requestContext":{"accountId":"592382460000","resourceId":"7wt5tp3333","stage":"dev","requestId":"e2bef286-bf5c-11e6-8ed0-8b69baa26de7","identity":{"cognitoIdentityPoolId":null,"accountId":null,"cognitoIdentityId":null,"caller":null,"apiKey":null,"sourceIp":"xxx.xxx.xx.xx","accessKey":null,"cognitoAuthenticationType":null,"cognitoAuthenticationProvider":null,"userArn":null,"userAgent":"curl/7.49.1","user":null},"resourcePath":"/","httpMethod":"GET","apiId":"qeg4d8alu6"},"body":null,"isBase64Encoded":false}}

確認

--region は必須

$ serverless deploy list -r ap-northeast-1
Serverless: Listing deployments:
Serverless: -------------
Serverless: Timestamp: 1481428344900
Serverless: Datetime: 2016-12-11T03:52:24.900Z
Serverless: Files:
Serverless: - aws-nodejs.zip
Serverless: - compiled-cloudformation-template.json

削除

remove でできる。

$ serverless remove -r ap-northeast-1
Serverless: Getting all objects in S3 bucket...
Serverless: Removing objects in S3 bucket...
Serverless: Removing Stack...
Serverless: Checking Stack removal progress...
.................
Serverless: Stack removal finished.

roleも削除してくれる

すごい楽

アプリケーションを作る立場からするとすごい楽。だけど、構成管理としては 使っているサービスは terraform に寄せたいけれど、現実的に厳しそう(そもそもterraformでlambdaでデプロイするのに、毎回アプリケーションをまとめたファイルを用意しなきゃいけない)で、なんかもやもやしてる。

広告を非表示にする

React + Flux アプリケーションを作るときに知っておきたかった2つのこと

数ヶ月くらいReact + Flux アプリケーションを3〜4つくらい業務で触ってみたら、知っておけば良かったという考え方がいくつかあった。

1. コンポーネントの分け方の考え方

Atomic Designと Presentational and Container Components

各要素をコンポーネントに分割するための考え方のひとつに Atomic Design がある。

f:id:taizo_onexone:20161123230719p:plain

パーツをコンポーネント単位で定義していくもの。

Reactのコンポーネントの分ける際にとても役に立つ考え方なので、実装側はこれを基準にデザイナーに考えてもらえるとフロントの実装側はとても助かる。

ただ、デザイナーがこのコンポーネント単位でデザインを起こすのにはそれなりに難易度が高い。

特に全体の設計をしてから、細部に落とし込むやり方に慣れていると大変らしい。

コンポーネント志向の場合、スタイルガイドのようなもので粒度の細かいものをひとつずつ実装してからそれをレイアウトしていく考え方になる。作業フローが逆になる。

一方でデータ設計の目線でみると Presentational and Container Components – Dan Abramov – Medium で書かれている Presentational と Container コンポーネントの分け方の考え方がある。

これは少しでも大きめなReactアプリケーションを作り始めると共感できるもの。stateの管理やらデザインのレイアウトやらをどのコンポーネントが責任を持つかをハッキリさせておくと複数人で開発する場合は良い気がした。特にレビューのコストが下がると思う。

Material-UIを Presentational Component とみなして、試しに実装してみるとわかりやすいと思う。

2. propsのバケツリレーをどう対応するか

Reactアプリケーションを作っていると、props のバケツリレーはどうしておくかも可能ならば事前に決めておきたい。せめて後で分割するときのことに思いを馳せておきたい。

props.children を使いこなす

単純にDOMをツリー上に記載していくと、コンポーネントの汎用性が良くならない。なので、外から内側のDOMを直接代入をしてコンポーネントの分離をしやすくしたりできる。

import React, { Component } from 'react';
import ReactDOM from 'react-dom';

const Item = (props) => {
  return (
    <p>{props.name}</p>
  );
}

const List = (props) => {
  return (
    <div>
      {props.children}
    </div>
  );
}

const names = ["a", "b", "c"];
const App = () => {
  const items = names.map((n, i) => <Item name={n} key={i} />);
  return (
    <List>
      {items}
    </List>
  )
}

ReactDOM.render(
  <App />,
  document.getElementById('root')
);

ポイントはListコンポーネントでItemコンポーネントを記載せずに、props.children をそのまま表示するように書くこと。

const List = (props) => {
  return (
    <div>
      <Item name={props.name} />
    </div>
  );
}

モーダルUIなどで外側だけを作って中の要素を丸々propsで渡すなど、外側のレイヤーだけかっちりしているけれど中は汎用的にしたいときはこういったモジュールを実装する。

storeの更新の監視を子で行う

バケツリレーを避けるために、子でstoreデータを監視するのもあり。 ただ、コンポーネントを削除した際にそのstoreデータをきちんと削除するか残し続けるかという選択肢が出てくる。

まとめ

Reactはわかりやすいけれど、Fluxやコンポーネントデザインにまで話が及ぶと明確な正解がないので、ひとつひとつやり方を落とし込んでいくコストが結構かかるのは覚悟必要ってのが最近触った感想です。

参考

qiita.com

Kubernetes こと始め (2) - Service

taizo.hatenablog.jp

続きです。

事前準備

ここからDockerイメージを2つ用意する。

gcr.io/<project-id>/test-app1GET /test-1 OK

gcr.io/<project-id>/test-app2GET /test-2 OK

が返ってくるとする。

それを使ってPodをふたつ立てておく。

dev-pod1.yml

apiVersion: v1
kind: Pod
metadata:
  name: test-app1
  labels:
    run: test
spec:
  containers:
  - name: test-app1
    image: gcr.io/<project-id>/test-app1:latest
    ports:
    - containerPort: 80

dev-pod2.yml

apiVersion: v1
kind: Pod
metadata:
  name: test-app2
  labels:
    run: test
spec:
  containers:
  - name: test-app1
    image: gcr.io/<project-id>/test-app2:latest
    ports:
    - containerPort: 80

それぞれPodを作成しておく。

$ kubectl create -f dev-pod1.yml
$ kubectl create -f dev-pod2.yml

(ここから先 kubectl create の記述は省きます )

Serviceとネットワーク

Docker で必要となるのは

  • Docker内のコンテナ間のやりとり
  • 外部とのやりとり

これらを設定していくのにServiceというのを用意していく。

Service

http://kubernetes.io/docs/user-guide/services/

minion 上で動作するNetwork Proxy の設定単位。

いくつかのTypeがあり、それらを組み合わせて構成していく。

NodePort

内部ネットワークの設定時に使う。

selector でどのPodに紐づけるかを決める。

dev-np.yml

apiVersion: v1
kind: Service
metadata:
  name: dev-np
spec:
  selector:
    run: test
  type: NodePort
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
      nodePort: 31707
      name: http

selectorで対象となるPodが含まれるようにしておく。 Podsには run=test が設定されているので、それを指定。

ちなみに、Serviceを作成するとfirewall についてのWarningが出る。

$ kubectl create -f  dev-np.yml
You have exposed your service on an external port on all nodes in your
cluster.  If you want to expose this service to the external internet, you may
need to set up firewall rules for the service port(s) (tcp:31707) to serve traffic.

See http://releases.k8s.io/release-1.3/docs/user-guide/services-firewalls.md for more details.
service "dev-np" created

直接自分のPCから動作を確認するには、GCPのfirewall を設定すれば、nodePort経由でアクセスできるようになる。

$ gcloud compute firewall-rules create my-rule --allow=tcp:31707

と、firewallに新しいルールを追加。 あとは各nodeの外部IPを確認して、そこにアクセスをして確認ができる。

$ kubectl get nodes -o json | jq ".items[]|{name: .metadata.name, externalIP: .status.addresses[1].address}"
{
  "name": "gke-kube-test-cluster-default-pool-771fd355-34h9",
  "externalIP": "104.199.214.47"
}
{
  "name": "gke-kube-test-cluster-default-pool-771fd355-6ejb",
  "externalIP": "104.199.206.123"
}
{
  "name": "gke-kube-test-cluster-default-pool-771fd355-dleq",
  "externalIP": "104.199.156.133"
}
$ curl http://104.199.156.133:31707
test-1 OK

LoadBalancer

わざわざfirewallの設定を入れたように、通常は外からServiceへのアクセスはできない。

    internet
        |
  ------------
  [ Services ]

NodePortを使った場合、firewallの設定をいじったが、LoadBalancerやIngressを使えば良きようにやってくれる。

    internet
        |
   [ Ingress, LoadBalancer  ]
   --|-----|--
   [ Services ]

外部からのアクセスを負荷分散させたい場合は、そのままの名前のLoadBalancerというタイプがある。

dev-lb.yml

apiVersion: v1
kind: Service
metadata:
  name: dev-lb
spec:
  selector:
    run: test
  type: LoadBalancer
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

これで80ポートにアクセスがあった場合に、label が run=test と指定されているPodの80にアクセスできるようになる。 podsを取得したときに --show-labels で確認できる。

$ kubectl get pods --show-labels
NAME        READY     STATUS    RESTARTS   AGE       LABELS
test-app1   1/1       Running   0          54s       run=test
test-app2   1/1       Running   0          50s       run=test
$ kubectl get svc dev-svc
NAME         CLUSTER-IP     EXTERNAL-IP      PORT(S)   AGE
dev-lb       10.3.251.63   104.199.223.53   80/TCP    3m

$ kubectl describe svc dev-lb
Name:           dev-lb
Namespace:      default
Labels:         <none>
Selector:       run=test
Type:           LoadBalancer
IP:         10.3.251.63
LoadBalancer Ingress:   104.199.223.53
Port:           <unset>   80/TCP
NodePort:       <unset>   32134/TCP
Endpoints:      10.0.0.5:80,10.0.2.5:80
Session Affinity:   None
Events:
  FirstSeen LastSeen    Count   From            SubobjectPath   Type        Reason          Message
  --------- --------    -----   ----            -------------   --------    ------          -------
  4m        4m      1   {service-controller }           Normal      CreatingLoadBalancer    Creating load balancer
  3m        3m      1   {service-controller }           Normal      CreatedLoadBalancer Created load balancer

LoadBalancer Ingress: 104.199.223.53 というものができて、そこにアクセスできるようになる。

Ingress

SSLでLoadBalancerを使いたかったりパスで制御したい場合は、細かい設定が必要な場合は Ingress を利用する。 Serviceがレイヤ3(TCP/UDP over IP)。Ingressがレイヤ7(HTTPS)の取り扱い担当。 Ingressは、外部からのURLアクセスはもちろん、パスでの振り分け、LoadBalancer、SSLの設定などいろいろできる。 ただこのIngress,ベータ。apiVersion: v1beta1 になっている。

試すために、まずは NodePort を作る

dev-np.yml

apiVersion: v1
kind: Service
metadata:
  name: dev-np
spec:
  selector:
    run: test
  type: NodePort
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
      name: http

次にそのNodePortをbackendにしたIngressを作成する

dev-ingress.yml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: dev-ingress
spec:
  backend:
    serviceName: dev-np
    servicePort: 80

/ にきたら、dev-np serviceに送る設定。

作成して最初はGlobalIPが振られない。

$ kubectl get ing
NAME          HOSTS     ADDRESS   PORTS     AGE
dev-ingress   *                   80        12s

作成してしばらくするとADDRESSが振られる。

$ kubectl get ingress dev-ingress
NAME          HOSTS     ADDRESS        PORTS     AGE
dev-ingress   *         130.211.20.6   80        1m

まだ設定完了ではなく、Annotations.backendsにあるBackendnの値が変わるのを待つ必要がある。

$ kubectl describe ing
Name:           dev-ingress
Namespace:      default
Address:        130.211.20.6
Default backend:    dev-np:80 (10.0.0.5:80,10.0.2.5:80)
Rules:
  Host  Path    Backends
  ----  ----    --------
  * *   dev-np:80 (10.0.0.5:80,10.0.2.5:80)
Annotations:
  backends:     {"k8s-be-31291--b0f63256b44dff5c":"Unknown"}
  forwarding-rule:  k8s-fw-default-dev-ingress--b0f63256b44dff5c
  target-proxy:     k8s-tp-default-dev-ingress--b0f63256b44dff5c
  url-map:      k8s-um-default-dev-ingress--b0f63256b44dff5c
Events:
  FirstSeen LastSeen    Count   From                SubobjectPath   Type        Reason  Message
  --------- --------    -----   ----                -------------   --------    ------  -------
  2m        2m      1   {loadbalancer-controller }          Normal      ADD default/dev-ingress
  1m        1m      1   {loadbalancer-controller }          Normal      CREATE  ip: 130.211.20.6

5分くらいすると Unknown が HEALTY に切り替わる。

Annotations:
  backends:     {"k8s-be-31291--b0f63256b44dff5c":"HEALTY"}

するとLoadBalancerのときと同じようにアクセスができるようになる。

$ curl http://130.211.20.6
test-1 OK

まとめ

Serviceの設定はかなり簡単でいろいろな組み合わせができる。 次はちょっと時間置いてから、kubectl apply を使った設定更新周りの話を書く。

参考