第07章:PodでNode/TS APIを動かす🍔🐳☸️
この章はとにかく 「1 Podで動いた!🎉」 まで一直線です。 (次の第8章で Deployment にして「落ちても戻る🛟」へ進化させます)
この章でできるようになること🎯
- Pod(= いちばん小さい実行単位)で Node/TypeScript APIを起動できる🍔
kubectl get/describe/logs/execで 生存確認&原因調査できる🔎kubectl port-forwardで 手元PCからアクセスできる🌐 (Kubernetes)- “よくある詰まり”の 最短直し方が分かる🧯
まずは超重要な前提(この章の地雷だけ回避💣)
Podで動かすWebサーバーは、コンテナ内で 0.0.0.0 にバインドしてないと外から繋がりません🙅♂️
「ローカルでは動くのに、K8sだと繋がらない」No.1原因です🥲
0) 今日の環境メモ(2026年の“今”)🗓️✨
- Kubernetes の最新パッチは v1.35.1(2026-02-10) (Kubernetes)
- ローカル学習だと kind は v0.31.0 でデフォルトKubernetes 1.35.0 (GitHub)
- minikube の最新は v1.38.0(2026-01-28) (minikube)
- Node は v24 が Active LTS(安定枠) (nodejs.org)
- TypeScript は 5.9系が安定版、6.0はBeta情報あり(学習は安定版推奨) (GitHub)
1) “動かす対象”のAPI(すでにイメージがあるなら読み飛ばしOK✅)
ここでは最小のAPIを用意します🍔 エンドポイントは2つだけ:
GET /health→okGET /hello→hello from pod
1-1) src/index.ts(最小のExpress API)🧩
import express from "express";
const app = express();
app.get("/health", (_req, res) => res.status(200).send("ok"));
app.get("/hello", (_req, res) => res.status(200).send("hello from pod"));
const port = Number(process.env.PORT ?? 3000);
// ⭐超重要:0.0.0.0 で待ち受ける(これがないとPod外から繋がりにくい)
app.listen(port, "0.0.0.0", () => {
console.log(`listening on http://0.0.0.0:${port}`);
});
1-2) Dockerfile(学習用:分かりやすさ優先)🐳
## build
FROM node:24-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY tsconfig.json ./
COPY src ./src
RUN npm run build
## runtime
FROM node:24-alpine
WORKDIR /app
ENV NODE_ENV=production
COPY --from=build /app/package*.json ./
COPY --from=build /app/node_modules ./node_modules
COPY --from=build /app/dist ./dist
EXPOSE 3000
CMD ["node", "dist/index.js"]
ここまでが “アプリ側”。次は “Kubernetes側” に入ります☸️✨
2) イメージをクラスタに「届ける」📦🚚(第6章の復習ミニ)
Podは ノード(複数)それぞれがイメージを取る世界です🌍 ローカル学習では、だいたい次のどっちかでOK:
A. kind の場合:kind load docker-image が楽ちん🚀
公式にもこの手順が載っています (Kind)
## 例:ローカルでビルド
docker build -t ts-api:0.1.0 .
## kindクラスタへ読み込み(クラスタ名があるなら --name も)
kind load docker-image ts-api:0.1.0
B. minikube の場合:minikube image load が定番🧳
(コマンド体系として minikube image ... が用意されています) (minikube)
docker build -t ts-api:0.1.0 .
minikube image load ts-api:0.1.0
もちろん「レジストリにpushしてpull」でもOKです👍(本番は基本それ)
3) Podマニフェストを書く📄✍️(この章の主役)
ファイル名:pod-ts-api.yaml
apiVersion: v1
kind: Pod
metadata:
name: ts-api-pod
labels:
app: ts-api
spec:
containers:
- name: api
image: ts-api:0.1.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 3000
env:
- name: PORT
value: "3000"
- name: NODE_ENV
value: "production"
ここで覚えるポイント🧠✨
kind: Podは “生身の1体”(増やす・入れ替えるのは次章)🧍labelsは次に Service/Deployment で効いてくる名札🏷️imagePullPolicy: IfNotPresentはローカル学習で便利(引っ張り失敗を減らす)🧯
4) 起動して「動いた!」まで行く🎉
4-1) apply(投入!)🚀
kubectl apply -f pod-ts-api.yaml
4-2) 状態を見る(まず get)👀
kubectl get pod -w
Runningになったら第一関門突破🥳ImagePullBackOffとか出たら、次の「詰まり集」へ🧯
4-3) 詳細を見る(困ったら describe)🔎
kubectl describe pod ts-api-pod
「何が起きてる?」はだいたい describe に書いてあります📘
5) ログを見る📜(Podの心の声)
kubectl logs ts-api-pod
追いかけたいなら follow(いわゆる tail)🧵
kubectl logs -f は公式リファレンスにもあります (Kubernetes)
kubectl logs -f ts-api-pod
6) Podの中に入って確認する🕵️♂️(exec)
kubectl exec -it ts-api-pod -- sh
中でこんな感じにチェックできます✅
## 環境変数
echo $PORT
## ローカル疎通(コンテナ内)
wget -qO- http://localhost:3000/health
7) 手元PCからアクセスする🌐(port-forward)
Pod に対してポート転送します🚪
コマンド仕様は公式の kubectl port-forward に載っています (Kubernetes)
kubectl port-forward pod/ts-api-pod 3000:3000
ブラウザでアクセス🎉
http://localhost:3000/healthhttp://localhost:3000/hello
8) わざと壊して「Podの限界」も体感😈➡️😇
Podは “1体” なので、アプリが落ちると再起動はしますが、運用として強い形ではないです(次章で進化)🛟
簡単な実験:
PORTを変な値にする(例:文字列)- apply
kubectl get podでRESTARTSが増えるのを見る👀
kubectl get pod
kubectl describe pod ts-api-pod
kubectl logs -f ts-api-pod
9) よくある詰まり集🧯(最短で抜ける)
A) ImagePullBackOff / ErrImagePull 📦💥
原因あるある:
- タグ間違い(
0.1.0が0.1.Oとか)😇 - ローカルイメージをクラスタに読み込んでない(kind/minikube)😅
- レジストリがprivateで認証できてない🔐
対処:
- kind →
kind load docker-image ...(Kind) - minikube →
minikube image load ...(minikube) - まず
kubectl describe pod ...の Events を見る👀
B) CrashLoopBackOff 🔁💀
対処:
kubectl logs -f ts-api-pod(Kubernetes)- アプリが「0.0.0.0 で待ち受けてるか」を確認✅(最重要)
C) port-forward はできたのに繋がらない🌐❌
原因:
- アプリが
localhostバインドになってる
対処:
- Nodeの listen を
"0.0.0.0"にする(この章の地雷回避)💣➡️✅
D) Pending のまま🕰️
対処:
kubectl describe pod ...のEventsを見る (リソース不足、ノードの準備不足などが見える👀)
10) できたかチェック✅(セルフテスト)
-
kubectl get podでRunningを見た👀 -
kubectl logsで “listening...” を見た📜 (Kubernetes) -
kubectl port-forwardで/healthがokになった🌐 (Kubernetes) -
kubectl execで Pod の中からlocalhost疎通した🕵️♂️
🤖 AIで楽するポイント(この章)✨
- YAMLを書いたらAIにこう聞く: 「このPod、起動しない可能性あるところを3つ指摘して。Eventsで確認する場所もセットで」🔎
kubectl describeの出力を貼って: 「この Events の読み方を、原因→確認→対処で短くまとめて」🧯
次の章へのつながり🔗✨
Podで「動いた!」は達成🎉 でも Pod は “生身の1体” なので、次は Deployment で 落ちても戻る🛟&増やせる📈 に進化します!
(第8章でやること:replicas / rollout / “Podを消して復活を見る” 😈➡️😇)