Kubernetesマニフェスト作成 - Webアプリケーション

| 18 min read
Author: noboru-kudo

ここまででローカル環境で開発する準備が整いました。
ここからは、実際に動くアプリケーションをローカル環境にデプロイしましょう。

このチュートリアルでは、一般的によくあるであろうシンプルなWebアプリケーションとバッチアプリケーションを例に見ていきます。
題材としてはタスク管理ツールとします。このツールの機能としては以下になります。

  • ユーザー向けに、Webブラウザからタスク登録、更新と表示機能(UI+API)
  • 管理者向けに、日次で前日完了したタスクをレポートする機能(バッチジョブ)

これらを2回に分けて実装していきます。今回は1つ目のWebアプリケーションの方を見ていきましょう。
以下のような構成になります。

WebアプリケーションはVue.jsで作成されたユーザーインターフェースです。
これがタスク管理API(task-service)を通じて、バックエンドのDynamoDBにタスク情報を登録、照会するものです。

Contents

事前準備#

これまでローカル環境で準備したものを全て使用します。未セットアップの場合は以下を参考にローカル環境の開発環境を整えてください。

なお、minikubeはDocker Desktopでも代用可能です。

また、UI/アプリケーションはNode.jsを利用します。こちらも別途インストールしてください。今回は現時点で最新の安定版であるv16.13.1を利用しています。

利用するKubernetesリソース#

さて、ここからすぐに作業に着手したいところですが、まずはアプリ開発で抑えておくべきKubernetesのリソース(オブジェクト)についての概要を説明します。
これまでも何度か出てきており、無意識に理解しているかもしれませんが、ここをきちんと理解するとできることの幅が広がります。
既に詳細を把握していて今更感がある場合はスキップしても構いません。

Service#

Serviceは一群のPodが安定して機能を提供するために、主に以下の仕組みが実装されています[1]

  • 静的エンドポイント提供:Pod群に対して静的なIPアドレス/ドメインを割り当てる
  • サービスディカバリー:バックエンドのPod群に対してトラフィックを負荷分散する(kube-proxy)
  • クラスタ外部からアクセス制御(ServiceType):NodePortやLoadBalancer等を利用してサービスをクラスタ外部に公開する[2]

これらは主に内部DNSサービスであるCoreDNS、ラベルセレクターによるルーティング先Podの動的管理、実際の負荷分散を担うkube-proxyによって実現されています。

具体的にはServiceの生成が検知されると、Kubernetes内では以下のような動きをします(Servicefooで3Podを管理する例)。

  1. ServiceのドメインをControl PlaneのCoreDNSにServiceのエントリ(Aレコード/SRVレコード)を追加する[3]
  2. Serviceのラベルセレクターからルーティング対象のPodをルックアップして、PodのIPアドレス等をEndpointとして登録する
  3. 各ノードに配置されているkube-proxy(Control Plane)は、Service/Endpointの情報からルーティングルール[4]を更新する(実際にクライアントからリクエストがあった場合は、これを利用して各Podに負荷分散)。

この仕組みは初回のみでなく、関連するリソースが追加、変更、削除された場合は、この動作が再度実施され、常に最新状態(期待する状態)が保たれるようになっています(Control LoopとかReconciliation Loopと呼ばれます)。

Serviceのもう1つ重要な役割として、正常なPodのみでルーティングルールを維持する機能があります。例えば、Podの1つに障害が発生した場合は以下のようなイメージで動きます。

このように、ServiceリソースはPodに定義されたReadinessProbeのヘルスチェックの結果を監視し、異常を検知したPodはルーティングルールから除外されます。
もちろんその後Podが復旧した場合は逆の動きをします。

Deployment#

Deploymentはアプリケーションの更新を宣言的に行うためのリソースです[5]

DeploymentがなくてもPod単体でデプロイすることは可能ですが、新バージョンをリリースする場合にどうすればよいでしょうか?
最もシンプルな方法は旧バージョンを削除して新バージョンをデプロイすれば良いですが、その場合はダウンタイムは避けられません。
これを防ぐためには、Blue-Greenデプロイを使って旧バージョンと並行して新バージョンをリリースし、正常に動作確認が取れたら旧バージョンを削除する等の工夫が必要になるでしょう。
また、アプリケーションが複数レプリカで動作させる場合には、一定数のレプリカを維持するためにさらに複雑なデプロイ作業が必要になるでしょう。

Deploymentを導入することで、マニフェストに期待する状態を記載するだけで、それ以降のオペレーションはKubernetesに任せることができます[6]

  • レプリカ管理:Podで必要なレプリカ数を維持する。内部的にはReplicaSetを使用する。
  • デプロイ:デプロイ戦略として順次更新(RollingUpdate)/と再作成(Recreate)を提供する。
  • リビジョン管理:デプロイしたアプリケーションのバージョン管理を行い、ロールバック・デプロイ中断等の機能を提供する。

以下はRollingUpdateでアプリケーションをバージョンアップ(v1->v2)するイメージです。

図では分かりにくいですが、Deploymentで新しいバージョンをデプロイすると、新バージョンのPodが少しずつ(デフォルトはレプリカ数の25%)起動し、正常実行が確認されると今度は旧バージョンのPodがアンデプロイされていくようになります[7]

もう1つのデプロイ戦略で選択できるRecreateは、旧バージョンのPodを全て削除した後で、新バージョンのデプロイを開始します。
この場合はダウンタイムは発生しますが、アプリが複数バージョン並行で実行できない場合はこちらを選択するとよいでしょう(デフォルトはRollingUpdateのため明示的に指定が必要です)。

DeploymentはこのReplicaSetを履歴として管理していますので、過去のデプロイ履歴参照やロールバックは以下のコマンドで実行することが可能です。

# デプロイ履歴を一覧表示
kubectl rollout history deploy <deployment-name>
# 特定のリビジョンのデプロイ内容を詳細表示
kubectl rollout history deploy <deployment-name> --revision <rev-number>
# 特定のリビジョンのデプロイにロールバック
kubectl rollout undo deploy <deployment-name> --to-revision <rev-number>

ConfigMap#

ConfigMapはアプリケーション内の設定を外部リソースとして分離します。
設定情報は環境によって異なるものが多いですが、アプリケーション内に持たせるとその都度ビルドが必要になります。
ConfigMapを使うことで、同一イメージで、複数環境に応じて設定を切り替えることが容易になります。

ConfigMapはキーバリューの形式で記述し、環境変数またはボリュームとしてPodにマウントして利用することが一般的です。
アプリケーションで使う設定ファイルをそのまま値として記述し、これをそのままボリュームとしてマウントして、アプリケーションで参照するやり方はよく使われます。

例えば、Spring Bootのapplication.ymlの場合は以下のようになります。

apiVersion: v1
kind: ConfigMap
metadata:
name: spring-boot-sample-config
data:
application.yml: |
spring:
datasource:
url: jdbc:postgresql://my-postgresql:5432/sample
logging:
level:
com.mamezou.sample: debug

これはキーにファイル名としてapplication.yml、バリューとしてSpring Bootの設定を記述しておきます。
そして、これをPodにボリュームとしてマウントすれば、Spring Bootにこの設定をapplication.ymlファイルとして読み込ませることが可能になります。

今回は利用しませんが、多くのアプリケーションは通常は認証用パスワードやAPIトークン等、センシティブ情報も設定情報として持っています。
このようなリソースをConfigMapに持たせてしまうと、ConfigMapのGit管理方法やRBAC、実際の値の暗号化等の情報管理が煩雑になります。
この場合は、ConfigMapではなくSecretリソースを使ってください(Vault等外部のプロダクトを使う場合は除く)。
Secretを使うことで、Kubernetes内(etcd)での暗号化や、ボリュームマウントのインメモリ(tempfs)化等の多くのセキュリティ上のメリットを享受することができます[8]

環境セットアップ#

では、ここからローカル環境でアプリケーションをデプロイしていきましょう。
本チュートリアルではアプリケーションの実装自体が目的ではありませんので、ソースコードについては事前にGitHubに用意しました。
以下のリポジトリをクローンしてローカル環境に配置してください。

appディレクトリ配下が対象のソースコードになります。
今回利用する部分は以下のとおりです(それ以外については無視してください)。

.
├── apis
│   └── task-service -> API(Node.js+Express)ソースコード
├── k8s
│   └── v1 -> Kubernetesマニフェスト(ローカル向け)
└── web -> UIリソース(Vue.js)

アプリケーションマニフェスト作成前に、LocalStack上のAWSリソース作成しておきましょう。
こちらを済ませた方は、既にローカル環境でLocalStackが動作しているはずです。

今回のアプリケーションで使用するDynamoDBの初期化スクリプトを作成しましょう。
app/k8s/v1/localstackディレクトリを作成し、localstack-init-scripts-config.yamlを配置しましょう。
以下の内容で、ConfigMapのリソースを記述してください。

apiVersion: v1
kind: ConfigMap
metadata:
name: localstack-init-scripts-config
data:
# AWS Credential情報初期化
01-credential.sh: |
#!/bin/bash
aws configure set aws_access_key_id localstack
aws configure set aws_secret_access_key localstack
aws configure set region local
export LOCALSTACK_ENDPOINT=http://localhost:4566

# DynamoDBテーブル作成
02-create-task-table.sh: |
#!/bin/bash
aws dynamodb create-table --table-name tasks \
--key-schema AttributeName=task_id,KeyType=HASH \
--attribute-definitions file:///docker-entrypoint-initaws.d/02-task-attr-definitions.json \
--global-secondary-indexes file:///docker-entrypoint-initaws.d/02-task-gsi.json \
--billing-mode PAY_PER_REQUEST \
--endpoint ${LOCALSTACK_ENDPOINT}
aws dynamodb list-tables --endpoint ${LOCALSTACK_ENDPOINT} --region local

02-task-attr-definitions.json: |
[
{
"AttributeName": "task_id",
"AttributeType": "S"
},
{
"AttributeName": "start_at",
"AttributeType": "N"
},
{
"AttributeName": "updated_at",
"AttributeType": "N"
},
{
"AttributeName": "user_name",
"AttributeType": "S"
},
{
"AttributeName": "status",
"AttributeType": "S"
}
]

02-task-gsi.json: |
[
{
"IndexName": "user_index",
"KeySchema": [
{
"AttributeName": "user_name",
"KeyType": "HASH"
},
{
"AttributeName": "start_at",
"KeyType": "RANGE"
}
],
"Projection": {
"ProjectionType": "ALL"
}
},
{
"IndexName": "status_index",
"KeySchema": [
{
"AttributeName": "status",
"KeyType": "HASH"
},
{
"AttributeName": "updated_at",
"KeyType": "RANGE"
}
],
"Projection": {
"ProjectionType": "ALL"
}
}
]

前回と違ってだいぶ複雑になりましたが、やっていることはDynamoDBのテーブルとインデックス(Global Secondary Index)を作成しているだけです。
スキーマ定義が若干複雑になりましので、別途JSONファイルとして作成し、初期化スクリプト(02-create-task-table.sh)はそこからテーブルやインデックスを作成するようにしています。

ConfigMapで言及した通り、ここではConfigMap内にファイル自体(シェルやJSON)を値として設定していますので、これをボリュームとしてPodにマウントすれば、LocalStackは初期化スクリプトとして認識します。

これをローカル環境のKubernetesに投入しましょう。

kubectl apply -f k8s/v1/localstack/localstack-init-scripts-config.yaml

このスクリプトファイルを認識させるために、LocalStackを再起動しましょう。Helmチャートの中でLocalStackはDeploymentとして作成されています。
Deployment配下のPodを全て再起動するには、以下のコマンドを実行します。

kubectl rollout restart deploy localstack

実際に作成されたかについては、LocalStackでの動作確認を参考にチェックしてみてください。
LocalStack上のAWSリソース作成については、これで完了です。

マニフェストファイル作成#

それではKubernetesのマニフェストファイルを作成していきましょう。
今回作成するリソースは以下です。

  • ConfigMap: APIの設定情報
  • Deployment: API(task-service)本体
  • Service: APIで管理するPod群のエンドポイント
  • Ingress: クラスタ外からAPIへのルーティング

なお、UIリソース(webディレクトリ配下)については、ここではコンテナ化しませんでした。
もちろん、これについてもローカルのKubernetes上でコンテナとして動作させることができます。
しかし、UIは見た目や振る舞いを試すために、トライ&エラーのフィードバック速度が重要です。
一般的にUIフレームワーク(この場合はVue CLI)の開発支援機能にはこの辺りが備わっており、これを利用する方が開発効率が良い場合が多いです。[9]
このため、UIについてはここではVue CLIの開発支援機能を用いてKubernetesとは別プロセスで動作させます[10]

完成形のイメージは以下のようになります。

ConfigMap#

それでは、ConfigMapから作成しましょう。
app/k8s/v1/task-serviceを作成し、configmap.yamlを配置しましょう。
こちらはアプリケーションの設定を記述します。以下のようになります。

apiVersion: v1
kind: ConfigMap
metadata:
name: task-service-config
data:
STAGE: localstack
NODE_ENV: development
TZ: Asia/Tokyo
TASK_TABLE_NAME: tasks
AWS_ENDPOINT: http://localstack:4566
AWS_DEFAULT_REGION: local
AWS_ACCESS_KEY_ID: localstack
AWS_SECRET_ACCESS_KEY: localstack

アプリケーションで利用するもののほかに、AWS関連の認証情報を設定しました。今回はLocalStackのためAWS認証情報はLocalStackの初期化スクリプトに合わせます(アクセスキー、シークレット等は任意の値で構いません)。
アプリケーションはNode.jsのため、これらをprocess.env.xxxxxxで参照できるようにしたいところです(後述)。

Deployment#

続いてDeploymentの方に入ります。同ディレクトリ内にdeployment.yamlを作成しましょう。

apiVersion: apps/v1
kind: Deployment
metadata:
name: task-service
spec:
replicas: 2
# ReplicaSetのラベルセレクター
selector:
matchLabels:
app: task-service
template:
metadata:
# Podのラベル
labels:
app: task-service
spec:
containers:
- name: task-service
# アプリケーションコンテナ
image: task-service
# LocalなのでImagePullはしない
imagePullPolicy: Never
# Podの公開ポート
ports:
- name: http
containerPort: 3000
# ConfigMapから環境変数を指定
envFrom:
- configMapRef:
name: task-service-config
# 各種ヘルスチェック
readinessProbe:
httpGet:
port: 3000
path: /health/readiness
livenessProbe:
httpGet:
port: 3000
path: /health/liveness
startupProbe:
httpGet:
port: 3000
path: /health/startup

重要な点については上記のコメントに記載していますが、2点着目してほしい部分があります。

1点目はenvFromの部分です。
LocalStackの初期化スクリプトは、ファイル自体をマウントしましたが、ここではConfigMapの内容をそのままコンテナの環境変数に取り込んでいます。
こうすることで、ConfigMapがそのままコンテナの環境変数として取り込むことができ、アプリケーション内ではprocess.env.STAGEのようにしてConfigMapの内容を参照することが可能になります。
今回はConfigMap全てを取り込みましたが、以下のように個別の値として環境変数に取り込むことも可能です。

    spec:
containers:
- name: task-service
# 省略
env:
- name: NODE_ENV
valueFrom:
configMapKeyRef:
name: task-service-config
key: NODE_ENV

2点目はreadinessProbe/livenessProbe/startupProbeの部分です。
ReadinessProbeはServiceのところで触れましたが、指定したヘルスチェックがしきい値(デフォルトは10秒間隔で3回)を超えて失敗すると、ルーティングルールより除外されます。
LivenessProbeのヘルスチェックも似ていますが、しきい値(デフォルトはReadinessProbeと同じ)を超えて失敗すると、コンテナが再起動されます。メモリリーク等はこれで(暫定ではありますが)回復できるでしょう。

StartupProbeは比較的新しいもの(v1.18からデフォルト有効)で、起動の遅いアプリケーションの場合、起動前にLivenessProbeによる再起動ループが発生することがあります[11]
StartupProbeは起動時のみにチェックされ、これが成功した後で、ReadinessProbe/LivenessProbeの実行が開始されるため、このような状況を回避することができます[12]

これらのヘルスチェックはKubernetesを正しく運用する上でとても重要です。詳細は公式ガイドを参照してください。

Service#

そして次はServiceです。同ディレクトリ内にservice.yamlを作成しましょう。
こちらは最もシンプルな最小構成になります。

apiVersion: v1
kind: Service
metadata:
name: task-service
labels:
app: task-service
spec:
selector:
app: task-service
ports:
- port: 3000
targetPort: http

ラベルセレクターでapp: task-serviceとし、先程Deploymentで指定したPodのラベルと合わせます。
こうすることで、このServiceはDeploymentで作成された2つのPodに対して、負荷分散してルーティングを行うようになります。

portsではこのServiceが公開するポート番号を指定します。こちらはPodに合わせて3000番ポートを指定しました。
targetPorthttpとしています。ここにはPod側のポートを指定しますが、Deploymentで指定したportsnameを指定することもできます(Named Portと言われます)。
こうすることで、Serviceはルーティングする対象のポートの名前だけ知っていれば良くなるため、Podとの結合度を下げることができます(具体的なPodのポート番号は知る必要がない)。

Ingress#

最後にIngressで、クラスタ外部からのリクエストを受け付けるようにします。
app/k8s/v1/ingressを作成し、ingress.yamlを配置しましょう。
こちらも非常にシンプルです。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
spec:
ingressClassName: nginx
rules:
- host: task.minikube.local
http:
paths:
- backend:
service:
name: task-service
port:
number: 3000
path: /api
pathType: Prefix

上記はminikubeを前提としているものです。
http://task.minikube.local/api へのアクセスについてAPIのServiceにルーティングするように指定しています。
Docker Desktopの場合は、localhostへのアクセスのためhost部分を削除してください(任意のホスト名が許可されます)。

アプリケーションのデプロイ#

では、ここまで作成したら実際にローカル環境のKubernetesで動かしてみましょう。
ここまでで、app/k8s/v1ディレクトリ配下は以下のようになっているはずです。

k8s
 └── v1
     ├── ingress
     │   └── ingress.yaml
     ├── localstack
     │   └── localstack-init-scripts-config.yaml -> 環境セットアップで反映済み
     └── task-service
         ├── configmap.yaml
         ├── deployment.yaml
         └── service.yaml

今回はkubectl applyではなくSkaffoldを使ってデプロイしましょう。

Skaffoldについては事前準備でこちらでインストール済みかと思います。
セットアップ時に実施したように、Skaffoldの初期化コマンドでskaffold.yamlを作成しましょう。
appディレクトリ上で以下を実行しましょう。

skaffold init --artifact=apis/task-service/Dockerfile.local=task-service \
--kubernetes-manifest=k8s/v1/task-service/*.yaml \
--kubernetes-manifest=k8s/v1/ingress/*.yaml \
--force

実行が終わると、app直下にskaffold.yamlというファイルが作成されているはずです。
以下のような内容になります。

apiVersion: skaffold/v2beta26
kind: Config
metadata:
name: app
build:
artifacts:
- image: task-service
context: apis/task-service
docker:
dockerfile: Dockerfile.local
deploy:
kubectl:
manifests:
- k8s/v1/task-service/*.yaml
- k8s/v1/ingress/*.yaml

buildステージでapis/task-service配下のDockerfile.localからイメージをビルドし、deployステージでkubectlでマニフェストをKubernetesに適用するようになっていることが分かります。

今回はビルドスピードをあげるためにdockerfileにローカル専用のDockerfileのDockerfile.localを指定しています[13]

実行する前に、事前にapp/apis/task-service配下に移動して依存モジュールをインストールしてください。これらはコンテナビルド時にコピーされて再利用されます。

npm install

それでは、APIをデプロイしましょう。appディレクトリ直下に戻って、以下のSkaffoldコマンドを実行します。

skaffold dev

コンテナビルドとKubernetesへのデプロイが始まっていることが分かります。
コンソール上でデプロイが終わったことを確認したら、別のターミナルを開いてkubectlで実際にデプロイされたものを確認してみましょう(skaffold devコマンドのターミナルは、Ctrl+Cを押すとアンデプロイされてしまいますので、注意してください)。

kubectl get deploy,rs,pod,cm,svc,ing

以下関連のある部分のみ抜粋します。

NAME                           READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/task-service   2/2     2            2           2m7s

NAME                                      DESIRED   CURRENT   READY   AGE
replicaset.apps/task-service-6c897c899b   2         2         2       2m7s

NAME                                READY   STATUS    RESTARTS   AGE
pod/task-service-6c897c899b-5z5f4   1/1     Running   0          2m7s
pod/task-service-6c897c899b-qpqw5   1/1     Running   0          2m7s

NAME                                       DATA   AGE
configmap/task-service-config              8      2m7s

NAME                   TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                         AGE
service/task-service   ClusterIP   10.111.193.252   <none>        3000/TCP                        2m7s

NAME                                    CLASS   HOSTS                 ADDRESS     PORTS   AGE
ingress.networking.k8s.io/app-ingress   nginx   task.minikube.local   localhost   80      2m7s

Deploymentから2つのPodのレプリカが作成され、それをReplicaSet/Serviceのラベルセレクターにより管理されています。
ここでは実施しませんが、kubectl describeで各リソースの詳細が見れますので、実際に確認してみると良いでしょう。

また、以下のコマンドで、実際にAPIにアクセスしてみましょう。

# minikube
curl -v task.minikube.local/api/tasks?userName=test
# docker desktop
# curl -v localhost/api/tasks?userName=test

ここでは200レスポンスが返ってきていれば問題ありません。
このAPIは、後続の作業でも引き続き使用しますので、このままの状態にしておいてください。

動作確認#

UIリソース(web)#

最後にUIを起動して、先程デプロイしたAPIに接続しましょう。
まずは、webディレクトリに移動して関連モジュールをインストールしましょう。

# app/webディレクトリ直下
npm install

次にUIからAPIへのアクセス方法を確認します。
web/vue.config.jsでUIからAPIへのアクセスのエンドポイントを指定する設定があります。
ここでminikubeの場合は、Ingressアドオンで指定したドメイン[14]、Docker Desktopの場合はlocalhostを指定してください。

module.exports = {
devServer: {
port: 8080,
proxy: {
"/api": {
// for minikube
target: "http://task.minikube.local",
// for docker-desktop
// target: "http://localhost",
changeOrigin: true,
},
},
},
};

最後に以下のコマンドを実行すれば、ローカル環境でUIを起動(開発モード)できます。

npm run serve

Vue.jsのリソースが開発モードでビルドされ、デフォルトの8080番ポートで公開されます(Ctrl+Cを押すと終了します)。
ブラウザからhttp://localhost:8080にアクセスしてUIが表示されることを確認しましょう。
表示されたら、任意のユーザー名を入力し、タスク管理ツールを起動します。その後、UI上でタスクの登録、表示、完了更新ができれば動作確認は終了です。

この状態になると、UI/APIともにファイル変更監視がされています。ソースコード修正をすると、すぐに実際のアプリケーションにも反映されます。
実際にソースコードを変更し、変更内容が反映できることを確認してみてください。

また、kubectlで先程デプロイしたものを見ると、以下のようにRollingUpdateが実行されていることが確認できるはずです。

まとめ#

ここでは、ローカル環境のKubernetesで、以下のことを実施してきました。

  • 仮想のAWSリソースとしてLocalStack(DynamoDB)を使用
  • タスク管理APIとしてDeployment/ConfigMap/Serviceを作成
  • 外部からのAPIのルーティングにIngress作成(NGINX Ingress Controllerを利用)
  • SkaffoldでKubernetesリソースをデプロイ
  • Kubernetesとは別プロセスでUIを起動し、ブラウザから動作確認

また、Skaffoldにより、コンテナビルドやKubernetesマニフェストの反映が自動化されていることも確認しました。
クラウド環境がなくとも、ここまでのレベルでローカルでKubernetesの環境で開発ができることが実感できたかと思います。

次回は、引き続きバッチアプリケーションの作成に入っていきます。


  1. Serviceの詳細はKubernetesの公式ドキュメントを参照してください。 ↩︎

  2. 今回はIngressを使用するため、ここでは触れませんが、これを利用することで様々な形でクラスタ外部からのリクエストに応えることができます。詳細はこちらを参照してください。 ↩︎

  3. これについてはLocalStack構築時の動作確認でも触れています。 ↩︎

  4. kube-proxyで使われる負荷分散は、デフォルトではLinuxのiptablesが使われており、ランダムアルゴリズムでルーティングされます。 ↩︎

  5. 他にもStatefulSetやDaemonSetが存在します。詳細はこちら(StatefulSet)こちら(DaemonSet)を参照してください。 ↩︎

  6. 一般的にPod単体でデプロイすることは、デバッグ等の一時的な利用を除いてまずありません。
    Deploymentは主に以下の機能を提供します。 ↩︎

  7. RollingUpdateは新バージョンが正常に起動してから、旧バージョンを終了するように動作しますので、一時的に指定したレプリカ数を超えるPod(新+旧)が起動することになります。多くのメモリやCPUを必要とするPodでRollingUpdateをする場合は、ノードのキャパシティに余裕をもたせる必要があります。 ↩︎

  8. とはいえ、kubectlでSecretを参照(kubectl get secret -o yaml <secret-name>)し、値をbase64デコードすれば中身が見れますので、SecretリソースはRBACでアクセス不可とするのが望ましいでしょう。 ↩︎

  9. Vue.jsに限らず昨今のUI向けのフレームワークはローカル向けの開発支援機能が完備されているため、これをそのまま利用した方が良いと思います。 ↩︎

  10. 商用環境においてもUIはコンテナ化せずに、CDNやホスティングサービス等を使うことの方が多いかと思います。 ↩︎

  11. 以前は再起動ループに陥らないようにLivenessProbe/ReadinessProbeのinitialDelaySecondsで調整していまいた。 ↩︎

  12. 今回作成したアプリケーションは高速に起動するため、StartupProbeは指定しなくても問題はありません。 ↩︎

  13. 商用環境向けにはWebpackでのビルドを用意していますが、ローカル環境で都度実行するのは時間がかかるため、ts-nodeコマンドから実行しています。 ↩︎

  14. minikubeの導入のこちらで設定しているドメインです。 ↩︎