- 投稿日:2021-08-15T15:53:31+09:00
Route53, GAE, React, FastAPIを用いて簡単なWebアプリを作製する 【中編】
なんの記事? 以下の記事の後編にあたります。 手順 残りの手順として フロントエンド 結合 デプロイ が存在します。が、その前に docker-compose でバックエンドとフロントエンドの環境を整えます。 構成 今回は以前にbackendのリポジトリを作成してしまったので、submoduleでバックエンドを引っ張ってきます。 . ├── README.md ├── docker-compose.prod.yml ├── docker-compose.yml ├── backend │ ├── Dockerfile │ ├── README.md │ ├── app │ ├── backend │ ├── pytest.ini │ ├── requirements.dev.txt │ ├── requirements.txt │ └── tests └── frontend ├── Docekrfile.prod ├── Dockerfile.dev ├── README.md ├── node_modules ├── package.json ├── public ├── src └── yarn.lock リポジトリは以下になります。 開発環境用のdocker-compose.yml 最終的に以下のようになりました。 docker-compose.yml services: backend: tty: true build: context: ./backend dockerfile: Dockerfile volumes: - ./backend/:/backend/ command: uvicorn app.main:app --reload --host 0.0.0.0 --port 8000 --log-level trace ports: - 8000:8000 frontend: build: context: ./frontend dockerfile: Dockerfile.dev command: yarn start volumes: - ./frontend:/usr/src/app ports: - "3000:3000" docker-compose up --buildを行いlocalhost:8000, localhost:3000 を見に行くことで、それぞれ起動していることが確認できます。 また、volumes でマウントを行っているので、docker-compose up --build -d で立ち上げたあと、開発しながら localhost:3000 を見に行くことで、開発を進めることが可能です。 開発を終えるときは docker-compose downをしておきましょう。 本番環境用のdocker-compose.prod.yml 本番環境用ではnginxを用いてフロントが表示されるように変更します。 docker-compose.prod.yml services: backend: tty: true build: context: ./backend dockerfile: Dockerfile volumes: - ./backend/:/backend/ command: uvicorn app.main:app --reload --host 0.0.0.0 --port 8000 --log-level trace ports: - 8000:8000 frontend: build: context: ./frontend dockerfile: Dockerfile.prod volumes: - ./frontend:/usr/src/app ports: - "80:80" 本番用のフロントは以下のようになります。 ./frontend/Dockerfile.prod FROM node:latest AS builder WORKDIR /usr/src/app COPY . . RUN npm install RUN npm run build FROM nginx:latest RUN rm -r -f /usr/share/nginx/html COPY --from=builder /usr/src/app/build /usr/share/nginx/html nginx経由の表示については、こちらを参考にしました。 docker-compose -f docker-compose.prod.yml up -d --build を行うことで、 localhostでのフロント表示が確認できます。 フロントエンド実装 フロントエンド実装に移ります。前回実装したAPIから、結果を取得する関数fetchPapers、またpaperをレンダリングするPaperコンポーネントと、Paper一覧を表示するPapersを実装します。 fetchPapers.js import axios from 'axios'; import DEFAULT_API_LOCALHOST from '../urls'; export const fetchPapers =() => { return axios.get(DEFAULT_API_LOCALHOST) .then(res => { return res.data }) .catch((e) => console.error(e)) } DEFAULT_API_LOCALHOST は前回実装したAPIのエンドポイント、すなわちhttp://localhost:8000/api/papers/になります。 index.js const DEFAULT_API_LOCALHOST = 'http://localhost:8000/api/papers/' export default DEFAULT_API_LOCALHOST; 仮置で、fetchPapers関数を用いて、APIの結果が帰ってくるかどうかをconsole上で見てみます。 src/pages/Papers.js import React, { Fragment, useEffect } from 'react'; // apis import Paper from '../components/Paper'; import { fetchPapers } from '../apis/fetchPapers'; export const Papers = () => { useEffect(() => { fetchPapers() .then((data) => console.log(data) ) }, []) return ( <Fragment> Paper一覧 </Fragment> ) } export default Papers; トップページでPapersをレンダし、ブラウザ上でログを見てみます。 NetWorkErrorで怒られてしまっています。networkのログを見てみると バックエンド側のCORS設定に問題があるようです。 を参考に、バックエンドを修正します。 backend/app/main.py import uvicorn from fastapi import FastAPI from starlette.middleware.cors import CORSMiddleware from backend.arxiv_api import ArxivApiClass from backend.extractor import Extractor app = FastAPI() app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"] ) arxiv_api = ArxivApiClass() extractor = Extractor() # ... submodule側で更新を行い、mainブランチにマージしたので、その反映を行います。 (base) ➜ arxiv-checker git:(feature/createPaperComponent) ✗ git submodule foreach git pull origin main Entering 'backend' remote: Enumerating objects: 12, done. remote: Counting objects: 100% (12/12), done. remote: Compressing objects: 100% (3/3), done. remote: Total 8 (delta 4), reused 7 (delta 4), pack-reused 0 Unpacking objects: 100% (8/8), done. From github.com:izuna385/arxiv-checker-backend * branch main -> FETCH_HEAD c37561e..6f5d886 main -> origin/main Updating c37561e..6f5d886 Fast-forward README.md | 4 ++-- app/main.py | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) (base) ➜ arxiv-checker git:(feature/createPaperComponent) ✗ docker-compost up --build で再度開発環境をビルドした後、localhost:3000番を見に行きます。 バックエンドから論文一覧を取得できていることが分かります。 useState, useEffectを用いたレンダリング バックエンドからの結果を実際にレンダリングする実装を次に行います。 Papers.js import React, { Fragment, useEffect, useState } from 'react'; // apis import Paper from '../components/Paper'; import { fetchPapers } from '../apis/fetchPapers'; export const Papers = () => { const[allPapersData, setAllPapersData] = useState([]); useEffect(() => { fetchPapers() .then(data => setAllPapersData(data.papers)) }, []) return ( <Fragment> {console.log(allPapersData)} <ul> {allPapersData.map((data) => ( <Paper paperData={data}/> ))} </ul> </Fragment> ) } export default Papers; allPapersDataを空の初期値で定義し、そこにバックエンドからの結果を格納しています。 ブラウザ上では、バックエンドの返却結果のリストの各要素が、Paperコンポーネントとして表示されます。 ここまでで、バックエンドとフロントエンドの結合までを完了しました。 動作を確認する場合は、リポジトリからcloneし、docker-compose up --buildで確認可能です。 次回 デプロイについてやっていければと思います。 リポジトリ 参考文献 React+Docker+DockerComposeの開発環境の構築について説明
- 投稿日:2021-08-15T15:53:31+09:00
Route53, GCE, React, FastAPIを用いて簡単なWebアプリを作製する 【中編】
なんの記事? 以下の記事の中編にあたります。 手順 残りの手順として フロントエンド 結合 デプロイ が存在します。が、その前に docker-compose でバックエンドとフロントエンドの環境を整えます。 構成 今回は以前にbackendのリポジトリを作成してしまったので、submoduleでバックエンドを引っ張ってきます。 . ├── README.md ├── docker-compose.prod.yml ├── docker-compose.yml ├── backend │ ├── Dockerfile │ ├── README.md │ ├── app │ ├── backend │ ├── pytest.ini │ ├── requirements.dev.txt │ ├── requirements.txt │ └── tests └── frontend ├── Docekrfile.prod ├── Dockerfile.dev ├── README.md ├── node_modules ├── package.json ├── public ├── src └── yarn.lock リポジトリは以下になります。 開発環境用のdocker-compose.yml 最終的に以下のようになりました。 docker-compose.yml services: backend: tty: true build: context: ./backend dockerfile: Dockerfile volumes: - ./backend/:/backend/ command: uvicorn app.main:app --reload --host 0.0.0.0 --port 8000 --log-level trace ports: - 8000:8000 frontend: build: context: ./frontend dockerfile: Dockerfile.dev command: yarn start volumes: - ./frontend:/usr/src/app ports: - "3000:3000" docker-compose up --buildを行いlocalhost:8000, localhost:3000 を見に行くことで、それぞれ起動していることが確認できます。 また、volumes でマウントを行っているので、docker-compose up --build -d で立ち上げたあと、開発しながら localhost:3000 を見に行くことで、開発を進めることが可能です。 開発を終えるときは docker-compose downをしておきましょう。 本番環境用のdocker-compose.prod.yml 本番環境用ではnginxを用いてフロントが表示されるように変更します。 docker-compose.prod.yml services: backend: tty: true build: context: ./backend dockerfile: Dockerfile volumes: - ./backend/:/backend/ command: uvicorn app.main:app --reload --host 0.0.0.0 --port 8000 --log-level trace ports: - 8000:8000 frontend: build: context: ./frontend dockerfile: Dockerfile.prod volumes: - ./frontend:/usr/src/app ports: - "80:80" 本番用のフロントは以下のようになります。 ./frontend/Dockerfile.prod FROM node:latest AS builder WORKDIR /usr/src/app COPY . . RUN npm install RUN npm run build FROM nginx:latest RUN rm -r -f /usr/share/nginx/html COPY --from=builder /usr/src/app/build /usr/share/nginx/html nginx経由の表示については、こちらを参考にしました。 docker-compose -f docker-compose.prod.yml up -d --build を行うことで、 localhostでのフロント表示が確認できます。 フロントエンド実装 フロントエンド実装に移ります。前回実装したAPIから、結果を取得する関数fetchPapers、またpaperをレンダリングするPaperコンポーネントと、Paper一覧を表示するPapersを実装します。 fetchPapers.js import axios from 'axios'; import DEFAULT_API_LOCALHOST from '../urls'; export const fetchPapers =() => { return axios.get(DEFAULT_API_LOCALHOST) .then(res => { return res.data }) .catch((e) => console.error(e)) } DEFAULT_API_LOCALHOST は前回実装したAPIのエンドポイント、すなわちhttp://localhost:8000/api/papers/になります。 index.js const DEFAULT_API_LOCALHOST = 'http://localhost:8000/api/papers/' export default DEFAULT_API_LOCALHOST; 仮置で、fetchPapers関数を用いて、APIの結果が帰ってくるかどうかをconsole上で見てみます。 src/pages/Papers.js import React, { Fragment, useEffect } from 'react'; // apis import Paper from '../components/Paper'; import { fetchPapers } from '../apis/fetchPapers'; export const Papers = () => { useEffect(() => { fetchPapers() .then((data) => console.log(data) ) }, []) return ( <Fragment> Paper一覧 </Fragment> ) } export default Papers; トップページでPapersをレンダし、ブラウザ上でログを見てみます。 NetWorkErrorで怒られてしまっています。networkのログを見てみると バックエンド側のCORS設定に問題があるようです。 を参考に、バックエンドを修正します。 backend/app/main.py import uvicorn from fastapi import FastAPI from starlette.middleware.cors import CORSMiddleware from backend.arxiv_api import ArxivApiClass from backend.extractor import Extractor app = FastAPI() app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"] ) arxiv_api = ArxivApiClass() extractor = Extractor() # ... submodule側で更新を行い、mainブランチにマージしたので、その反映を行います。 (base) ➜ arxiv-checker git:(feature/createPaperComponent) ✗ git submodule foreach git pull origin main Entering 'backend' remote: Enumerating objects: 12, done. remote: Counting objects: 100% (12/12), done. remote: Compressing objects: 100% (3/3), done. remote: Total 8 (delta 4), reused 7 (delta 4), pack-reused 0 Unpacking objects: 100% (8/8), done. From github.com:izuna385/arxiv-checker-backend * branch main -> FETCH_HEAD c37561e..6f5d886 main -> origin/main Updating c37561e..6f5d886 Fast-forward README.md | 4 ++-- app/main.py | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) (base) ➜ arxiv-checker git:(feature/createPaperComponent) ✗ docker-compost up --build で再度開発環境をビルドした後、localhost:3000番を見に行きます。 バックエンドから論文一覧を取得できていることが分かります。 useState, useEffectを用いたレンダリング バックエンドからの結果を実際にレンダリングする実装を次に行います。 Papers.js import React, { Fragment, useEffect, useState } from 'react'; // apis import Paper from '../components/Paper'; import { fetchPapers } from '../apis/fetchPapers'; export const Papers = () => { const[allPapersData, setAllPapersData] = useState([]); useEffect(() => { fetchPapers() .then(data => setAllPapersData(data.papers)) }, []) return ( <Fragment> {console.log(allPapersData)} <ul> {allPapersData.map((data) => ( <Paper paperData={data}/> ))} </ul> </Fragment> ) } export default Papers; allPapersDataを空の初期値で定義し、そこにバックエンドからの結果を格納しています。 ブラウザ上では、バックエンドの返却結果のリストの各要素が、Paperコンポーネントとして表示されます。 ここまでで、バックエンドとフロントエンドの結合までを完了しました。 動作を確認する場合は、リポジトリからcloneし、docker-compose up --buildで確認可能です。 次回 デプロイについてやっていければと思います。 リポジトリ 参考文献 React+Docker+DockerComposeの開発環境の構築について説明
- 投稿日:2021-08-15T15:52:35+09:00
ローカルで起動しているapacheを停止する方法
docker-compose upをした際に、「Cannot start service laravel.test: Ports are not available: listen tcp 0.0.0.0:80: bind: address already in use」と表示された。 ローカルのapacheが起動しており、80ポートを使っているのが原因だったが、apacheを停止するのに意外と手間取ったので忘備録として書いておく。 ps aux | grep httpd XXXXXXXXX 80825 0.0 0.0 4277624 692 s001 S+ 3:36PM 0:00.00 grep httpd _www 80823 0.0 0.0 4298400 808 ?? S 3:36PM 0:00.00 /usr/sbin/httpd -D FOREGROUND root 80819 0.0 0.0 4298528 3168 ?? Ss 3:36PM 0:00.40 /usr/sbin/httpd -D FOREGROUND やはり起動している。止めようと思って「sudo apachectl stop」を実行してみても、httpdは起動していないと言われる。 sudo apachectl stop httpd (no pid file) not running apatchctlが実行されているパスを調べてみる。 which apachectl /usr/local/bin/apachectl httpdのプロセスが起動しているパスは「/usr/sbin/httpd」だったので、どうやらローカルの違う場所にあるhttpdが実行されているらしい。 ということで、apachectlをフルパスで指定してstopを実行。 sudo /usr/sbin/apachectl stop 無事httpdのプロセスが停止して、docker-compose upが実行できた。
- 投稿日:2021-08-15T11:24:04+09:00
docker-compose.yml内で環境変数の展開
変数展開 docker-composeファイル内でホストの環境変数が展開されます。内容は公式ドキュメントそのままなので、最新情報は公式ドキュメントを参照してください。 Variable substitution(公式) 基本パターン シェルと同じ書き方で展開されます。 $VARIABLE ${VARIABLE} デフォルト値指定 未定義、空白の場合、デフォルト値を設定できます。:-と-の2パターンあり変数の評価方法はシェルの仕様と同じです。 # 変数が未定義、または、空白の場合デフォルト値を代入します。 ${VARIABLE:-default} # 変数が未定義の場合デフォルト値を代入します。 ${VARIABLE-default} 必須チェック 必須チェックを行います。エラーの場合、docker-composeコマンドは失敗します。これも:?エラーメッセージと-?エラーメッセージの2パターンあり変数の評価方法はシェルの仕様と同じです。 # 変数が未定義、または、空白の場合異常終了します。 ${VARIABLE:?err} # 変数が未定義の場合異常終了します。 ${VARIABLE?err} $$ $をエスケープするには$を2つ重ねます。 "$$VAR_NOT_INTERPOLATED_BY_COMPOSE" 使用不可 以下はエラーになることを確認しました。 = := デフォルト値代入 + :+ 定義時の代入 :offset :offset:length 展開の部分指定 以下は未対応です。 ${VARIABLE/foo/bar} 変数の置換 すでに同内容の投稿がありました。 案外知られてないdocker-composeの環境変数定義の記法
- 投稿日:2021-08-15T11:09:48+09:00
M1macでdocker pullしたときのエラー
個人メモ。 mysql:8をdocker pullしたときに下記のエラーが出力された。latestでも同じ。 latest: Pulling from library/mysql no matching manifest for linux/arm64/v8 in the manifest list entries pullコマンドをオプション--platformをつけて実行する。 docker pull --platform=linux/x86_64 mysql:8 runするときにも同じオプションをつける。 docker run -d -it --platform=linux/x86_64 -e MYSQL_ROOT_PASSWORD=[任意のパスワード] mysql:8 何回もrunする場合はdocker-composeファイルを書く。 https://stackoverflow.com/questions/65456814/docker-apple-silicon-m1-preview-mysql-no-matching-manifest-for-linux-arm64-v8 とはいえ前述のdockerのドキュメントによると、動くけどエミュレータ上で動かしてるから性能は落ちるので、M1チップでも動くイメージできるだけ使ってね、とのこと。
- 投稿日:2021-08-15T01:43:20+09:00
m1 macでmysqlのDockerを立てる
もともとのmysqlのイメージを使っていると動かず、linux/amd64のプラットフォームを利用する必要がある。 Dockerfile.m1とdocker-compose.m1.ymlをそれぞれ作った。 Dockerfile.m1 FROM --platform=linux/amd64 mysql:5.7 # FROM mysql@sha256:77b7e09c906615c1bb59b2e9d7703f728b1186a5a70e547ce2f1079ef4c1c5ca RUN echo "USE mysql;" > /docker-entrypoint-initdb.d/timezones.sql && mysql_tzinfo_to_sql /usr/share/zoneinfo >> /docker-entrypoint-initdb.d/timezones.sql COPY ./my.cnf /etc/mysql/conf.d/my.cnf docker-compose.m1.ymlではDockerfile.m1を指定するようにしている docker-compose.m1.yml mysql: build: context: . dockerfile: ./mysql/Dockerfile.m1 environment: TZ: Asia/Tokyo MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: backend ports: - 13306:3306 volumes: - mysql_volume:/var/lib/mysql my.cnfは以下のようにしている。 my.cnf # MySQLサーバーへの設定 [mysqld] # 文字コード/照合順序の設定 character_set_server=utf8mb4 collation_server=utf8mb4_bin # タイムゾーンの設定 default_time_zone=SYSTEM log_timestamps=SYSTEM # デフォルト認証プラグインの設定 default_authentication_plugin=mysql_native_password # mysqlオプションの設定 [mysql] # 文字コードの設定 default_character_set=utf8mb4 # mysqlクライアントツールの設定 [client] # 文字コードの設定 default_character_set=utf8mb4 参考 ありがとうございました。
- 投稿日:2021-08-15T00:41:45+09:00
Kubernetes-in-docker(kind)でkubernetesクラスタを構築する
はじめに 対象読者 コンテナでKubernetesクラスタを構築したい方 kindを試したい方 前提知識 Dockerやコンテナに関する知識 Kubernetesの基礎的な知識 背景 複数ノードのKubernetesクラスタを簡単に構築したい!!と思い、 下記のような要望を満たせないかと調べたところkind (kubernetes-in-docker)というツールの存在を知ったので使ってみました。 本記事は備忘録です。 仮想マシンで構築するのは面倒なのでしたくない(ローカルでもクラウドでも) クラウドのk8sサービスも使いたくない docker-composeみたいに1コマンドでクラスタの作成削除ができると嬉しい クラスタは使い捨てにしたい kindとは kindの全体像は下の図のようになります。 goアプリケーションであるkindから、クラスタの作成コマンドを叩くとkindest/nodeのコンテナが起動しkubernetesクラスタを構築します。 図中では区別していませんが、kindest/nodeのコンテナはそれぞれMasterノードとWorkerノードとして起動されます。 kindを使うと何がうれしいのか...? 公式ページにはfor testing Kubernetes itselfと記載があり、Kubernetesそのものをテストするために作られたものらしい。 多くのKubernetesユーザはfor local development or CIとあるように、ローカルでの開発やKubernetesの勉強、CI/CDのパイプラインなどの方で活用できそうです。 kind is a tool for running local Kubernetes clusters using Docker container “nodes”. kind was primarily designed for testing Kubernetes itself, but may be used for local development or CI. https://kind.sigs.k8s.io/ 環境構築 dockerのインストール はじめにDockerをインストールします。 Windows10を使用しているので、Docker Desktop for Windowsをインストールしています。 C:\>docker -v Docker version 20.10.5, build 55c4c88 goのインストール 次にgoをインストールします。 下記URLからダウンロードできるインストーラを利用してインストールできます。 C:\>go version go version go1.16.7 windows/amd64 kindのインストール kindのインストール方法は下記のQuick Startに記載があります。 Windows向けの実行ファイルは下記URLからダウンロードします。 https://kind.sigs.k8s.io/dl/v0.11.1/kind-windows-amd64 ダウンロードされたファイルに拡張子がついていませんが、.exeを追加するだけでOKです。 Windows環境なのでmklinkコマンドを利用してダウンロードしたファイルのシンボリックリンクを作成します。 mklink kind.exe kind-windows-amd64 これでkindコマンドが使用できるようになりました。 (kind.exeのあるディレクトリで作業をする or PATHを通すのどちらかが必要) kindでクラスタの作成 とりあえずクラスタを作成してみる kind create clusterコマンドを実行してクラスタを起動してみました。 C:\>kind create cluster Creating cluster "kind" ... • Ensuring node image (kindest/node:v1.21.1) ? ... ✓ Ensuring node image (kindest/node:v1.21.1) ? • Preparing nodes ? ... ✓ Preparing nodes ? • Writing configuration ? ... ✓ Writing configuration ? • Starting control-plane ?️ ... ✓ Starting control-plane ?️ • Installing CNI ? ... ✓ Installing CNI ? • Installing StorageClass ? ... ✓ Installing StorageClass ? Set kubectl context to "kind-kind" You can now use your cluster with: kubectl cluster-info --context kind-kind Not sure what to do next? ? Check out https://kind.sigs.k8s.io/docs/user/quick-start/ 特に何も指定しないとkindという名前でkubernetesクラスタが作成されるようです。 C:\>kind get clusters kind docker psコマンドを実行すると、下記のようにkind-control-planeという名前のコンテナが起動していることが確認できます。 デフォルトではkind-control-planeの1ノードしか起動されないようですね。 C:\>docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES c01d1fc6b936 kindest/node:v1.21.1 "/usr/local/bin/entr…" 2 minutes ago Up 2 minutes 127.0.0.1:57863->6443/tcp kind-control-plane 作成したクラスタを削除します。 C:\>kind delete cluster Deleting cluster "kind" ... 複数ノードのクラスタを作成する kindではyamlにクラスタの構成を記述することができます。 下のyamlではMasterノード1つ、Workerノード3つで構成されるクラスタが作成されます。 mycluster.yaml kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 nodes: - role: control-plane - role: worker extraPortMappings: - containerPort: 30001 hostPort: 30001 - role: worker extraPortMappings: - containerPort: 30002 hostPort: 30002 - role: worker extraPortMappings: - containerPort: 30003 hostPort: 30003 下記のコマンドでmycluster.yamlを元にkubernetesクラスタを作成します。 kind create cluster --config mycluster.yaml docker psすると、コンテナが起動していることが確認できます。 コンテナとホスト間でポートがマッピングされていることも確認できます。 C:\>docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 8de298506989 kindest/node:v1.21.1 "/usr/local/bin/entr…" About a minute ago Up About a minute 0.0.0.0:30003->30003/tcp kind-worker3 78772c73a52a kindest/node:v1.21.1 "/usr/local/bin/entr…" About a minute ago Up About a minute 127.0.0.1:58237->6443/tcp kind-control-plane a2a7a3c46e95 kindest/node:v1.21.1 "/usr/local/bin/entr…" About a minute ago Up About a minute 0.0.0.0:30001->30001/tcp kind-worker cafaf17da932 kindest/node:v1.21.1 "/usr/local/bin/entr…" About a minute ago Up About a minute 0.0.0.0:30002->30002/tcp kind-worker2 Masterノードのコンテナに入ってkubectl get nodesコマンドを実行すると、複数ノード(コンテナ)でクラスタが構築されていることが確認できます。 C:\>docker exec -it kind-control-plane bash root@kind-control-plane:/# root@kind-control-plane:/# kubectl get nodes NAME STATUS ROLES AGE VERSION kind-control-plane Ready control-plane,master 10m v1.21.1 kind-worker Ready <none> 9m48s v1.21.1 kind-worker2 Ready <none> 9m48s v1.21.1 kind-worker3 Ready <none> 9m48s v1.21.1 最後にクラスタを削除します。 C:\>kind get clusters kind C:\>kind delete cluster Deleting cluster "kind" ...