コピペコードで快適生活

明日使えるソースを自分のために

TypeScript+webpack環境を作る - babel使う版

TypeScriptをはじめてみる - コピペコードで快適生活 の続き

必要なライブラリをインストール

npm install --save-dev webpack webpack-cli typescript babel-loader @babel/core @babel/preset-typescript
  • webpack:
    • モジュールバンドラー。
    • JavaScript等の複数のファイルを1つにまとめる。
    • loaderを組み込むことで、まとめる前に変換処理(ES2015→ES5など)を加えることができる。
  • webpack-cli:
    • webpackのcli
  • babel-loader:
    • webpackにbabelの変換処理を組み込むloader
    • babelは古いブラウザで動くJavaScriptに変換するツール群
  • @babel/core:
    • babelのコア機能
  • @babel/preset-typescript
    • TypeScript→JavaScriptの変換を行う
    • babelでの変換処理本体は、プラグインとして提供される
    • @babel/preset-env は最新のJavaScriptからの変換を行う

${APP_DIR}/package.json の更新

scriptsにビルドコマンドを追加する

{
  "scripts": {
    "watch": "webpack --watch",
    "build": "webpack --mode production"
  },
  "devDependencies": {
    "@babel/core": "^7.14.8",
    "@babel/preset-typescript": "^7.14.5",
    "babel-loader": "^8.2.2",
    "typescript": "^4.3.5",
    "webpack": "^5.45.1",
    "webpack-cli": "^4.7.2"
  }
}

${APP_DIR}/tsconfig.json の作成

TypeScriptをどのように変換するかを設定する

{
  "compilerOptions": {
    "sourceMap": true,
    "target": "ES5", // TSはECMAScript 5に変換
    "module": "ES2015" // TSのモジュールはES Modulesとして出力
  }
}
  • CommonJSのモジュール:
    • require/module.exportsで外部JSファイルを扱う
    • Node.jsが採用している
    • tsconfig.jsonのデフォルト
  • ES Modules:
    • import/exportで外部JSファイルを扱う
    • ES2015が採用している
    • webpackのTree Shaking(未使用のimportを振り落とす)が効く

${APP_DIR}/webpack.config.js の作成

webpackのバンドル設定を行う

const path = require('path')

module.exports = {
  // production:  改行やインデントを削除してJSファイル出力
  // development: ソースマップ有効でJSファイル出力
  // ただし `webpack --mode production` したときは production が有効になる
  mode: 'development',

  // 入力元の指定
  entry: {
    index: path.join(__dirname, '/src/index.ts'),
  },

  // 出力先の指定
  output: {
    path: path.join(__dirname, 'dist'),
    filename: '[name].js',
  },

  module: {
    rules: [
      {
        test: /\.ts$/,            // 拡張子 .ts のファイルを
        loader: 'babel-loader',   // babelでトランスパイルする
        options: {
          presets: ['@babel/preset-typescript']
        },
        exclude: /node_modules/,  // ただし外部ライブラリは除く
      },
    ],
  },

  // import './MyLib.ts' が 
  // import './MyLib' の書き方でOKになる
  resolve: {
    extensions: [
      '.ts', '.js',
    ],
  },
};

tsファイルを書いてみる

${APP_DIR}/src/index.ts

import { Animal } from './Animal';
let animal = new Animal("cat", "pipimi");
animal.say();

${APP_DIR}/src/Animal.ts

export class Animal {
  animaltype: string;
  name: string;

  constructor(animalType: string, name: string) {
    this.animaltype = animalType;
    this.name = name;
  }

  say() {
    console.log(`Hello. I am ${this.name} of ${this.animaltype}.`);
  }
}

ビルドする

npm run build

参考

TypeScriptをはじめてみる

TypeScriptの雰囲気を掴むために、5分でできるチュートリアルをやってみる。

環境の準備

PC環境は汚したくないので、dockerで環境を作る。

#{APP_DIR}/docker-compose.yml に以下を書く

version: '3'
services:
  node:
    image: node
    volumes:
     - "./:/var/app"
    tty: true

コンテナを起動してログインする

docker-compose up
docker-compose exec node /bin/bash

TypeScriptをインストール

cd /var/app
npm install -g typescript

TypeScriptを書いていく

#{APP_DIR}/greeter.ts を書いていく

// クラスの定義
class Student {
    // プロパティの宣言
    fullName: string;

    // コンストラクタ
    // "引数名: 型" で引数の型指定ができる 
    // 引数にpublicをつけることでプロパティとなる
    constructor(public firstName: string, public middleInitial: string, public lastName: string) {
        this.fullName = firstName + " " + middleInitial + " " + lastName;
    }
}

// インターフェースの定義
interface Person {
    firstName: string;
    lastName: string;
}

function greeter(person: Person) {
    return "Hello, " + person.firstName + " " + person.lastName;
}

// let user = { firstName: "Jane", lastName: "User"};
let user = new Student("Jone", "M.", "User");

document.body.innerHTML = greeter(user);

トランスパイルする

以下のコマンドでトランスパイルできる。 同じディレクトリにjsファイルができる。

tsc greeter.ts

参考:

Kubernetesの設定ファイルの書き方キホン

確認できる環境(minikube)の準備

$ brew install kubectl
$ kubectl version --client

$ brew install minikube
$ minikube version

minikube コマンド

minikube start   # 起動(デフォルトはDockerで起動)
minikube status  # 状態表示
minikube ssh     # ホストOSにログイン
minikube stop    # 停止

※minikubeを起動すると、~/.kube/config がよしなに変更されて、kubectlコマンドでminikube環境への接続が可能になる。

Pod

  • 1個以上のコンテナの集まり
  • 1Podに1コンテナ配置することが多い。
  • 複数のコンテナでストレージを共有するようなケースでは1Podに複数コンテナを配置する
  • Deploymentとセットで定義することが多いが、Pod単体を設定を書くこともできる。
  • https://kubernetes.io/ja/docs/concepts/workloads/pods/pod-overview/

Deployment

Deploymentの設定ファイル

apiVersion: apps/v1      # 固定値
kind: Deployment         # 固定値
metadata:
  name: nginx-deployment # Deployment名
  labels:
    app: nginx           # Podテンプレートと同じ値
spec:
  # レプリカ数
  replicas: 3

  # デプロイメントの履歴数
  # デフォルト値は10
  revisionHistoryLimit: 5

  # このDeployamentが管理するPodをどう見つけるかの定義
  # 基本はPodテンプレートの`labels`と同じにすれば良い
  selector:
    matchLabels:
      app: nginx

  # Podテンプレート
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx:1.7.9
          ports:
            - containerPort: 80 # コンテナが開けるポート

Deploymentの作成・確認・削除

$ kubectl apply -f nginx-deployment.yml        # 設定をもとにオブジェクトを作成する
$ kubectl get deployment                       # オブジェクトの一覧を表示する
$ kubectl describe deployment nginx-deployment # オブジェクトの詳細情報を表示する
$ kubectl delete -f nginx-deployment.yml       # オブジェクトを削除する

Service

Serviceの設定ファイル

kind: Service   # 固定値
apiVersion: v1  # 固定値
metadata:
  # Serviceの名前
  # 他のPodから `http://nginx-service` でアクセス可
  name: nginx-service
spec:
  # 接続タイプ
  # - ClusterIP クラスタ内部のみ接続可能(デフォルト値)
  # - NodePort クラスタ外から接続可能
  type: NodePort

  # どのPodを対象にするか
  selector:
    app: nginx

  # 公開するポート
  ports:
  - name: http       # 複数ポートを指定するときはname必須
    protocol: TCP
    port: 80         # 受け口ポート
    targetPort: 80   # 転送先ポート
  - name: https
    protocol: TCP
    port: 443        # 受け口ポート
    targetPort: 443  # 転送先ポート

Serviceの作成・確認・削除

$ kubectl apply -f nginx-service.yml        # 設定をもとにオブジェクトを作成する
$ kubectl get service                       # オブジェクトの一覧を表示する
$ kubectl describe service nginx-service    # オブジェクトの詳細情報を表示する
$ kubectl delete -f nginx-service.yml       # オブジェクトを削除する

アクセスできるURLの確認

$ minikube service nginx-service --url
http://192.168.64.2:32599

コンテナにログインする

以下のコマンドでPod一覧を表示する。

$ kubectl get pod
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-5d59d67564-2gzp2   1/1     Running   2          2d1h
nginx-deployment-5d59d67564-4mvjs   1/1     Running   2          2d1h
nginx-deployment-5d59d67564-wlglr   1/1     Running   2          2d1h

で、NAME値を指定してkubecltコマンドを実行することで、sshログインができる。

kubectl exec --stdin -tty nginx-deployment-5d59d67564-2gzp2 -- /bin/bas

参考

シェルで古いファイルを一括で消す

バックアップスクリプトでよくやるのだけど、毎回書き方を忘れているのでメモ。

# -execオプションを使う版
# {} が対象のファイルパスに置換されて実行される。
# -mtime +3 => 最終更新日時が、過去〜4(3+1)日前のファイルを表示する
find ${TARGET_DIR} -type f -mtime +3 -exec rm -f {};

# xargsを使う版
# こっちのほうが-execオプションより速い
find ${TARGET_DIR} -type f -mtime +3 | xargs rm -f

バックアップ数の世代制限を超えたら消す場合はこんな

cd ${BACKUP_DIR};
REVISION_COUNT=`ls | wc -l`;
if [ ${REVISION_COUNT} -gt 10 ];
then
  ls | head -1 | xargs -Rf rm
fi

シェルスクリプトのアタマに添えるおまじない

シェルスクリプトを書くときに、アタマに添えるおまじないをメモ。

#!/bin/sh

# set -e
# スクリプトの実行中にエラー(exit 0以外)が発生すると、そこでスクリプトが終了させる。
# というかつけてないと、エラーしても次の処理に進むから怖い。
# 
# set -u
# 未定義の変数を使用すると、そこでスクリプトが終了させる。
# 
# set -o pipefail
# パイプの途中でエラーが起きた場合もエラーが発生させる。
set -euo pipefail

# どのパスから実行しても、スクリプトのあるディレクトリにcdしてから実行する。
cd `dirname $0`

# 以下、メイン処理を書く

参考

proxy先がTCPコネクションを切ったときブラウザには何が返るか

ブラウザ → proxy(nginx) → origin(apache) の通信経路で、originがTCPコネクションを切った場合、proxyは50xを返す。proxy(nginx)にはこんなログが出る。

proxy_1  | 2021/07/01 13:15:38 [error] 25#25: *2 upstream prematurely closed connection while reading response header from upstream, client: 172.20.0.1, server: localhost, request: "GET /php/ HTTP/1.1", upstream: "http://172.20.0.2:80/", host: "localhost"
proxy_1  | time:01/Jul/2021:13:15:38 +0000  remote_addr:172.20.0.1  host:localhost  scheme:http req:GET /php/ HTTP/1.1  status:502  size:494    response_time:5.655referer:-    agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36 upstream_addr:172.20.0.2:80 upstream_cache_status:- upstream_response_time:5.656

ブラウザで、ERR_CONNECTION_CLOSEDが出る場合は、ブラウザとproxy間の通信が切れたもの。

MySQLのバッファプール使用状況を確認する

ダーティページの使用状況を確認したかったので。

mysql> SHOW GLOBAL STATUS LIKE 'InnoDB\_buffer\_pool%';
+-----------------------------------+---------------+
| Variable_name                     | Value         |
+-----------------------------------+---------------+
| Innodb_buffer_pool_pages_data     | 464754        |  # バッファプール内のデータ合計
| Innodb_buffer_pool_pages_dirty    | 0             |  # ダーティページ
| Innodb_buffer_pool_pages_flushed  | 51792309      |  # ディスクフラッシュしたページ数
| Innodb_buffer_pool_pages_free     | 0             |  # バッファプールの空き
| Innodb_buffer_pool_pages_misc     | 59534         |
| Innodb_buffer_pool_pages_total    | 524288        |  # バッファプール内のページ数
| Innodb_buffer_pool_read_ahead_rnd | 82900402      |
| Innodb_buffer_pool_read_ahead_seq | 41051358      |
| Innodb_buffer_pool_read_requests  | 2642185748634 |  # バッファプールから読んだページ数
| Innodb_buffer_pool_reads          | 1272273714    |  # ディスクからバッファプールにロードしたページ数
| Innodb_buffer_pool_wait_free      | 0             |
| Innodb_buffer_pool_write_requests | 320720943     |  # バッファプールに書いたページ数
+-----------------------------------+---------------+
12 rows in set (0.00 sec)

mysql> SHOW GLOBAL STATUS LIKE 'Innodb\_pages%';
+----------------------+------------+
| Variable_name        | Value      |
+----------------------+------------+
| Innodb_pages_created | 1073458    |  # バッファプールに作成したページ数
| Innodb_pages_read    | 6795625969 |
| Innodb_pages_written | 51793282   |  # ディスクフラッシュしたページ数
+----------------------+------------+
3 rows in set (0.00 sec)

参考