EC2 を1台だけ立てて、そこに Kubernetes1 を入れ、自分で作った gRPC サーバーのコンテナを動かし、手元の Mac から呼ぶところまでやりました。使ったのは EKS ではなく k3s です。はじめてのgRPC と はじめてのTerraform の続きになります。
1. この記事でやること
Docker は使っているけれど Kubernetes はまだ、という状態から始めます。docker run は打てる、Dockerfile も書いたことがある。でも Pod や Deployment という言葉は聞いたことがある程度。私がまさにその状態でした。
最後にこうなります。
$ GRPC_HOST=203.0.113.45 GRPC_PORT=30051 venv/bin/python3 client.py
こんにちは、三橋 さん
$ kubectl delete pod grpc-hello-5648f8f79f-6d2pf
pod "grpc-hello-5648f8f79f-6d2pf" deleted
$ GRPC_HOST=203.0.113.45 GRPC_PORT=30051 venv/bin/python3 client.py
こんにちは、三橋 さん
真ん中で Pod を消しています。それなのに3回目がそのまま返ってきます。消した Pod は戻ってきません。代わりに新しい Pod が立っていて、そちらが返事をしています。 この記事はその一連を自分の手で作って、落ちていた時間が何秒だったかまで測るところまでです。
出てくる言葉は3つです。Pod はコンテナが入る箱、Deployment は「その箱を常に n 個動かしておく」というルール、Service は箱が入れ替わっても変わらない受付窓口。この3つだけ頭に入れておけば読めます。中身は3章で書きます。
図にするとこうなります。
作業は1日で終わります。AWS に課金が発生するのは EC2 を立てている間だけで、私の場合は9分弱でした。金額は11章にまとめてあります。
2. なぜ EKS ではなく k3s なのか
AWS で Kubernetes といえば EKS です。ただ EKS は、Pod を1つも動かしていなくてもクラスタが存在するだけで1時間 0.10ドルかかります。1か月立てっぱなしにすると管理料だけで約70ドル、そこに EC2 の代金が乗ります。「勉強のために1日触りたい」という用途には重すぎます。
k3s は Rancher が作っている Kubernetes です。Kubernetes そのものを1つの実行ファイルにまとめてあり、curl 1行で入ります。 管理料という考え方がないので、かかるのは EC2 の代金だけです。
機能を削った別物ではありません。kubectl はそのまま使えますし、Pod も Deployment も Service も同じ名前で同じように動きます。私が今回打ったコマンドは、EKS に対してもそのまま通るものばかりです。
| EKS | k3s | |
|---|---|---|
| 管理料 | 1クラスタ 1時間 0.10ドル | なし |
| 入れ方 | AWS のコンソールか eksctl | EC2 の中で curl 1行 |
| kubectl | 使える | 同じものが使える |
| 向いている場面 | 本番で複数台をまとめて運用する | 1台で仕組みを覚える・小さく動かす |
覚えたい相手が「Kubernetes の仕組み」なら、k3s で足ります。
3. 書いたファイルは3つ
gRPC サーバーのコードは前回のものをそのまま使いました。Kubernetes のために新しく書いたのは3つだけです。
置き場所を先に決めておきます。どれも手元の Mac で書きます。 EC2 へ送るのは Dockerfile とサーバー側のコードだけで、YAML の2つは手元に置いたまま kubectl から渡します。
| ファイル | 書く場所 | どこで使うか |
|---|---|---|
Dockerfile |
手元の Mac | EC2 へ scp して、EC2 の中で docker build
|
server.py・hello_pb2.py・hello_pb2_grpc.py
|
前回のもの | 同上(イメージの中に入る) |
deployment.yaml |
手元の Mac | 手元から kubectl apply で渡す |
service.yaml |
手元の Mac | 同上 |
client.py |
手元の Mac | 手元で実行する |
3-1. Dockerfile — サーバーをイメージにする
FROM python:3.14-slim
WORKDIR /app
RUN pip install --no-cache-dir grpcio protobuf
COPY hello_pb2.py hello_pb2_grpc.py server.py ./
EXPOSE 50051
CMD ["python3", "server.py"]
中身は4つです。土台の OS、入れるもの、詰めるファイル、起動コマンド。Docker を触ったことがあれば読めるはずで、Kubernetes 固有のものは何も入っていません。
protobuf を明示的に書いているのには理由があります。grpcio だけ入れると、生成コードの hello_pb2.py が読む google.protobuf が見つからずに止まります。前回これで詰まりました。
client.py と hello.proto はイメージに入れていません。サーバー側では使わないからです。
3-2. deployment.yaml — 「常に1つ動かす」というルール
apiVersion: apps/v1
kind: Deployment
metadata:
name: grpc-hello
spec:
replicas: 1
selector:
matchLabels:
app: grpc-hello
template:
metadata:
labels:
app: grpc-hello
spec:
containers:
- name: grpc-hello
image: grpc-hello:v1
imagePullPolicy: Never
ports:
- containerPort: 50051
Kubernetes の YAML はどれもこの4つで始まります。apiVersion(この書式の版)、kind(何を作るか)、metadata(名前)、spec(中身)。次の service.yaml も同じ形です。
spec の中に template があって、その下にまた metadata と spec が出てきます。下の段は Pod 1個ぶんの設計図です。 上が Deployment の設定、下が「そこから作る Pod はこういうもの」という入れ子になっています。
ここが Docker との一番の違いでした。Pod2 を直接書くこともできますが、そうすると消したときに復活しません。 Deployment3 は「この Pod を常に replicas 個保つ」という係です。9章で Pod を消したときに新しいものが立つのは、この1行があるからです。
2つ注意した点があります。
imagePullPolicy: Never。 これが無いと、k3s は grpc-hello:v1 を Docker Hub へ取りに行って ErrImagePull で止まります。7章で自分の手で読み込ませたイメージを使わせるための指定です。
タグを :v1 にした。 imagePullPolicy を書かなかった場合、タグが :latest だと既定が Always(毎回取りに行く)になります。今回は Never を明示しているので既定は効きませんが、書き忘れたときに取りに行かれないよう、タグの側でも避けておきました。
もう1つ、selector.matchLabels と template.metadata.labels は必ず同じにします。ここが食い違うと Deployment が自分で立てた Pod を見失います。
3-3. service.yaml — 番号が3つ出てきて、ここが一番まぎらわしい
apiVersion: v1
kind: Service
metadata:
name: grpc-hello
spec:
type: NodePort
selector:
app: grpc-hello
ports:
- port: 50051
targetPort: 50051
nodePort: 30051
protocol: TCP
Service4 は受付窓口です。Pod は立て直すたびに IP が変わりますが、Service の側は変わりません。手元の client.py が同じ番号で呼び続けられるのはこれのおかげです。
どの Pod へ流すかは selector で決めます。deployment.yaml で Pod に付けた app: grpc-hello と同じ文字列を書いています。 Service は特定の Pod を IP で覚えているのではなく、この札が付いた Pod をその都度探します。だから Pod が入れ替わっても届きます。
番号が3つ出てきます。最初に読んだとき、どれがどれだか分かりませんでした。
| 書いた場所 | 意味 |
|---|---|
nodePort: 30051 |
EC2 の外(手元の Mac)から呼ぶ番号 |
port: 50051 |
k3s の中から grpc-hello:50051 で呼ぶ番号 |
targetPort: 50051 |
Pod の中で server.py が待っている番号 |
nodePort は 30000〜32767 の範囲しか使えません。 gRPC でよく使う 50051 をそのまま外に出すことができないので、前回まで 50051 直書きだった client.py に手を入れました。
host = os.environ.get("GRPC_HOST", "localhost")
# ポートも環境変数で受ける(k3s の Service は 30000〜32767 しか外に出せない)
port = os.environ.get("GRPC_PORT", "50051")
with grpc.insecure_channel(f"{host}:{port}") as channel:
既定値を 50051 のままにしたので、GRPC_PORT を付けなければ前回と同じ動きのままです。
4. Terraform に足したのは通行許可証2つ
EC2 は前回の Terraform をそのまま使いました。足したのはセキュリティグループ52つだけです。
resource "aws_security_group" "k3s_api" {
name = "aws-study-tf-k3s-api-sg"
description = "k3s api from my home only"
ingress {
description = "k3s api"
from_port = 6443
to_port = 6443
protocol = "tcp"
cidr_blocks = [var.my_ip]
}
egress {
description = "all outbound"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
6443 番は、手元の kubectl が EC2 の Kubernetes につなぐ口です。もう1つ同じ形で 30051 番(nodePort のほう)を開けます。どちらも cidr_blocks = [var.my_ip] で自宅の IP からだけに絞っています。
EC2 への付け方はこうです。
vpc_security_group_ids = [
aws_security_group.study.id,
aws_security_group.k3s_api.id,
aws_security_group.k3s_nodeport.id,
]
ここで前回まで付けていた 50051 番と 8080 番を外しました。今回は Service 経由でしか呼ばないので、直接叩く口は要りません。使わない口は開けたままにしない、を守った形です。
terraform plan を打つと、自宅の IP も番号も伏せられて出ます。
+ ingress = (sensitive value)
variables.tf で my_ip に sensitive = true を付けているためです。IP が画面に出ないのは安心ですが、裏返しに「どの番号を開けるつもりか」も plan では確かめられません。そこは main.tf を目で見ることになります。
5. 手元に kubectl を入れて、EC2 を立てる
先に手元の Mac へ kubectl6 を入れます。Kubernetes に指示を出すコマンドで、この先ずっと使います。
入門記事の多くは brew install kubernetes-cli と書いていますが、Intel の Mac ではこれが通りませんでした(理由は12章)。公式のバイナリを直接落とします。
curl -LO https://dl.k8s.io/release/v1.37.0/bin/darwin/amd64/kubectl
curl -LO https://dl.k8s.io/release/v1.37.0/bin/darwin/amd64/kubectl.sha256
echo "$(cat kubectl.sha256) kubectl" | shasum -a 256 --check
chmod +x kubectl && mv kubectl /usr/local/bin/
60MB で1分でした。Apple Silicon の Mac なら URL の amd64 を arm64 に変えます。
kubectl version --client
Client Version: v1.37.0
Kustomize Version: v5.8.1
ここから課金が始まります。EC2 だけを立てたいので -target で絞ります。
terraform apply -target=aws_instance.study
絞らないと、同じ main.tf に書いてある RDS まで立ちます。
Apply complete! Resources: 7 added, 0 changed, 0 destroyed.
この EC2 は Docker が入った状態で立ち上がります。Terraform の user_data に書いてあるためで、7章で docker build を打つのに要ります。
user_data = <<-EOF
#!/bin/bash
dnf install -y docker
systemctl start docker
systemctl enable docker
usermod -aG docker ec2-user
EOF
ssh で入って、k3s を入れます。この1行だけです。
curl -sfL https://get.k3s.io | sudo sh -
公式の案内には | sh - と書いてありますが、Amazon Linux の ec2-user では権限が足りません。sudo を挟みます。
終わると、kubectl が使える状態になっています。
sudo k3s kubectl get nodes
NAME STATUS ROLES AGE VERSION
ip-172-31-7-1 Ready control-plane,master 35s v1.36.4+k3s1
1台だけの Kubernetes が立ちました。EC2 側に kubectl を別途入れる必要はありません。 k3s の実行ファイルが kubectl も内蔵していて、/usr/local/bin/kubectl がそこへのシンボリックリンクとして作られます。
ログにこんな行が出ます。
Skipping /usr/local/bin/ctr symlink to k3s, command exists in PATH at /usr/bin/ctr
ctr だけはリンクが作られません。Docker が持っている ctr が先にいるためです。これが7章で sudo k3s ctr とフルで打つ理由になります。
6. 手元の kubectl からつなぐ — ここで1回止まりました
毎回 ssh で入るのは面倒なので、手元の Mac から操作できるようにします。つなぎ方の情報は EC2 の /etc/rancher/k3s/k3s.yaml にあります。
このファイルは root しか読めないので、EC2 の中でいったん読める場所へ寄せます。
sudo cp /etc/rancher/k3s/k3s.yaml /tmp/k3s.yaml
sudo chown ec2-user:ec2-user /tmp/k3s.yaml
あとはこれを手元へ持ってきて、server: の 127.0.0.1 を EC2 の IP に書き換えるだけ、のはずでした。
tls: failed to verify certificate: x509: certificate is valid for
10.43.0.1, 127.0.0.1, 172.31.7.1, ::1, not 203.0.113.45
k3s が作った証明書に、EC2 のパブリック IP が入っていません。 入っているのはクラスタ内部の IP と 127.0.0.1 だけです。EC2 の中から使う分には困らないので、既定ではそうなっています。
直し方は、証明書に載せる名前を設定に書いて、作り直させることです。
sudo tee /etc/rancher/k3s/config.yaml <<'EOF'
tls-san:
- 203.0.113.45
EOF
sudo rm -f /var/lib/rancher/k3s/server/tls/serving-kube-apiserver.crt \
/var/lib/rancher/k3s/server/tls/serving-kube-apiserver.key
sudo systemctl restart k3s
消した2つは再起動時に作り直されます。87秒で Ready に戻りました。
あらためて k3s.yaml を手元へ持ってきます。
scp -i ~/.ssh/<鍵> ec2-user@203.0.113.45:/tmp/k3s.yaml ~/.kube/config-s8
sed -i '' "s|127.0.0.1|203.0.113.45|" ~/.kube/config-s8
この18行のファイルには、証明書と鍵が3件入っています(certificate-authority-data・client-certificate-data・client-key-data)。作業フォルダに置いて .gitignore する手もありますが、私は ~/.kube/ に置きました。git の外に出してしまえば、うっかり commit する心配そのものが無くなります。
このファイルを使うよう kubectl に教えます。この先の kubectl は全部この設定で打つので、ターミナルを開き直したらもう一度打ちます。
export KUBECONFIG=~/.kube/config-s8
kubectl get nodes
NAME STATUS ROLES AGE VERSION
ip-172-31-7-1 Ready control-plane,master 4m v1.36.4+k3s1
手元から EC2 の Kubernetes が見えました。ここから先は ssh に戻らなくて済みます。
なお手元の kubectl は v1.37.0、EC2 の k3s は v1.36.4 です。1つ違いですが問題なく動きました。
7. イメージを EC2 で組み立てて、k3s に渡す
コードと Dockerfile を EC2 へ送って、そこで組み立てます。
ssh -i ~/.ssh/<鍵> ec2-user@203.0.113.45 "mkdir -p ~/build"
scp -i ~/.ssh/<鍵> Dockerfile server.py hello_pb2.py hello_pb2_grpc.py ec2-user@203.0.113.45:~/build/
ホーム直下ではなく ~/build/ に置きます。ビルドの対象がそのフォルダごと送られるので、関係ないファイルを巻き込まないためです。
cd ~/build && docker build -t grpc-hello:v1 .
6.9秒で終わりました。ここまでは普通の Docker です。
ここからが Kubernetes 特有のところです。 docker build しただけでは、Pod からこのイメージが見えません。
k3s は Docker ではなく containerd7 で動いています。 Docker が持っているイメージの置き場と、k3s が見る置き場は別物です。同じ EC2 の中にあっても、そのままでは渡りません。
この状態のまま次の章へ進むと、Pod は立ち上がらずに ErrImageNeverPull で止まります。imagePullPolicy: Never を書いているので、Docker Hub へ取りに行くこともしません。
渡すには、いったんファイルに書き出して、k3s 側に読み込ませます。
docker save grpc-hello:v1 -o /tmp/grpc-hello.tar
sudo k3s ctr images import /tmp/grpc-hello.tar
149MB の tar ができて、読み込みは1.9秒でした。ctr ではなく k3s ctr とフルで打つのは、5章で見たとおり素の ctr が Docker 側を向いているためです。
k3s には docker.io/library/grpc-hello:v1 という名前で入ります。deployment.yaml に書いた grpc-hello:v1 はこの形に補われて、ちゃんと一致します。
この方法だと、Docker Hub にも ECR にも1バイトも送っていません。 レジストリを用意しなくても Kubernetes は動かせる、というのが個人的には一番の収穫でした。
8. Pod を立てて、手元から呼ぶ
手元の Mac から2つの YAML を渡します。
kubectl apply -f deployment.yaml -f service.yaml
deployment.apps/grpc-hello created
service/grpc-hello created
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP
grpc-hello-5648f8f79f-6d2pf 1/1 Running 0 1s 10.42.0.9
0.66秒で Running になりました。イメージが既に EC2 の中にあるので、取得の待ち時間がありません。
kubectl get svc
NAME TYPE CLUSTER-IP PORT(S) AGE
grpc-hello NodePort 10.43.95.205 50051:30051/TCP 3s
ここで IP が3つ出てきます。EC2 のパブリック IP、Service の 10.43.95.205、Pod の 10.42.0.9。全部別物です。手元から呼ぶときに使うのは1つ目だけで、残り2つは k3s の中の住所です。
呼びます。
GRPC_HOST=203.0.113.45 GRPC_PORT=30051 venv/bin/python3 client.py
こんにちは、三橋 さん
0.44秒。使った client.py は前回のものと同じで、変えたのはポートを環境変数で受ける3行だけです。 呼ぶ側から見ると、相手が Pod になったことは分かりません。
9. Pod を消すと、何秒落ちるのか
ここが今回いちばんやりたかったところです。「Kubernetes は落ちても勝手に上がる」と説明されますが、上がるまでの間はどうなっているのかが気になっていました。
消した直後から呼び続けて測ります。40行です。
import os, subprocess, time
import grpc, hello_pb2, hello_pb2_grpc
IP = os.environ["IP"]
POD = os.environ["POD"]
target = f"{IP}:30051"
def call():
try:
with grpc.insecure_channel(target) as ch:
stub = hello_pb2_grpc.GreeterStub(ch)
stub.SayHello(hello_pb2.HelloRequest(name="三橋"), timeout=1.5)
return True
except Exception:
return False
print(f"削除前に1回呼ぶ: {'通った' if call() else '通らない'}")
t0 = time.monotonic()
subprocess.run(["kubectl", "delete", "pod", POD, "--wait=false"], check=True, capture_output=True)
print(f"kubectl delete を打った({time.monotonic() - t0:.2f}秒)")
first_fail = recovered = None
while time.monotonic() - t0 < 180:
ok = call()
t = time.monotonic() - t0
if not ok and first_fail is None:
first_fail = t
print(f"つながらなくなった: {t:.2f}秒後")
if first_fail is not None and ok:
recovered = t
print(f"また通った: {t:.2f}秒後")
break
if first_fail is not None and recovered is not None:
print(f"落ちていた時間: {recovered - first_fail:.2f}秒")
elif first_fail is None:
print("一度もつながらない瞬間が無かった")
else:
print("180秒たっても戻らなかった")
打ち方はこうです。Pod の名前は kubectl get pods で出たものを渡します。
IP=203.0.113.45 POD=grpc-hello-5648f8f79f-6d2pf venv/bin/python3 measure_restart.py
結果です。
削除前に1回呼ぶ: 通った
kubectl delete を打った(0.21秒)
つながらなくなった: 1.32秒後
また通った: 1.51秒後
落ちていた時間: 0.19秒
0.19秒でした。 一瞬ではあるものの、確かに落ちています。「勝手に上がる」は「止まらない」ではない、というのが数字で見えました。
新しく立った Pod を見ます。
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP
grpc-hello-5648f8f79f-q824w 1/1 Running 0 12s 10.42.0.10
名前も IP も変わっています(6d2pf → q824w、10.42.0.9 → 10.42.0.10)。それでも client.py は 203.0.113.45:30051 のままで届きました。 Service が受付をしている、というのはこういうことでした。
何が起きたかは記録に残っています。
kubectl get events --sort-by=.lastTimestamp
Killing Stopping container grpc-hello
SuccessfulCreate Created pod: grpc-hello-5648f8f79f-q824w
Pulled Container image "grpc-hello:v1" already present on machine
Created Created container: grpc-hello
Started Started container grpc-hello
Pulled という行名が出ますが、中身は already present on machine(もう手元にある)です。取りに行っていません。 imagePullPolicy: Never を書いていても記録の行名は Pulled のままなので、最初に見たときは取りに行ったのかと思いました。7章で読み込ませたものがそのまま使われています。
1つ気づいたことがあります。消した Pod は即座には消えません。
NAME READY STATUS RESTARTS AGE
grpc-hello-5648f8f79f-6d2pf 1/1 Terminating 0 3m
grpc-hello-5648f8f79f-q824w 1/1 Running 0 30s
古いほうが30秒ほど Terminating のまま残りました。Kubernetes は終了の合図(SIGTERM)を送ってから既定で30秒待ちます。私の server.py は wait_for_termination() で待っているだけで、その合図を受け取って自分から終わる作りになっていません。だから猶予の30秒をまるまる使い切ってから止められます。
新しい Pod は先に立ち上がっているので、外から見ると 0.19秒で復旧しています。とはいえ、止まるほうと立つほうは別々に進むというのは、表の数字だけ見ていると気づけませんでした。
10. 消す
EC2 が要るのはここまでです。
terraform destroy
Destroy complete! Resources: 7 destroyed.
消えたことは自分の目で確かめます。
aws ec2 describe-instances \
--filters "Name=instance-state-name,Values=running,stopped" \
--query 'Reservations[].Instances[].[InstanceId,State.Name]' --output text
aws ec2 describe-volumes --query 'Volumes[].[VolumeId,Size,State]' --output text
どちらも何も返らなければ終わりです。EC2 は「停止」だけだとディスク代が止まりません(30GB で1日約14円)。destroy まで通します。
11. かかった時間とお金
本文で後回しにした数字をここに並べます。
時間
| 何に | 実測 |
|---|---|
| terraform apply(EC2 と周辺あわせて7個) | 34秒 |
| k3s のインストール | 30.9秒 |
| 証明書の作り直し(6章) | 87秒 |
| docker build | 6.9秒 |
| k3s ctr images import(149MB) | 1.9秒 |
| Pod が Running になるまで | 0.66秒 |
| client.py の返事 | 0.44秒 |
| kubectl delete から復旧まで | 1.51秒 |
| そのうち、つながらなかった時間 | 0.19秒 |
| terraform destroy | 2分3.8秒 |
Kubernetes を入れる作業そのものは31秒で終わります。時間を使ったのは証明書の件と、イメージの受け渡しでした。
お金
EC2 を立てていたのは 8分34秒でした。
| 何に | 概算 |
|---|---|
| m7i-flex.large | 1時間 約18.5円 |
| ディスク gp3 30GB | 1日 約14円 |
| 今回の合計(8分34秒) | 約2.7円 |
始める前は「2〜3時間で37〜55円くらい」と見込んでいたので、20分の1で済みました。手順が決まっていれば早く終わります。
EKS で同じことをすると、クラスタの管理料が1時間 0.10ドル(約15円)です。8分でも1時間ぶんから課金されるので、EC2 代と合わせて18円ほど。金額の差は小さいのですが、「クラスタを作る・消す」に十数分かかるぶん、気軽に消せなくなるのが実際のところでした。
消し忘れたとき
1か月立てっぱなしにすると、EC2 が約13,300円、ディスクが約420円です。学習用なら使うたびに作って消すほうが安くつきます。
12. つまずいたところ
| つまずき | 分かったこと | |
|---|---|---|
| 1 |
brew install kubernetes-cli が終わらない |
Intel Mac には組み立て済みのファイルが用意されていない。Go のコンパイラから入れてソースを組み立て始める。公式のバイナリを curl で落とせば1分 |
| 2 | 手元の kubectl が証明書で拒まれる | k3s の証明書にはパブリック IP が入っていない。tls-san に書いて作り直す |
| 3 | Pod が ErrImagePull で止まる |
docker build したイメージは k3s から見えない。docker save → k3s ctr images import で渡す |
| 4 |
kubectl apply --dry-run=client が使えない |
ファイルの形だけ確かめたくても、リソースの種類を知るのにクラスタへの接続が要る |
| 5 | 消した Pod が30秒残る | 終了の合図を受け取って自分から終わる作りでないと、猶予の30秒を待たされる |
1つ目は Kubernetes と関係ないところです。Intel の Mac を使っていると、入門記事に書いてある brew install がそのまま通らないことがあります。前回の Terraform でも同じことがありました。
brew install kubernetes-cli を打つと、Intel Mac 向けの組み立て済みファイルが用意されていないため、Go のコンパイラ・bash・coreutils を先に入れてからソースを組み立て始めます。10分待っても終わらず、ncurses を組み立てている途中でした。5章の公式バイナリなら1分です。
ただし公式バイナリは Homebrew の管理外になるので、brew upgrade では上がりません。 版を上げるときは同じ手順で置き換えます。
3つ目が、Docker から来た人がいちばん引っかかるところだと思います。同じサーバーの中にイメージがあるのに使えないというのは、言われるまで思いつきませんでした。Kubernetes が Docker とは別のコンテナの仕組みで動いている、というのが体感できた場面です。
-
Kubernetes。コンテナを何台ものサーバーにまたがって動かし、落ちたら立て直し、数を保つための仕組み。読み方は「クバネティス」で、k と s の間に8文字あるので k8s と略されます。 ↩
-
Pod。Kubernetes がコンテナを動かす最小の単位。1つの Pod に複数のコンテナを入れることもできますが、今回は1つです。 ↩
-
Deployment。「この Pod を常に n 個保つ」というルールを書いたもの。Pod が消えたら新しく立て、数が多ければ減らします。 ↩
-
Service。Pod への入口になる受付窓口。Pod が入れ替わっても Service 側の宛先は変わりません。今回使った NodePort は、サーバーの特定の番号を外に開ける型です。 ↩
-
セキュリティグループ。AWS の通行許可証にあたるもので、どの IP からどの番号を通すかを書きます。 ↩
-
kubectl。Kubernetes に指示を出すコマンド。「クーベコントロール」「キューブシーティーエル」など読み方は人によって違います。 ↩
-
containerd。コンテナを実際に動かす部分。Docker もこれを内部で使っていますが、置き場は Docker と k3s で別々に持っています。 ↩