Maker Faire Tokyo 2018でのRakuChordキット販売への道のり

Maker Faire Tokyo 2018に出展しました!

ここ数年と同様に、会社の知人のサークル「コネクト・ミー」に混ぜてもらって参加しました。

connect-me-net.tumblr.com

 

「コネクト・ミー」での僕の役割は、回路回りでのトラブルなどがあった際に知恵を貸すといった、「電子工作のスーパーバイザー」的なものです。

ただし、今回は7月に風邪で体調不良だったため、ほとんどお手伝いできず、、ただただ混ぜてもらっただけとなってしまいました。

今年は、「コネクト・ミー」としても”モノを売りたい!”というところで、コマーシャルMakerとしての出展を行いました。

 

「コネクト・ミー」メインの展示について

メインで販売していたのは、「みみにゃん」

電子工作的に面白いところはそれほどないのですが、耳の造形にこだわっており、そこそこそれっぽいネコミミだったのではと思っています。(会場内で購入してくれた方がつけているのをみて、わざわざ買いに来てくださる方がいるほどでした。)

f:id:inajob:20180806150055p:plain

また、みみと合わせて「ひげにゃん」という、猫の口を模したマスクを展示していました。(こちらは展示のみ)ひげにゃんは裏側に距離センサーが付いており、顔の前にマスクがある状態で、口をパクパクさせる動きを認識し、喋ったり、ひげが動いたりするというハイテク猫マスクです。

f:id:inajob:20180806150317p:plain

コネクト・ミーの展示は、子供連れの親子の方や、若い女性、カップルなど、多くの方にウケていました。

初めての販売だった「みみにゃん」についても、予定通りに売ることができました。

 

さて、ここまでは私が居候(?)させていただいている「コネクト・ミー」メインの展示の話でした。

 

コネクト・ミーの展示スペースの端を少し借りる形で、私も自分の作った電子工作の展示とキットの販売を行っていました。

inajobの独自コーナーについて

今年はコマーシャルMakerで参加ということで、僕は長年開発を続けている自作の電子楽器「RakuChord」を販売することにしました。完成品は難しそうなので、キットの販売です。

f:id:inajob:20180806152045p:plain

 

また、去年に引き続きですが、「組みひも組み器」ESP-WROOM-02ゲーム機」「自作Gamebuino」を展示しました。

さらに新作として「o-bako on ESP32」というESP32を使ったゲーム機も展示しました。

 

f:id:inajob:20180806151716p:plain

 

「組みひも組み器」は、興味を持ってくれる方が多く、たくさんの方が人が足を止めて説明を聞いてくれました。

またRakuChordを目当てに来てくれる方もいて、大変感激しました。

inajob.hatenablog.jp

inajob.hatenablog.jp

 

毎年自己紹介をすると「Twitterのこのアイコンの人ですね!」といわれることが多いので、今年は自分Tシャツを着て参加しました。

f:id:inajob:20180806151338p:plain

おかげで、ほかの方のブースに行った時にも一目で「おっあのひとだ!」と認識してもらえることが何度かありました。Twitterで活動してる方にはオススメです。

RakuChordのキットについて

RakuChordのキットについては、このイベントに向けてというわけではなく、ライフワーク的にコツコツと進めてきました。

このページを作ったのが今年の2月です。また同時にソースコードも公開しました。(GitHub - inajob/rakuchord

inajob.github.io

 

そして、興味のありそうな知人にRakuChordの貸し出しなどを行い、人に使ってもらう際のノウハウを集めました。

 

そうこうしていると今回のMaker Faire Tokyo 2018にコマーシャルMakerとして出ようというという話が出てきて、これは良い機会! ということでキットの準備を始めました。

組み立て説明書の作成

実はこれはMaker Faire Tokyo 2018参加が決まる前から作業していました。仮にこのイベントがなくともどこかでキットを配りたいなと思っていたからです。

inajob.github.io

1台を自分で組み立てる様子を写真で撮り、それに説明のテロップを追加して説明書を作成しました。

f:id:inajob:20180806144658p:plain

 

また部品の一覧表も作成しました。

手順は簡単なのですが、ステップにばらすと意外と枚数が多く、苦労しました。

販売個数の決定

今回は、お試しということで家に余っているRakuChordの基板(中国に発注する時は10枚で注文するので、大抵余る)を売ろう ということで、販売個数は8個に決定しました。

部品調達

基板は余っているものだったので、もう準備することはないのですが、それ以外の部品に関しては家にないので、調達する必要があります。

表計算ソフトに、必要な部品を列挙し、それぞれどこで何個購入するかをまとめて、発注しました。中国通販(AliExpress)で購入したり、普通に秋葉原の小売店で必要数購入したりして、部品をそろえました。

f:id:inajob:20180806144910p:plain

それぞれの部品の価格についてもまとめておきました。

部品製作(筐体)

今回は8個ということで、我が家にある3Dプリンタで作成しました。休みの日や、早く帰宅した日を利用して、淡々と出力しました。

3DデータはOpenSCADで作成しています。(後ほど公開予定です)

f:id:inajob:20180806145046p:plain

価格決定

ここはかなり悩みました。今回は単純に材料費の合計にマジックナンバーを掛けるという方式で価格を決定しました。

極端に安く売ることもできるのですが、売れば売るほど損をするようでは、僕の財布も、モチベーションも保てません。

スイッチサイエンスで販売されているキットの価格なども参考にしつつ、大まかな価格感を決定しました。

 

「4500円」

f:id:inajob:20180806145115p:plain

これが高いと感じるか、妥当と感じるかは人それぞれなのかなと思います。。

検品

キットなので組み立てて動作を確認することができません。怪しい部品については部品単位で動作を確認します。特に中国通販で買ったICに関しては、動作が怪しい気がしたので、確認したところ実際に期待した動作をしないものがあったりしました。

キッティング

部品が次々と届くわけですが、販売用にこれらをキット化する必要があります。文具屋やダイソーなどで小分けの袋を購入したり、説明用のチラシをネットプリントで印刷します。

そしてそれらをキットとしてパックします。

f:id:inajob:20180806145516p:plain

f:id:inajob:20180806145609p:plain細かく紛らわしい部品が多いので、一度詰めた後に再度確認しました。

運搬

わざわざ見出しを書きましたが、今回は8個だけだったので、普通に手提げ袋に入れて自分で運びました。大量に売るとなると運搬も業者に頼むなどが必要なのだろう、と思いました。

販売

実際の販売は楽しいものでした。Maker Faire Tokyoには何度も出展したことがあるので、同じ感じなのですが、販売をしていると、プラスアルファで「売れる」という喜びがあります。

たくさん在庫があると、売れ残ったらどうしよう・・みたいに思うところですが、今回は8個ということで、気楽に構えていました。

結果6個売れるということで、なかなかの戦果だったのでは?と思います。

まぁ実際買ってくれた方の多くは、以前からの知り合いやTwitterで仲良くしている方たちだったので、コネで売った 感はあります。初見でも「ほしい!」と思わせる何かを作るのは、大変なのだなと感じました。

販売後

Twitterなどで作成報告を書いてくださっている方もいて、販売後も楽しみがあります。(不備があるかも、、と考えると心配ではありますが・・)自分の作ったものが、他人にも認められて、購入されて、しかも活用されている!というのを見られるのはとても感慨深いものがあります。

まとめ

今回は自分で作った電子工作作品を他人に販売するという貴重な体験ができました。

RakuChordはライフワーク的に作っている楽器で、今後もソフトウェア面、ハードウェア面ともに改良を続けていく予定です。

また面白いものができたら販売していきたいなと感じました。次はネットで販売するのをやってみたいな!

f:id:inajob:20180806152344p:plain

 

3DプリンタX軸の自己修復的な修理

X軸の調子が悪い

3Dプリンタを買ってもう1年半ほどですが、どうも最近X軸の調子が悪い

inajob.hatenablog.jp

具体的にはX軸のベルトが頻繁に緩むようになっていました。

Y軸のベルトは対して緩まないのになぜX軸だけ、、?と思いながら、緩んでいるときには、ケーブルをきつく付け直していました。

f:id:inajob:20180725213828p:plain

↑緩んでいたのは赤く囲った部分のベルトです。

f:id:inajob:20180725213942p:plain

↑今回問題となったのはここの部品。この部分は3Dプリンタで作成されたものです。

f:id:inajob:20180725214046p:plain

現物はこんな感じです。一見問題ないように見えますが、モーターを固定している部分が大きく曲がってしまっているのです。

f:id:inajob:20180725214159p:plain

取り外すとわかりやすいですが、波打つように曲がってしまっています。

X軸のベルトの張力により、徐々にプラスチックが曲がってきてしまったようです。

そのためベルトが他の部品にこすれるようになってしまい、摩耗していましたし、X軸の移動もスムーズではなくなりかけていました。

f:id:inajob:20180725214356p:plain

そういえば3Dプリンタのマニュアルに、パーツのデータも同梱されていたので、同じものを3Dプリンタで出力。自分で自分を修理するというのができるのが3Dプリンタの面白いところです。

ベアリングがかなりきつくはめ込んであって外すの、入れなおすのも苦労しましたが、とりあえず新しいパーツに付け替えて今は問題なく動いています。

 

これにて修理終了。

f:id:inajob:20180725214804p:plain

左右でパーツの色が違っているのも愛嬌ということで。これからも働いてもらいます!

 

3Dプリンタを使って何が作れるかはこちら

inajob.hatenablog.jp

マイコンボードまとめ

最近マイコンボードがたくさん出てきているので、CPUごとにまとめました。(ついでにゲーム機もまとめました) Arduinoとか、mbedとかメジャーなものはまだ記載していません。

LPC1114

IchigoJam

PIC32

OrangePico

Machikania

STM32F103C8

Blue Pill

ESP8266

ESPr Developper

KOMAINO

ESP32

ESPr Developper 32

obniz

Nefty BT

m5stack

ATSAMD21

Gamebuino META

Arduino M0 Pro

LPC11U6x

pokitto

ATTiny85

8pino

Digispark

Atmega328

nekoboard2

ちっちゃいーの

Dotsuino

TinyDuino

Gamebuino Classic

Atmega32u4

Arduboy

Beetle

Arduino Esplora

nRF51822

micro:bit

未分類

Teensy

Trinket

micro:bit

Mbed

ESP32を使ったゲーム機"o-bako"のシミュレータを開発した

ESP32を使ったゲーム機 "o-bako"

”o-bako” とは最近僕が作っているゲーム機です。

ESP32と128×128の液晶、アンプとスピーカ。十字ボタンとA,Bボタン、スタートボタンを搭載しています。

さらにPS/2キーボードが接続できるようになっています。

f:id:inajob:20180527165238p:plain

ESP32-DevKitC を利用しており、arduino-esp32を使うことで、Arduinoのようにプログラムを組むことができます。

f:id:inajob:20180527175931p:plain f:id:inajob:20180527175958p:plain

3Dプリンタで簡易的なケースも作成しました。

f:id:inajob:20180527180919p:plain

構成としては最近話題のm5stackと似たようなものです。

また、Lua言語のインタプリタを動かせるようになっており、Luaで書いたプログラムを実行することができます。

さらにWiFi機能を使ってWebサーバとしても動作します。このWebサーバにアクセスすることで、Luaプログラムを閲覧したり、編集することができます。

 

f:id:inajob:20180527174542p:plain

o-bako Simulator

 o-bakoはまだ開発中なのですが、o-bakoで動かすLuaで書かれたゲームはそれ以外の環境でも、理論的には動かすことができます。

パソコンでプログラムを書いて、o-bakoに転送し、動作を検証し、という作業を効率化するためにブラウザで動作するo-bakoのシミュレータを開発しました。

inajob.github.io

 

f:id:inajob:20180527171658p:plain

理論的にはこのシミュレータで動作するように書いたプログラムは、o-bakoでも同じように動作します。

 

いまのところo-bakoが定義している命令は下記の9個だけです。(まだ追加する予定ですが、それほど大きく増やすつもりはありません。)

tone(no, freq, vol) 音を鳴らす(no: 0-2, vol: 0-255)
spr(x,y,w,h,sx,sy[,sw,sh]) (x,y)にspriteを(sx,sy)からサイズはw,hで描画する。sw,shを設定すると拡大、縮小できる。
pset(x,y) (x,y)に1ピクセルのドットを描画
color(r,g,b) ペンの色を[r,g,b]に設定。(r: 0-255, g: 0-255, b: 0-255)
text(s,x,y) (x,y)に文字列sを描画
drawrect(x,y,w,h) (x,y)にサイズw,hの四角形の枠線を描画
fillrect(x,y,w,h) (x,y)にサイズw,hの四角形を塗りつぶす
fillcircle(x,y,r) (x,y)を中心に半径rの円を塗りつぶす
btn(n) ボタンの入力を取得 ボタンを押してからのフレーム数が返る

テキストエリアにプログラムを書き込んで「Execute」をクリックするとゲームが動作するので、試してみてください。


ゲームプラットフォームとしての"o-bako" 

最近Arduboy, Gamebuino, Pokittoなど様々なゲームプラットフォームが出てきていますが、それぞれで作ったゲームはそのゲーム機専用になってしまい、ほかのプラットフォームでは動作しません。

Luaのようなもうすこし高レベルの層を定義し、それに向けたゲームを作るようにすることで、ほかのプラットフォームでも簡単に動作するものができるのではないか?と考えています。

LuaC言語が動作する環境であれば、非常に簡単に移植することができます。(メモリ、CPUがそこそこ必要ですが・・)

 

とか書きましたが実際のところは僕が作ってみたいので作ってるだけです。生暖かく見守ってください。

 

Arduinoで掃除しないルンバを作った

これは何?

f:id:inajob:20180331231312p:plain

ロボット作りの習作ということで、Arduinoを使っていわゆるルンバみたいな部屋の中を自律的に走行するロボット(ただし掃除はしない)を作ってみました。

 

材料

  • Arduino
  • モーターとギアボックス
  • タイヤ
  • モータードライバ(TA7291P)
  • 距離センサー(HC-SR04)
  • ブレッドボード
  • 9V電池
  • 3Dプリンタとフィラメント

筐体の作成

今回は作りながら構成を考えるということで、まずはこういうユニバーサルボードを作ってみます。

穴の大きさは11mm。僕がよく作るねじの直径が10mmなので、そのねじがうまく入るような大きさにしました。

f:id:inajob:20180331224926p:plain

ギアボックスと3mmのボルトとナットでで固定します。この時点でかなりそれっぽい!

f:id:inajob:20180331224834p:plain

OpenSCADでねじを作ります。

f:id:inajob:20180331225129p:plain

Fusion360でこういうのを作ります。

Arduino固定用パーツ

f:id:inajob:20180331225232p:plain

ブレッドボード固定用パーツ

f:id:inajob:20180331225321p:plain

9V電池固定用パーツ

f:id:inajob:20180331225703p:plain

 

で、こんな風に上にArduinoを固定します。

f:id:inajob:20180331225421p:plain

9V電池はこんな風に固定する

f:id:inajob:20180331225752p:plain

回路

下の記事を参考にして、モータードライバを制御しました。今回は両輪別々に制御したかったので、同じ回路を2つ並べました。

shangtian.hatenablog.com

 

超音波センサーについては下記記事を参考に。

deviceplus.jp

 

(この後紹介するスピーカーも含めた回路図です)

f:id:inajob:20180401225137p:plain

 

 

プログラムの作成

ほとんどプログラムも前述の記事の真似です。

自立制御の部分はテキトーに作りました。

50cm先に障害物を発見すると、バックして左に少し回転してまた前進します。

const int motor1A = 2;
const int motor1B = 3;
const int motor2A = 4;
const int motor2B = 5;
const int motorPwm = 6;

const int echoPin = 8;
const int trigPin = 7;

enum Mode{modeLeft, modeRight, modeForward, modeBackward};
Mode mode = modeForward;

void back(){
  digitalWrite(motor1A, HIGH);
  digitalWrite(motor1B, LOW);

  digitalWrite(motor2A, LOW);
  digitalWrite(motor2B, HIGH);
}
void backward(){
  digitalWrite(motor1A, HIGH);
  digitalWrite(motor1B, LOW);

  digitalWrite(motor2A, LOW);
  digitalWrite(motor2B, HIGH);
}
void forward(){
  digitalWrite(motor1A, LOW);
  digitalWrite(motor1B, HIGH);

  digitalWrite(motor2A, HIGH);
  digitalWrite(motor2B, LOW);
}
void turnLeft(){
  digitalWrite(motor1A, HIGH);
  digitalWrite(motor1B, LOW);

  digitalWrite(motor2A, HIGH);
  digitalWrite(motor2B, LOW);
}
void turnRight(){
  digitalWrite(motor1A, LOW);
  digitalWrite(motor1B, HIGH);

  digitalWrite(motor2A, LOW);
  digitalWrite(motor2B, HIGH);
}

double getDistance(){
  double duration = 0;
  double distance = 0;

  digitalWrite(trigPin, LOW); 
  delayMicroseconds(2); 
  digitalWrite( trigPin, HIGH );
  delayMicroseconds( 10 );
  digitalWrite( trigPin, LOW );
  duration = pulseIn( echoPin, HIGH );
  if (duration > 0) {
    duration = duration/2;
    distance = duration*340*100/1000000;
    if(distance > 100){
      distance = 100;
    }
  }
  return distance;
}

void setup() {
  Serial.begin(9600);
  pinMode(motor1A, OUTPUT);
  pinMode(motor2A, OUTPUT);
  pinMode(motor1B, OUTPUT);
  pinMode(motor2B, OUTPUT);
  pinMode(motorPwm, OUTPUT);

  digitalWrite(motorPwm, LOW);

  pinMode( echoPin, INPUT );
  pinMode( trigPin, OUTPUT );

  forward();
}

int sp = 255;
int nearCount = 0;
int forceTurnCount = 0;
int forceBackCount = 0;

void loop() {
  switch(mode){
    case modeLeft: turnLeft(); break;
    case modeRight: turnRight(); break;
    case modeForward: forward(); break;
    case modeBackward: backward(); break;
  }

  // speed
  analogWrite(motorPwm,sp);

  double distance = getDistance();
  if(distance < 50){
    nearCount ++;
  }else{
    nearCount = 0;
  }

  if(nearCount > 10 && mode == modeForward){
    mode = modeBackward;
    forceBackCount = 100;
    Serial.println("detect object. back");
  }else if(mode == modeBackward){
    forceBackCount --;
    if(forceBackCount == 0){
      forceTurnCount = 30;
      mode = modeLeft;
    }
    Serial.println("back");
  }else if(mode == modeLeft){
    forceTurnCount --;
    if(forceTurnCount == 0){
      mode = modeForward;
    }
    Serial.println("left");
  }else{
    mode = modeForward;
    Serial.println("forward");
  }
}

 動画

感想 

3Dプリンタがあると、こういう物理的な工作が簡単にできました。

また今回は初めからすべてを設計するのではなく、ユニバーサルボード的なものを作って、後付けパーツで組み立てていくという方式にしたため、簡単に設計を試行錯誤することができました。

 

そして自律的に動くものをプログラムするのは難しいと感じました。今回はとても単純な仕組みで作りましたが、これ以上賢く作るためには、このようなルールをどんどん入れていくか、ロボットが空間を把握するような仕組みをプログラムするか、、 いずれにしても大変そうです。

また気が向いたら改良していこうと思います。

 

追記:話せるようにしてみる

ちょうど家にあったDFPlayerMiniを使って状況に応じてmp3を再生させるようにしてみました。

 おきまりのセリフをしゃべるだけだけど、これだけでかなり愛着がわくものになった気がします。

 

音声は下記サイトのものを利用しました。

soundeffect-lab.info

 

参考部品リンク

Arduino

つかったのはこちら

www.aitendo.com

 普通のならこれかな?

【永久保証付き】Arduino Uno

【永久保証付き】Arduino Uno

 

 

モーターとギアボックス

つかったのはこれ。もう欠品のようだ

www.aitendo.com

 これが同じもののように見える。タイヤも付いている。

 モータードライバ

つかったのはこれ。ディスコンらしい。

akizukidenshi.com

 Amazonにもあるが別のモータードライバを使うのがよさそう。

 距離センサー

akizukidenshi.com

 Amazonならこれかな?

HC-SR04 超音波距離センサーモジュール For Arduino

HC-SR04 超音波距離センサーモジュール For Arduino

 
DFPlayerMini

 

 

ブレッドボード 

akizukidenshi.com

 Amazonならこれかな?

月10ドルのKubernetesクラスタに無料で取得したドメインでアクセスできるようにする

概要

前回は$10/月のKubernetesクラスタを作成しました。

inajob.hatenablog.jp

ここに自分用のWebサービスなどをデプロイすれば個人サーバとして活用できるわけですが、いつまでもIPアドレスでアクセスするというのはダサいですね。 今回は無料でドメインを取得しKubernetes上のサービスをその名前でアクセスできるようにしてみます。

f:id:inajob:20180228185422p:plain

ドメインをとるのはちょっと・・・という人はcurlのオプションでヘッダをつけてアクセスすることでその挙動を確認することができます。(が今回の記事では触れません)

TKドメインの取得

トラケウのドメインである.tkは無料で取得できます。

.tk - Wikipedia

もちろんすでにドメインを持っている人はこのような怪しいドメインを取得する必要はありません

https://my.freenom.com

とれるかな、、 f:id:inajob:20180228175551p:plain いけそう! f:id:inajob:20180228175618p:plain kubernetesのmasterのIPアドレスを入れる(あとで変えるので何でもよいのですが、、) f:id:inajob:20180228175858p:plain いい感じに入力する f:id:inajob:20180228175946p:plain 下記からアクセスすると所有しているドメインの一覧が確認できる。 https://my.freenom.com/clientarea.php?action=domains

CloudFlareでワイルドカードDNSの登録

FreenomでもDNSサービスは提供しているのですが、CloudFlareのほうが操作性がよくワイルドカードDNSが利用できるのでこちらを使うことにします。

www.cloudflare.com 右上のAdd Siteからドメインを追加画面に遷移 f:id:inajob:20180228180457p:plain

一番左の無料のやつを選択 f:id:inajob:20180228180524p:plain

いったんそのままContinue f:id:inajob:20180228180615p:plain

nameserverを変えろと言われる。 f:id:inajob:20180228180653p:plain

freenomに行って指示通りにNameserverを変更する f:id:inajob:20180228180847p:plain

Cloudflareにて反映されるのを待つ f:id:inajob:20180228180930p:plain

ページを行ったり来たりしていると数分で反映された f:id:inajob:20180228181223p:plain

いまこのドメインにアクセスすると下記のようになる。 これは名前からサーバまではいけるがそのサーバの80番が開いていないということのようだ。 登録したIPが間違っていたかな? f:id:inajob:20180228181250p:plain

nghttpx-ingress-controllerがデプロイされているホストをを調べる f:id:inajob:20180228181410p:plain

worker01にデプロイされているので、そのIPに設定する(masterのIPを指定していました;) (通常のPodは10.x.xのようなクラスタ内IPが付与されますがnghttpx-ingress-controllerは.spec.hostNetwork=trueとなっているためホストのIPとなっています my-vps-kubernetes/rc-default.yaml at master · inajob/my-vps-kubernetes · GitHubf:id:inajob:20180228181657p:plain

アクセスできた! この"default backend -404" というのはKubernetes上のサービスから返却しているものです。

f:id:inajob:20180228181819p:plain

図にするとこんな感じ f:id:inajob:20180228182434p:plain

$ kubectl get pods -n kube-system
NAME                                         READY     STATUS    RESTARTS   AGE
default-http-backend-55c6c69b88-vlqcx        1/1       Running   0          1h <--- これです
etcd-kubernetes                              1/1       Running   0          1h
kube-apiserver-kubernetes                    1/1       Running   0          1h
kube-controller-manager-kubernetes           1/1       Running   0          1h
kube-dns-6f4fd4bdf-c2995                     3/3       Running   0          1h
kube-proxy-622sq                             1/1       Running   0          1h
kube-proxy-j5754                             1/1       Running   0          1h
kube-scheduler-kubernetes                    1/1       Running   0          1h
monitoring-grafana-8dd9cb57f-4ms82           1/1       Running   0          1h
nghttpx-ingress-controller-78749dc54-8wlxr   1/1       Running   0          29m
node-exporter-5294m                          1/1       Running   0          1h
prometheus-8694d8cdd8-vmw7h                  1/1       Running   0          1h
weave-net-r5jft                              2/2       Running   0          1h
weave-net-wm7sn                              2/2       Running   0          1h

Ingressを試す

ドメインの取得、DNSサーバへの登録が終わり、無事取得したドメインでKubernetesクラスタまで到達できることが確認できました。 次はIngressを試します。

Ingressを利用するとVirtualHostのようにHostヘッダの値で違うServiceにアクセスさせることができます。

nginxをデプロイして、Serviceも作成します。

$ kubectl run nginx --image=nginx
deployment "nginx" created
$ kubectl expose deployment nginx --port=80
service "nginx" exposed

Ingressはコマンドでは作れないので下記のようなテキストファイルを用意します

nginx-ingress.yaml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: nginx-ingress
spec:
  rules:
  - host: nginx.inajob-test.tk
    http:
      paths:
      - path: /
        backend:
          serviceName: nginx
          servicePort: 80

上記をKubernetesにデプロイします。

$ kubectl apply -f nginx-ingress.yaml
ingress "nginx-ingress" created

cloudflareにAレコードを追加します f:id:inajob:20180228183320p:plain

やった!アクセスできました。 f:id:inajob:20180228183400p:plain

新しいサブドメインIngressを用意するたびにcloudflareにAレコードを追加するのが面倒なのでワイルドカードドメインを追加してみます。

丸で囲ったところに注意です。CloudFlareではCloudFlareを経由しキャッシュを返したり、SSL化したりするような機能がありますが、ワイルドカードドメインの場合はそれが使えないので明示的にOFFにしています。

f:id:inajob:20180228183707p:plain

f:id:inajob:20180228183635p:plain

これであとはIngressを用意するだけでサブドメインが増えていくようになります。

まとめ

ここまでできると月$10のクラスタでもそこそこつかえるKubernetesが構築できたのではないかと思います。

ということで、vultrでサーバを作りましょう! (この記事が役立った!という人はぜひこちらのリンクからお願いします。)

www.vultr.com

月10ドルで海外VPSでKubernetesを試してみる(kubernetes v1.9版)

VultrでのKubernetesセットアップ方法

以前書いた記事

inajob.hatenablog.jp

で反響があったのですが、今試すとずいぶんやり方が変わっているところがあるので、Kubernetes1.9のやり方をまとめました。

例によって下記からVultrに申し込んでもらうと僕に$10入ります。 (以前の記事で$10ゲットしたので、やる気が出てこの記事を書く気になりました! この記事読んで試してみたいと思った人はぜひ下記リンクからお願いします。僕へのご褒美になります)

www.vultr.com

以前の記事では1台のマシンで構築したのですが、さすがにつらかったので、今回は奮発して$10/monthで2台構成のクラスタを作成します。 この手順で作るkubernetesはアルファの機能を使っていたり、セキュリティ上まずい設定を指定しているところもあるので、このままインターネットにさらし続けるのは危険です。

今回はコマンドやmanifestをgit上にまとめました。 github.com

準備

f:id:inajob:20180228170636p:plain

サーバは上記のプランで2つ用意する。 OSはUbuntu 17.10 x64

master, worker共通のセットアップ手順

事前にパッケージは最新化しておく

# apt-get update && apt-get upgrade
#必要に応じてリブートする
# reboot
# git clone https://github.com/inajob/my-vps-kubernetes.git
# cd my-vps-kubernetes/
# sh init-scripts/setup.sh

init-scripts/setup.shの解説

#!/bin/sh

# dockerをインストール
apt-get install -y docker.io

# kubeadm kubelet kubectlのインストール
apt-get update && apt-get install -y apt-transport-https
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
deb http://apt.kubernetes.io/ kubernetes-xenial main
EOF
apt-get update
apt-get install -y kubelet kubeadm kubectl

# swapの設定(非推奨だが非力なマシンなので設定します)
dd if=/dev/zero of=/swapfile count=2048 bs=1M
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
echo "/swapfile   none    swap    sw    0   0" >> /etc/fstab

#kubeletの設定ファイルを作るためにkubeadm initを実行(実際は失敗する)
kubeadm init

# kubeletの設定を変更しswapがonの状態でも起動できるようにする
sed -i 's/\/usr\/bin\/kubelet/\/usr\/bin\/kubelet --fail-swap-on=false /' /etc/systemd/system/kubelet.service.d/10-kubeadm.conf

# kubeadmのお片づけをする(これをしないとこのあとのkubeadm initが実行できない)
kubeadm reset

# kubeletの設定変更を反映する
systemctl daemon-reload
systemctl restart kubelet

masterのセットアップ手順

# kubeadm init --ignore-preflight-errors=Swap

--ignore-preflight-errors=Swapは本来Swapが有効だとこのコマンドは失敗するのだが、それを無視して進めるようするためのオプションです。

kubeadm join .... といったworker接続用の文字列が出るのでメモ帳などにコピーしておきます。

workerのセットアップ手順

さきほどコピーしたkubeadm join .... の末尾に同様に--ignore-preflight-errors=Swapをつけて実行します。

# kubeadm join ....--ignore-preflight-errors=Swap

手元のラップトップ

kubectlをインストールしておきます。

SCPでmasterサーバのadmin.confを持ってきます。

$ scp root@masterサーバのアドレス:/etc/kubernetes/admin.conf ./admin.conf

ラップトップ内にmasterサーバへのプロキシを作成します。

$ kubectl --kubeconfig=:admin.conf proxy  --port=8080 --disable-filter=true --accept-hosts='^*$' --reject-paths='^$'

nodeを確認します

$ kubectl get nodes
NAME         STATUS     ROLES     AGE       VERSION
kubernetes   NotReady   master    4m        v1.9.3
worker01     NotReady   <none>    3m        v1.9.3

CNIネットワークを指定していないのでNotReadyのままですが2台のサーバでクラスタが組めていることが確認できます。

Weaveのデプロイ

CNIネットワークプラグインであるweaveををインストールします。 ほかのネットワークプラグインを使うこともできるので気になる人は公式ページから探してみてください

Using kubeadm to Create a Cluster | Kubernetes

$ kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=1.9"

Readyになりました。

$ kubectl get nodes
NAME         STATUS    ROLES     AGE       VERSION
kubernetes   Ready     master    6m        v1.9.3
worker01     Ready     <none>    5m        v1.9.3

kube-dnsカスタム設定のデプロイ

$ git clone https://github.com/inajob/my-vps-kubernetes.git
$ cd my-vps-kubernetes/
$ kubectl apply -f manifests/dns/
configmap "kube-dns" created

これの中身は下記です

apiVersion: v1
kind: ConfigMap
metadata:
  name: kube-dns
  namespace: kube-system
data:
  upstreamNameservers: |
    ["8.8.8.8", "8.8.4.4"]

ubuntu固有の問題らしく kube-dns copies 127.0.0.35 from host's /etc/resolv.conf, doesn't work · Issue #45828 · kubernetes/kubernetes · GitHub これを入れないとpodから外への名前解決が失敗します。

どうもUbuntuは内部にDNSサーバを持っているようで、127.0.0.53が/etc/resolv.confに書かれています。しかしPodの中からはこのIPに到達できないので、kube-dnsから外の名前を引くことができなくなるようです。 このConfigMapを入れることで外のDNSを明示的に指定しています。

ingress-controllerのデプロイ

$ kubectl apply -f manifests/ingress-controller/
deployment "default-http-backend" created
service "default-http-backend" created
serviceaccount "ingress" created
clusterrole "ingress-clusterrole" created
role "ingress-role" created
rolebinding "ingress-role-binding" created
clusterrolebinding "ingress-clusterrole-binding" created
deployment "nghttpx-ingress-controller" created
service "nginhttpx-health" created

今後のためにingress-controllerをデプロイします。

prometheus, node-exporter, grafanaのデプロイ

$ kubectl apply -f manifests/monitoring/
deployment "monitoring-grafana" created
service "monitoring-grafana" created
daemonset "node-exporter" created
configmap "prometheus-config" created
clusterrole "prometheus" created
serviceaccount "prometheus" created
clusterrolebinding "prometheus" created
deployment "prometheus" created
service "prometheus" created

負荷状況のメトリクスを取得、可視化するために追加します。

動作確認

Pod一覧

$ kubectl get pods -n kube-system
NAME                                         READY     STATUS    RESTARTS   AGE
default-http-backend-55c6c69b88-vlqcx        1/1       Running   0          1m
etcd-kubernetes                              1/1       Running   0          10m
kube-apiserver-kubernetes                    1/1       Running   0          9m
kube-controller-manager-kubernetes           1/1       Running   0          9m
kube-dns-6f4fd4bdf-c2995                     3/3       Running   0          10m
kube-proxy-622sq                             1/1       Running   0          9m
kube-proxy-j5754                             1/1       Running   0          10m
kube-scheduler-kubernetes                    1/1       Running   0          9m
monitoring-grafana-8dd9cb57f-4ms82           1/1       Running   0          43s
nghttpx-ingress-controller-78749dc54-jl4nv   1/1       Running   0          1m
node-exporter-5294m                          1/1       Running   0          43s
prometheus-8694d8cdd8-vmw7h                  1/1       Running   0          43s
weave-net-r5jft                              2/2       Running   0          4m
weave-net-wm7sn                              2/2       Running   0          4m

PrometheusのUIを確認

Prometheusは固定のポートでexposeしてあります。

http://masterまたはworkerのIPアドレス:30090/

GraphanaのUIを確認

Graphanaも固定のポートでexposeしてあります。

http://masterまたはworkerのIPアドレス:30091/

grafanaの設定方法は 月5ドルの海外VPSでKubernetesを試してみる - inajob's blog の記事のままです。参考にしてください。

f:id:inajob:20180228174920p:plain

next

このリポジトリではingress-controllerもデプロイしています。 ドメインを持っている人は、DNSの設定とIngressリソースのデプロイを行うことで、オリジナルドメインのサービスを提供することができます。

それについては次の記事に記載しています。

inajob.hatenablog.jp