僕は技術ができない

技術のできないスーツ園児ニアが考えていること

KubernetesマスターとKubernetesノードについてふわっと理解する

今回は Kubernetesクラスターを構成する Kubernetes マスター と Kubernetes ノードについてふわっと理解していこうと思います。

Kubernetes 上ではクラスタを「望ましい状態」に保つために様々なコントロールプレーンと呼ばれるプロセスが協調しながら動いています。

コントロールプレーンを理解する前に、まずは「コントロールプレーンがどこで動くのか」についてまとめたいと思います。

コントロールプレーンはどこで動くのか

Kubernetes クラスターは以下の2つで構成されています。

  • Kubernetes マスター:クラスターを管理するプロセスの集合
  • Kubernetes ノード(ワーカーとも言う):コンテナが実際にデプロイされるマシン

ざっくり言ってしまうと、マスター内のコントロールプレーンがクラスターの「望ましい状態」を管理し、ノード内のコントロールプレーンが「望ましい状態」にするため自律的に動くという役割分担になっています。

マスターやノードのホストは物理マシンでもよいですし、VMでもよいです。

Kubernetesマスターの冗長化

基本的には、Kubernetes マスターはクラスター内の1台のサーバーにホストされます。

f:id:contemporarycuz:20191113215130p:plain

もちろん、本番ではマスターが止まるとクラスターが機能しなくなるため、複数台用意して冗長化を図ります。

f:id:contemporarycuz:20191113215204p:plain

また、Kubernetes マスターはあくまでもクラスターを管理するプロセスの集合なので、「プロセスの一部のみを冗長化」したり、「同一のマシンにマスターとノードを同居させる」こともできます。

f:id:contemporarycuz:20191113220850p:plain
プロセスの一部のみを冗長化

f:id:contemporarycuz:20191113220929p:plain
同一のマシンにマスターとノードを同居

マスターの冗長化については以下の記事がわかりやすいです。

qiita.com

クラウドのマネージドKubernetesを利用した場合の冗長化

パブリッククラウドのマネージドサービスを利用する場合には「Kubernetes マスター」がクラウドベンダーに管理されているため、マスターの冗長化は考える必要はありません。以下にAzureの例を示しておきます。

docs.microsoft.com

f:id:contemporarycuz:20191113215645p:plain
Azure Kubernetes Service のアーキテクチャー

Angular で Firebase の Database, Storage データを読み取るまでの流れ

前回は Angular プロジェクトを Firebase にデプロイし、アクセスするまでをやりました。

www.contemporarycuz.com

今回は、Firestore や Storage につないでデータを表示するところまでをやります。

ケースとしては、とりあえずアプリをデプロイして繋ぐことができればOKというガバガバ仕様を想定してますので予めご了承ください。

Firebase 側での作業

Config の取得

Firebaseコンソールの「Project Overview」から、</> (Webアプリ)を選択し、アプリを登録します。

f:id:contemporarycuz:20190917170145p:plain

f:id:contemporarycuz:20190917170452p:plain

SDK Snippet からアプリのConfig類をコピーしておきます。

f:id:contemporarycuz:20190917171050p:plain

Firestore へのデータ登録

コレクションを作成します。

f:id:contemporarycuz:20190917175143p:plain

今回は以下の設定で作成しました。

  • コレクション ID:hoge-collection
  • ドキュメント ID:hoge-doc

こんな感じです。

f:id:contemporarycuz:20190917175356p:plain

Firestorage へのデータ登録

適当にファイルをアップロードします。

f:id:contemporarycuz:20190917181642p:plain

アクセス権をガバガバにします。以下のように読み取りアクセスをパブリックに向けます。

f:id:contemporarycuz:20190917191852p:plain

とりあえず、Firebase側での作業はこれで終わりです。

ローカル側での作業

アプリをFBのリソースを利用するように書き換えます。

Firebase モジュールのインポート

@angular/fire パッケージをインストール(npm リファレンス

$ npm install --save firebase @angular/fire

src/app/app.module.ts を書き換えます。

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';

import { AngularFireModule } from '@angular/fire';  // 追記
import { AngularFireAuthModule } from '@angular/fire/auth';  // 追記
import { AngularFirestoreModule } from '@angular/fire/firestore';  // 追記
import { AngularFireStorageModule } from '@angular/fire/storage';  // 追記

var firebaseConfig = {
  apiKey: "(略)",
  authDomain: "(略)",
  databaseURL: "(略)",
  projectId: "(略)",
  storageBucket: "(略)",
  messagingSenderId: "(略)",
  appId: "(略)"
};

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    AngularFireModule.initializeApp(firebaseConfig),  // 追記
    AngularFireAuthModule,  // 追記
    AngularFirestoreModule,  // 追記
    AngularFireStorageModule  // 追記
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

テスト用にコンポーネントを用意

コンポーネントを生成します。

$ ng generate component firestore
$ ng generate component firestorage

ルーティング設定をします。

src/app/app-routing.module.ts

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

import { FirestoreComponent } from './firestore/firestore.component'; // FirestoreComponentをimport
import { FirestorageComponent } from './firestorage/firestorage.component'; // FirestorageComponentをimport


const routes: Routes = [
  {path: 'firestore', component: FirestoreComponent}, // FirestorageComponentを追加
  {path: 'firestorage', component: FirestorageComponent} // FirestoreComponentを追加
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

デフォルトのトップページが邪魔なので消します。

src/app/app.component.html

<router-outlet></router-outlet>

疎通確認します。

$ ng serve --open

f:id:contemporarycuz:20190917173536p:plain

Firestore コンポーネントの書き換え

適当に書き換えます。このdataにFirestoreに登録したデータを表示させます。 src/app/firestore/firestore.component.html

<div>
    <p>firestore works!</p>
</div>
<div>
    <p>{{data}}</p>
</div>

src/app/firestore/firestore.component.ts

import { Component, OnInit } from '@angular/core';
import { AngularFirestore } from '@angular/fire/firestore'; // @angular/fire/firestore のインポート

@Component({
  selector: 'app-firestore',
  templateUrl: './firestore.component.html',
  styleUrls: ['./firestore.component.css']
})
export class FirestoreComponent implements OnInit {
  data: string = 'this variable is from firestore'; // 変数の初期化

  constructor(private firestore:AngularFirestore) { }

  // データベースの読み取り(hoge-collection -> hoge-doc -> hoge-field)
  ngOnInit() {
    this.firestore.collection('hoge-collection').doc('hoge-doc').valueChanges().subscribe((value)=>{
      this.data = value['hoge-field'];
    });
  }

}

疎通確認します。

f:id:contemporarycuz:20190917175956p:plain

Firestoreの値を書き換え、リアルタイムに画面も更新されるか見てみましょう。

f:id:contemporarycuz:20190917180202p:plain

Firestorage コンポーネントの書き換え

src/app/firestorage/firestorage.component.html

<div>
    <p>firestorage works!</p>
</div>
<div>
    <img id="image" src="" />
</div>

src/app/firestorage/firestorage.component.ts

import { Component, OnInit } from '@angular/core';
import { AngularFireStorage } from '@angular/fire/storage';

@Component({
  selector: 'app-firestorage',
  templateUrl: './firestorage.component.html',
  styleUrls: ['./firestorage.component.css']
})
export class FirestorageComponent implements OnInit {

  constructor(private storage:AngularFireStorage) {  }

  ngOnInit() {
    this.storage.storage.ref('angular.png').getDownloadURL().then((url) => {
      var img = (<HTMLInputElement>document.getElementById('image'));
      img.setAttribute('src', url);
    });
  }
}

(参考)TypescriptでHTMLElementを使う方法

stackoverflow.com

TypescriptもAngularもわからないマンなので document.getElementById を使わずに Angular で正しく実装する方法がよくわからず、、、 だれか教えてください。

疎通確認します。

$ ng serve --open

f:id:contemporarycuz:20190917212939p:plain

Firebase にデプロイ

ビルド&デプロイ

$ ng build --prod
$ firebase deploy

デプロイ先で疎通確認

f:id:contemporarycuz:20190917214418p:plain

Angular プロジェクトを Firebaseにデプロイするまでの流れ

今回は Angular プロジェクトを Firebase にデプロイし、アクセスするまでの流れをまとめます。

ケースとしては、とりあえずアプリをデプロイして繋ぐことができればOKというガバガバ仕様を想定してますので予めご了承ください。

Firebase側での作業

プロジェクトの作成

以下にアクセス
https://console.firebase.google.com/

Firebase アカウントを作成していない場合は作成してください。特記すべきことは特になく、案内に従って適当にポチポチしてればできます。

以下の設定値でプロジェクトを新規作成します。

  • プロジェクト名:deploy-test
  • Google Analytics の設定:デフォルトのFBアカウント

Authentication の設定

プロジェクトが作成されたら、左ペインから「Authentication」をクリックします。 「ログイン方法」タブから適当にログインプロバイダを選び、設定します。 今回は Google アカウントでログインするように設定します。

f:id:contemporarycuz:20190917160408p:plain

「プロジェクトの公開名」と「プロジェクトのサポートメール」を設定し、「有効にする」トグルを有効にし、「保存」をクリックします。

f:id:contemporarycuz:20190917160843p:plain

Database の設定

プロジェクトホームの左ペインから「Database」をクリックし「データベースの作成」をクリックします。

f:id:contemporarycuz:20190917161229p:plain

以下の設定値で Firestore を作成しました。セキュリティルールは個々の事情に合わせて選んでください。

  • セキュリティルール:テストモード
  • ロケーション:asia-northeast1

Storage の設定

プロジェクトホームの左ペインから「Storage」をクリックし、「スタートガイド」をクリックします。

f:id:contemporarycuz:20190917161958p:plain

セキュリティ保護ルールとロケーションはデフォルトのまま作成します。

一旦これで FIrebase 側の作業は終了です。

ローカル側での作業

Angular プロジェクトの作成〜ビルド

$ ng new deploy-test
? Would you like to add Angular routing? Yes
? Which stylesheet format would you like to use? (Use arrow keys)
❯ CSS 
  SCSS   [ https://sass-lang.com/documentation/syntax#scss                ] 
  Sass   [ https://sass-lang.com/documentation/syntax#the-indented-syntax ] 
  Less   [ http://lesscss.org                                             ] 
  Stylus [ http://stylus-lang.com                                         ]

プロジェクト直下に移動し、疎通確認します。

$ cd deploy-test
$ ng serve --open

一旦ビルドします。

$ ng build --prod

ツール類 のインストール(まだしていない場合)

Angular CLI

以下を実行します。

$ npm install -g @angular/cli --unsafe-perm
$ ng --version
Angular CLI: 8.3.4

Firebase Tools

以下を実行します。

$ npm install -g firebase-tools --unsafe-perm
$ firebase --version
7.3.2

Firebase へのデプロイ設定

以下を実行します。 今回は「Firestore」「Hosting」「Storage」を利用するので、それらにチェックを入れています。

$ firebase login
$ firebase init

     ######## #### ########  ######## ########     ###     ######  ########
     ##        ##  ##     ## ##       ##     ##  ##   ##  ##       ##
     ######    ##  ########  ######   ########  #########  ######  ######
     ##        ##  ##    ##  ##       ##     ## ##     ##       ## ##
     ##       #### ##     ## ######## ########  ##     ##  ######  ########

You're about to initialize a Firebase project in this directory:

  /Users/(...略...)/deploy-test

? Which Firebase CLI features do you want to set up for this folder? Press Space to select features, then Enter to confirm your choices. 
 ◯ Database: Deploy Firebase Realtime Database Rules
 ◉ Firestore: Deploy rules and create indexes for Firestore
 ◯ Functions: Configure and deploy Cloud Functions
 ◉ Hosting: Configure and deploy Firebase Hosting sites
❯◉ Storage: Deploy Cloud Storage security rules

プロジェクトセットアップでは、Firebaseの設定ファイルを指定します。 ここでは自動生成するために基本的にはデフォルト通りで設定しています。 ただし、注1〜注3では、デフォルトのままだと勝手に index.html を生成してしまうので、ビルドしたファイルの index.html に向くように設定します。 ここでは、「dist/deploy-test/index.html」を向くように設定し、overwriteされないようにしています。

=== Project Setup

First, let's associate this project directory with a Firebase project.
You can create multiple project aliases by running firebase use --add, 
but for now we'll just set up a default project.

? Please select an option: Use an existing project
? Select a default Firebase project for this directory: deploy-test-(略) (deploy-test)
i  Using project deploy-test-(略) (deploy-test)

=== Firestore Setup

Firestore Security Rules allow you to define how and when to allow
requests. You can keep these rules in your project directory
and publish them with firebase deploy.

? What file should be used for Firestore Rules? firestore.rules

Firestore indexes allow you to perform complex queries while
maintaining performance that scales with the size of the result
set. You can keep index definitions in your project directory
and publish them with firebase deploy.

? What file should be used for Firestore indexes? firestore.indexes.json

=== Hosting Setup

Your public directory is the folder (relative to your project directory) that
will contain Hosting assets to be uploaded with firebase deploy. If you
have a build process for your assets, use your build's output directory.

? What do you want to use as your public directory? dist/deploy-test  // ☆注1☆
? Configure as a single-page app (rewrite all urls to /index.html)? Yes  // ☆注2☆
? File dist/deploy-test/index.html already exists. Overwrite? No  // ☆注3☆
i  Skipping write of dist/deploy-test/index.html

=== Storage Setup

Firebase Storage Security Rules allow you to define how and when to allow
uploads and downloads. You can keep these rules in your project directory
and publish them with firebase deploy.

? What file should be used for Storage Rules? storage.rules

i  Writing configuration info to firebase.json...
i  Writing project information to .firebaserc...

✔  Firebase initialization complete!

Firebase へのデプロイ

$ firebase deploy

=== Deploying to 'deploy-test-(略)'...

i  deploying storage, firestore, hosting

(...略...)

✔  Deploy complete!

Project Console: https://console.firebase.google.com/project/deploy-test-()/overview
Hosting URL: https://deploy-test-().firebaseapp.com

Hosting URLにアクセスします。

f:id:contemporarycuz:20190917164546p:plain

これでデプロイまで行けました。

Angularでプロジェクトの作成からページ遷移の実装まで

最近 Angular をはじめました。

プロジェクトを作成してからページ追加、ページ遷移の実装までの流れを一旦整理しておきたいと思います。

実装

プロジェクトの作成

適当にプロジェクトを作ってプロジェクト直下に潜ります。
1つ目の質問に Yes と答えています。これするとページ遷移の実装に必要な app-routing.module.ts が作られます。
2つ目の質問はお好みで。

$ ng new my-router-app
? Would you like to add Angular routing? Yes
? Which stylesheet format would you like to use? (Use arrow keys)
❯ CSS 
  SCSS   [ https://sass-lang.com/documentation/syntax#scss                ] 
  Sass   [ https://sass-lang.com/documentation/syntax#the-indented-syntax ] 
  Less   [ http://lesscss.org                                             ] 
  Stylus [ http://stylus-lang.com                                         ] 

... 略 ...

$ cd my-router-app

コンポーネントの作成

コンポーネントを作っていきます。

$ ng generate component main
$ ng generate component page1

ルーティング設定

app-routing.module.ts にルーティング設定をします。

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { MainComponent } from './main/main.component'; // MainComponentをimport
import { Page1Component } from './page1/page1.component'; // Page1Componentをimport

const routes: Routes = [
  {path: '', component: MainComponent}, // MainComponentを追加
  {path: 'page1', component: Page1Component} // Page1Componentを追加
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

ng generate component をした時点で app.module.ts に以下のようにページが追記されていると思いますが、一応確認します。

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { MainComponent } from './main/main.component';
import { Page1Component } from './page1/page1.component';

@NgModule({
  declarations: [
    AppComponent,
    MainComponent, // MainComponent
    Page1Component // Page1Component
  ],
  imports: [
    BrowserModule,
    AppRoutingModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

デフォルトのサンプルページを消す

デフォルトで作られるサンプルページが邪魔なので、消します。

<router-outlet></router-outlet> // これだけ残す

疎通確認

ローカルでServe

$ ng serve

rootのページ f:id:contemporarycuz:20190915135428p:plain

Page1のページ f:id:contemporarycuz:20190915135508p:plain

ページ追加ができました。

Docker Registry と Repository の違いをめちゃくちゃわかりやすく説明してみた

Docker には Docker Registory(以下 レジストリ)と Repository(以下リポジトリ)の概念があります。

「レジストリ」のことを「リポジトリ」って普段あまり意識せずに使ったりしますが、全然違うものなのでしっかりと区別して理解しておきたいです。

まだ僕は Docker 初心者なので間違ってるかもしれません。コメントください。


目次

まずはふわっと理解

まず、 レジストリ は「コンテナイメージをホストするサーバ」のことを指します。Docker イメージを保管しておく場所です。

そして、 リポジトリ は「同じイメージ名だけど、異なるタグを持つイメージの集合」のことを指します。

以下では「リポジトリは機能的に似通ったイメージのコレクションで、同じ名前を持つが異なるバージョンがあって、タグによって個々のイメージは区別できる」と言及されています。

Repository is a collection of the functionally similar images, which share same name but may represent different versions/flavours of the same software. Images in the repository are distinguished by tags.

What is the difference between a Docker repository and an image?


絵に描いてみるとこんな感じです。

f:id:contemporarycuz:20190830010306p:plain

イメージ名に対応するリポジトリがあり、それらをレジストリがホストしているという構造になります。

実際にはレジストリとして Docker Hub やプライベートレジストリを利用するため、
<リポジトリ名> <レジストリホスト名>/<イメージ名>
となります。

例えば、my-private-registry/my-image とか。


手を動かして確認

ふわっと理解したら、実際に手を動かして確認してみます。

ローカルに持っているイメージにタグをつけていきます。 ここでは Azure Container Registry を利用する感じで書きますが、本筋には関係ないはずです。

# とりあえずタグをつける
$ docker tag my-local-image my-private-registry.azurecr.io/my-image:1.0.0

# プッシュするイメージ名は "同じ" で タグを変える
$ docker tag my-local-image my-private-registry.azurecr.io/my-image:1.1.0

# イメージ名が異なるリポジトリ名をつける
$ docker tag my-local-image my-private-registry.azurecr.io/my-image-another:1.2.0

次にリモートリポジトリにプッシュします。

$ docker push my-private-registry.azurecr.io/my-image:1.0.0

$ docker push my-private-registry.azurecr.io/my-image:1.1.0

$ docker push my-private-registry.azurecr.io/my-image-another:1.2.0

レジストリ 内の リポジトリ 一覧を取得します。

$ az acr repository list --name my-private-registry --output table

Result
------------------------
my-image
my-image-another

3つのイメージをプッシュしましたが、その内2つのイメージ名が同じなので、結果的にリポジトリは2つになっています。

最後にそれぞれのリポジトリのタグ一覧を確認してみます。

# リポジトリ "my-private-registry.azurecr.io/my-image" のタグ一覧を取得
$ az acr repository show-tags --name my-private-registry --repository my-image --output table

Result
--------
1.0.0
1.1.0

# リポジトリ "my-private-registry.azurecr.io/my-image-another" のタグ一覧を取得
$ az acr repository show-tags --name my-private-registry --repository my-image-another --output table

Result
--------
1.2.0

人と話をするときには ちゃんと レジストリ と リポジトリ を使い分けて話そうと思います。

Kubernetes の API Resource をふわっと理解する

Kubernetes上で扱われる情報(Pod, Service等)は api-server 上では API Resource として定義されています。
それに対して、実際にKubernetes上で動作しているリソース(というかプロセスと言ったほうがいいかもしれない)のことをオブジェクトと言います、たぶん。

API Resource には大きく5種類があります。
Kubernetes API Reference v1.15

リソースカテゴリ 概要
Workloads クラスタでコンテナを管理、実行するために使用するオブジェクト
Discovery & LB Podを外部からアクセス可能なロードバランサーにつなぐために使用するオブジェクト
Config & Storage アプリケーションに設定値を埋め込む、データをコンテナの外部で永続化するために利用するオブジェクト
Cluster クラスタ自体の構成方法を定義するオブジェクト
Metadata クラスタ内の他のリソースのふるまいを構成するオブジェクト

上記の定義でいまいちわからないのが Cluster と Metadata。

例を考えてみるとイメージはつくかな。

Cluster Resources のふわっとしたイメージ

Cluster Resources は Node, Namespace, ServiceAccountといったクラスタ自体の管理に必要なリソースのこと。

  • Node は コンテナをホストしてる物理的なマシンのこと(VMでもいいけど)。
  • Namespace は Kubernetes クラスタ内を論理的に分ける単位。Linux の Namespace とは別だよ。
  • ServiceAccount は クラスタ内のなんらかのプロセスが api-server にリクエスト投げるときに使うアカウント。api-server には認証認可の仕組みがあるのでリクエスト投げるならアカウントが必要になる。

Metadata Resources のふわっとしたイメージ

Metadata Resources は LimitRange, HorizontalPodAutoscaler といった、オブジェクトの制限やスケール、管理に関するリソースのこと。

  • LimitRange は性能の上限と下限を設定するリソース
  • HorizontalPodAutoscaler は Pod のレプリカ数をCPU負荷によってスケールさせるリソース

リソース(オブジェクト)の全体感はこんな感じで。

Mapping Data Flow(Azure Data Factory)使ってみた

だいぶ前になりますが、Azureもくもく会でLTさせていただいたので資料を共有します。
ADF Pipelineの中でデータ加工を簡単にGUIポチポチ操作だけでできる便利な機能です。
プレビュー機能なので本番ではまだまだ使えないとは思いますが、GAされたらすぐ使えるように今後もちょくちょく触っていこうと思います。

speakerdeck.com