たなしょのメモ

日々勉強していることをつらつらと

エンジニアの知的生産術を読んでみた

インプットやアウトプットの方法に興味があったので読んでみた。

gihyo.jp

感想

日常の学びや仕事をしていく中で役立つことが書かれており、自分の中で言語化できていなかったり気づいていないことを知れてとても有意義な本だった。
特に第2章 やる気を出すにあるタスクに集中できない原因はまさにタイムリーな話だったので、早速仕事に取り入れて効果が出ており即効性を感じている(個人差はある)。
エンジニアとタイトルに書いているがインプットとアウトプットに悩んでいる人、全員に読んでほしい本だと感じた。
7章の中から気付かされることが1つでもあればそれが今後の学びにつながると思う。

以下、共感したところや学んだところをざっと書いてみた。

第1章 新しいことを学ぶには

「どうしてこんなやり方を思いついたのだろう、自分には思いつかないな、彼は天才なのかもしれないな」と思うがそれは自分が一番手前の箱しか見ていないから感じる。

シニアエンジニアと自分の差を比較してしまうのでひしひしと感じるな。。。

大学に入らなくてもcourseraやedx、放送大学があるな

www.coursera.org

www.edx.org

www.ouj.ac.jp

参考書を選ぶコツ

  • 大学の講義の参考図書に選定されている

  • 正誤表が充実している

  • 改訂されている・ロングセラーである

遅延評価的勉強法

  • 知りたいところから学ぶ

  • 結局Yak sharvingしていく

Matzのソースコードの読み方

  • 面白そうなところをつまみ食い

  • 目的をもって読む

ソースコードの読み方例

  • 内部構造を解説したドキュメントがあればそれを読む

  • ディレクトリ構造を読む

  • ファイル構成を読む

  • 略語を調査する

  • データ構造を知る

  • 関数どうしの呼び出し関係を把握する

  • 関数を読む

ソースコード読んでもhowしかわからない。whyの情報はコメントやコミットログ、過去のやり取りにある。

仕事でも他グループのPRを見ることで何がリリースされるのかや新しく施策を始めようとしていることを知れたので非常に良い経験になった。

写経について私も最近は前よりもやらなくなっているかな。
最近はHaskellを勉強していて関数型言語という今まで触ってきた言語とは考え方が異なるので写経している。
でも今まで触った言語と同じような考え方で良い言語ならもう写経はせずドキュメントをさらっと読む程度にするかも。

第2章 やる気を出す

以下3つは意識したら仕事で集中できるようになった。おすすめ。

  • タスクを細分化して、タスクを一つに絞る

  • やる気を損ねる大きな原因は、タスクを一つに絞れない。

  • タスクを選んだ後にやる気が出ない多い原因は、タスクが大きすぎること。

第3章 記憶を鍛えるには

インプットとアウトプットを繰り返すことが大事。

Ankiを使えば学習間隔決定アルゴリズムであるM2アルゴリズムを使って学習できる。
* 今度資格の勉強の時に使ってみよう

理解できないことを学ぼうとしない。
* 学ぼうとしているものを理解するステップが必要。

本を読んで情報を収集するだけではなく、集めた情報を積み上げてピラミッドを作る作業が必要。
* まさにインプットからのアウトプットの作業だ。

第4章 効率的に読むには

本を読むことの目的

  • 娯楽

  • 情報を見つけること

  • 理解を組み立てること

読む速度を測ってみると良いらしい

読まずに知識を手に入れる

  • 書評をwebで検索する

    • Whole Mind System これどうなんだ。自分は娯楽の側面もあるからこんな読書の仕方は嫌だな

    • 仕事で必要に駆られて手にいれたい知識ならいいかもしれない

Whole Mind Systemの一部であるマインドマップの作成などはNotebookLMがやってくれそうなので、PDF版を購入して要約やマインドマップを書かせるのが良いかもしれない。

第5章 考えをまとめるには

書き出し方でとにかく書いて情報を出してみる。まずは5分間
100個くらい考えていることを書き出すことを目標にしてみる。
* これ0秒思考かなんかで読んだな。

出し切ったらKJ法で分類する。

第6章 アイデアを思いつくには

先入観を持たずに他人の話を聞くことは難しいので、まずは自分の話を聞くことから練習してみましょう

まさにその通りだと思う。内省できてから他人の話を素直に聞けるようになった。

難しい言葉を使わないで説明できるかは新卒の時の会社の先輩に言われたなぁ。

本当にその単語の意味を理解しているのか疑問を持った方が良い。
* これは共感した。下手に横文字を使いすぎるの良くない。

第7章 何を学ぶかを決めるには

何か学びたいという熱意の湧いてくる対象を見つけ、それを学べば良いのです。

自分の学びの原動力かも。無理に学びたくないもの学ばなくてもいいと思っている。

社会人がまず何を学ぶべきか、それは「今やっている仕事の効率化」です。しことを効率化することで時間の余裕を作り、その余裕を新たな学びに投資するのです。

確かに。残業ばかりしているので耳が痛い。定時に上がって学ぶ時間を確保するところからやらないとな。

nginx実践入門を読んでみた

nginxを業務で使うことになったので読んでみた。

gihyo.jp

第1章 nginxの概要とアーキテクチャ

nginxはc10k問題を解決するために開発された。 c10k問題とは1台のサーバが1万ものクライアントからの接続を同時に処理しようとするサーバの処理が追いつかなくなるというスケーラビリティの問題だそうだ。

nginxの最大の特徴は優れたスケーラビリティなのだそうだ。

nginxの用途 - テキストや画像といった静的なコンテンツの配信 - リバースプロキシとして動作させる

大量のプロセスを起動するとプロセス間コンテキストスイッチのオーバーヘッドが大きくなって性能が劣化する。

第2章 インストールと起動

インストールしたくないのでcompose.ymlを書いた。

services:
  nginx:
    image: nginx:latest
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./html:/usr/share/nginx/html:ro
    command: nginx -g 'daemon off;'

Dockerは便利だ。

第3章 基本設定

nginx.confは相対パスで書いてあったので絶対パスに書き換えた。

worker_processes 1;

events {
    worker_connections 1024;
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';

    # Use the container's standard log directory so the file exists
    access_log /var/log/nginx/access.log main;

    sendfile on;

    tcp_nopush on;

    server {
        listen 80;
        server_name localhost;

        # Match the volume in compose.yml which mounts ./html to /usr/share/nginx/html
        root /usr/share/nginx/html;
        index index.html index.htm;
    }
}

nginxは変数名の先頭に$をつけて表現する。

クエリストリングの値は$arg_属性名、HTTPヘッダの値は$http_フィールド名で使用できる。

serverディレクティブでIPアドレス、ポート、ホスト名ごとに別々の設定を持つ複数のHTTPサーバを動作させることができる。

バーチャルサーバと呼ばれる。

rootディレクティブで指定したディレクトリのパスがそのURIのルートにマッピングされる。

worker_processes ディレクティブ ワーカー数はCPUのコア数と同じ数にするのが良い。 パラメータにautoを指定することで、CPUのコア数を自動検出してコア数と同じにする。

パフォーマンスに影響する設定

  • keepalive_timeout.
  • sendfile.
  • tcp_nopush.
    • TCP_NOPUSHオプションを有効/無効にする.
    • このオプションを使用するとおもっとも大きなパケットサイズでレスポンスヘッダとファイルの内容を送信でき、送信するパケット数を最小化できる。基本的に有効にしておく。
  • open_file_cache.
    • オープンしたファイルのキャッシュを有効/無効にする.

第4章 静的なWebサイトの構築

特に気になるところはなかった。

第5章 安全かつ高速なHTTPSサーバの構築

高速なTLSを実現するうえで使用となる数値がTTFBです。

TTFBを最小化する方法として3つのテクニック。
- HTTP/2, またはSPDYによる通信の高速化.
- TLSセッション再開によるハンドシェイクの高速化.
- OCSPステープリングによるサーバ証明書検証コストの削減.

現在は以下のテクニックが必要だそうだ。Claudeに聞いてみた。
2025年時点での追加テクニック.

  1. TLS 1.3を使う(必須).

    • ハンドシェイクが高速化.
    • 古い暗号スイートを排除.
  2. HTTP/3 (QUIC)の検討.

    • 0-RTT接続再開.
    • パケットロスに強い.
  3. Early Hints (103ステータス).

    • ブラウザにリソースのプリロードを早期通知.
  4. TLS証明書の最適化.

    • ECDSA証明書(RSAより軽量).
    • 証明書チェーンの最小化.
  5. BBRやTCP Fast Open.

今(2025年)の情報をもとに安全かつ高速なHTTPSサーバの構築を構築すると下記のようになる。

github.com

第6章 Webアプリケーションサーバの構築

リバースプロキシの役割.
- ロードバランス.
- コンテンツキャッシュ.
- HTTPS通信の終端化.

nginxでリクエストをプロキシするにはproxy_passディレクティブを指定する

プロキシする際に指定すべきヘッダ

下記の設定はどこでも使われている可能性がある。

自分が見たnginxのconfigファイルには書いてあった

ヘッダフィールド名 指定するパラメータ 説明
X-Forwarded-Host $host ユーザのリクエストに含まれるホスト名を指定する
X-Forwarded-For $proxy_add_x_for_warded_for リクエストが経由したアドレスを全て指定する
X-Forwarded-Proto $scheme ユーザのリクエストが使用したHTTPスキームを指定する

本書で記載されているphp-fpm.confは足りない部分があったので補完した。

[www]
listen = /var/run/php-fpm.sock
listen.owner = nginx
listen.group = nginx
listen.mode = 0660

user = nginx
group = nginx

pm = dynamic
pm.max_children = 8
pm.start_servers = 4
pm.min_spare_servers = 2
pm.max_spare_servers = 4
pm.max_requests = 500

; security
security.limit_extensions = .php

; timeouts
request_terminate_timeout = 30s
request_slowlog_timeout = 10s
slowlog = /var/log/php-fpm/slow.log

; logging
catch_workers_output = yes
php_admin_value[error_log] = /var/log/php-fpm/error.log
php_admin_flag[log_errors] = on

; process management
pm.process_idle_timeout = 10s
pm.max_spawn_rate = 32

; status page (optional)
pm.status_path = /status
ping.path = /ping
ping.response = pong

以下が必須項目.
1. listen.owner/group/mode - ソケットファイルのパーミッション。これがないとnginxがアクセスできない.
2. user/group - PHP-FPMの実行ユーザー。セキュリティ上重要.
3. security.limit_extensions - .php以外の実行を防ぐ。セキュリティ必須.

以下項目ほぼ必須.
4. request_terminate_timeout - 暴走スクリプト対策.
5. catch_workers_output - アプリのエラーをログに出力.
6. slowlog - パフォーマンス問題の調査に必須.

第7章 大規模コンテンツ配信サーバの構築

以下の3つが比較的問題になりやすいリソース

確かにオブザーバビリティの面でよく取り扱われる.
- CPU.
- ディスク I/O.
- ネットワーク.

負荷を確認する際によく利用するコマンド.
- top).
- dstat
- ss -s.

ssコマンドの代わりにnetstatコマンドを使う場合もある。

zenn.dev

スケーリングを行う方法は以下の2つが考えられる 1. キャッシュサーバーにディスクを増設してスケールアップする 2. 新たにキャッシュサーバを追加する

第8章 Webサーバの運用とメトリクスモニタリング

fluentdの勉強

エンジニア養成読本シリーズ

gihyo.jp

上の本は古いので今勉強するならこれがいいかも

gihyo.jp

公式ドキュメント

docs.fluentd.org

少し古いが全体的にまとめて色々な技術学ぶならこれかな

gihyo.jp

以下のツールを解析でおすすめされたが今は使われているのだろうか?

Norikra

norikra.github.io

GrowthForecat

kazeburo.github.io

より進んだ解析を行うために、ログをHDFSAmazon Redshift, Google BigQuery, Treasure Dateに出力し、長期間の集計を行うことが必要。

www.ibm.com

第9章 Luaによるnginxの拡張

Luaを使ってのnginxの拡張は今は使わないので斜め読み程度にとどめた。 ngx_luaを使うらしい。

第10章 OpenResty

openresty.org

初めて聞くフレームワークなのとあまり使われてなさそうなので流し読みした。

まとめ

Nginxのファイルを読む時に少しは抵抗感がなくなった気がする。

Nginxを用いたアーキテクチャを考える時にリファレンス的に使えるかもしれない。

早速会社のconfファイルを眺めてみよう。

kubernetes-the-hard-way-on-proxmox をやってみた

動機

RAM32GBの中華製ミニデスクトップを買ったので、Kubernetesの学習に良いらしいのでやってみた。

github.com

Prerequisites

概要

  • proxmoxのvmを切ってgatewayとcontrolleプレーンとworkerノードを作成する。

gatewayのネットワークドライブは2つ用意して、ローカルのネットワーク環境とKubernetesのネットワーク環境を用意する。

Installing the Client Tools

概要

Provisioning Compute Resources

概要

  1. ネットワーク設定
  2. VMIPアドレス
  3. ファイアウォール設定
  4. VM間の通信

各ノード間の通信テストやgateway-01のFWルールや各ノード間の/etc/hostsファイルの設定をする。

  • 下記のtmuxコマンドは全てのペインに同じコマンドを送信できて便利
[prefix]Ctrl+b then :
setw synchronize-panes on
  • for文でipぶん回すのインフラエンジニアっぽい
ubuntu@gateway-01:~$ for i in 10 11 12 20 21 22; do echo "Testing 192.168.8.$i"; ping -c 2 192.168.8.$i; done
Testing 192.168.8.10
PING 192.168.8.10 (192.168.8.10) 56(84) bytes of data.
64 bytes from 192.168.8.10: icmp_seq=1 ttl=64 time=0.190 ms
64 bytes from 192.168.8.10: icmp_seq=2 ttl=64 time=0.299 ms

--- 192.168.8.10 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1030ms
rtt min/avg/max/mdev = 0.190/0.244/0.299/0.054 ms
Testing 192.168.8.11
PING 192.168.8.11 (192.168.8.11) 56(84) bytes of data.
64 bytes from 192.168.8.11: icmp_seq=1 ttl=64 time=0.141 ms
64 bytes from 192.168.8.11: icmp_seq=2 ttl=64 time=0.222 ms

--- 192.168.8.11 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1022ms
rtt min/avg/max/mdev = 0.141/0.181/0.222/0.040 ms
Testing 192.168.8.12
PING 192.168.8.12 (192.168.8.12) 56(84) bytes of data.
64 bytes from 192.168.8.12: icmp_seq=1 ttl=64 time=0.158 ms
64 bytes from 192.168.8.12: icmp_seq=2 ttl=64 time=0.272 ms

--- 192.168.8.12 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1021ms
rtt min/avg/max/mdev = 0.158/0.215/0.272/0.057 ms
Testing 192.168.8.20
PING 192.168.8.20 (192.168.8.20) 56(84) bytes of data.
64 bytes from 192.168.8.20: icmp_seq=1 ttl=64 time=0.157 ms
64 bytes from 192.168.8.20: icmp_seq=2 ttl=64 time=0.249 ms

--- 192.168.8.20 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1021ms
rtt min/avg/max/mdev = 0.157/0.203/0.249/0.046 ms
Testing 192.168.8.21
PING 192.168.8.21 (192.168.8.21) 56(84) bytes of data.
64 bytes from 192.168.8.21: icmp_seq=1 ttl=64 time=0.153 ms
64 bytes from 192.168.8.21: icmp_seq=2 ttl=64 time=0.335 ms

--- 192.168.8.21 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1021ms
rtt min/avg/max/mdev = 0.153/0.244/0.335/0.091 ms
Testing 192.168.8.22
PING 192.168.8.22 (192.168.8.22) 56(84) bytes of data.
64 bytes from 192.168.8.22: icmp_seq=1 ttl=64 time=0.164 ms
64 bytes from 192.168.8.22: icmp_seq=2 ttl=64 time=0.242 ms

--- 192.168.8.22 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1021ms
rtt min/avg/max/mdev = 0.164/0.203/0.242/0.039 ms

Provisioning a CA and Generating TLS Certificates

概要

このステップでは以下を実施します:
1. Certificate Authority (CA) の作成
2. コンポーネント用のTLS証明書の生成:
- Admin用クライアント証明書.
- Kubelet用クライアント証明書(各ワーカーノード).
- Controller Manager用クライアント証明書.
- Kube Proxy用クライアント証明書.
- Scheduler用クライアント証明書.
- Kubernetes APIサーバー用証明書.
- Service Account用キーペア.

なぜ証明書が必要?

Kubernetesコンポーネント間通信は全て暗号化され、相互に認証される必要がある:
- APIサーバー ↔ etcd.
- APIサーバー ↔ kubelet.
- kubectl ↔ APIサーバー.
- など.

  • CA設定ファイルの作成
cat > ca-config.json <<EOF
{
  "signing": {
    "default": {
      "expiry": "8760h"
    },
    "profiles": {
      "kubernetes": {
        "usages": ["signing", "key encipherment", "server auth", "client auth"],
        "expiry": "8760h"
      }
    }
  }
}
EOF
  • CA証明書署名リクエスト(CSR)の作成
cat > ca-csr.json <<EOF
{
  "CN": "Kubernetes",
  "Key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "JP",
      "L": "Tokyo",
      "O": "Kubernetes",
      "OU": "CA",
      "ST": "Tokyo",
    }
  ]
}
EOF
cfssl gencert -initca ca-csr.json | cfssljson -bare ca
  • Admin用クライアント証明書
cat > admin-csr.json <<EOF
{
  "CN": "admin",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "JP",
      "L": "Tokyo",
      "O": "system:masters",
      "OU": "Kubernetes The Hard Way",
      "ST": "Tokyo"
    }
  ]
}
EOF
  • 証明書を作成
cfssl gencert \
  -ca=ca.pem \
  -ca-key=ca-key.pem \
  -config=ca-config.json \
  -profile=kubernetes \
  admin-csr.json | cfssljson -bare admin
  • Kubelet用クライアント証明書.
  • worker-0
cat > worker-0-csr.json <<EOF
{
  "CN": "system:node:worker-0",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "JP",
      "L": "Tokyo",
      "O": "system:nodes",
      "OU": "Kubernetes The Hard Way",
      "ST": "Tokyo"
    }
  ]
}
EOF

cfssl gencert \
  -ca=ca.pem \
  -ca-key=ca-key.pem \
  -config=ca-config.json \
  -hostname=worker-0,192.168.8.20 \
  -profile=kubernetes \
  worker-0-csr.json | cfssljson -bare worker-0
  • Controller Manager用クライアント証明書
cat > kube-controller-manager-csr.json <<EOF
{
  "CN": "system:kube-controller-manager",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "JP",
      "L": "Tokyo",
      "O": "system:kube-controller-manager",
      "OU": "Kubernetes The Hard Way",
      "ST": "Tokyo"
    }
  ]
}
EOF

cfssl gencert \
  -ca=ca.pem \
  -ca-key=ca-key.pem \
  -config=ca-config.json \
  -profile=kubernetes \
  kube-controller-manager-csr.json | cfssljson -bare kube-controller-manager
  • Kube Proxy用クライアント証明書
cat > kube-proxy-csr.json <<EOF
{
  "CN": "system:kube-proxy",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "JP",
      "L": "Tokyo",
      "O": "system:node-proxier",
      "OU": "Kubernetes The Hard Way",
      "ST": "Tokyo"
    }
  ]
}
EOF

cfssl gencert \
  -ca=ca.pem \
  -ca-key=ca-key.pem \
  -config=ca-config.json \
  -profile=kubernetes \
  kube-proxy-csr.json | cfssljson -bare kube-proxy
  • Scheduler用クライアント証明書
cat > kube-scheduler-csr.json <<EOF
{
  "CN": "system:kube-scheduler",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "JP",
      "L": "Tokyo",
      "O": "system:kube-scheduler",
      "OU": "Kubernetes The Hard Way",
      "ST": "Tokyo"
    }
  ]
}
EOF

cfssl gencert \
  -ca=ca.pem \
  -ca-key=ca-key.pem \
  -config=ca-config.json \
  -profile=kubernetes \
  kube-scheduler-csr.json | cfssljson -bare kube-scheduler
KUBERNETES_HOSTNAMES=kubernetes,kubernetes.default,kubernetes.default.svc,kubernetes.default.svc.cluster,kubernetes.svc.cluster.local

cat > kubernetes-csr.json <<EOF
{
  "CN": "kubernetes",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "JP",
      "L": "Tokyo",
      "O": "kubernetes",
      "OU": "Kubernetes The Hard Way",
      "ST": "Tokyo"
    }
  ]
}
EOF

cfssl gencert \
  -ca=ca.pem \
  -ca-key=ca-key.pem \
  -config=ca-config.json \
  -hostname=10.32.0.1,192.168.8.10,192.168.8.11,192.168.8.12,192.168.8.1,192.168.3.18,127.0.0.1,${KUBERNETES_HOSTNAMES} \
  -profile=kubernetes \
  kubernetes-csr.json | cfssljson -bare kubernetes
  • Service Account用キーペア
cat > service-account-csr.json <<EOF
{
  "CN": "service-accounts",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "JP",
      "L": "Tokyo",
      "O": "Kubernetes",
      "OU": "Kubernetes The Hard Way",
      "ST": "Tokyo"
    }
  ]
}
EOF

cfssl gencert \
  -ca=ca.pem \
  -ca-key=ca-key.pem \
  -config=ca-config.json \
  -profile=kubernetes \
  service-account-csr.json | cfssljson -bare service-account

Generating Kubernetes Configuration Files for Authentication

概要

kubelet,kube-proxy,kube-scheduler,admin用にkubeconfigファイルを作成する。
kubeconfigファイルは、Kubernetesクラスターへの接続情報を含む設定ファイル。
コンポーネントが使用するkubeconfigには以下の情報が含まれる:
- クラスター情報(APIサーバーのアドレス、CA証明書).
- ユーザー認証情報(クライアント証明書、秘密鍵).
- コンテキスト(どのクラスターにどのユーザーで接続するか).

KUBERNETES_PUBLIC_ADDRESS=192.168.3.18
  • kubelet用kubeconfigの生成
  • worker-0用
kubectl config set-cluster kubernetes-the-hard-way \
  --certificate-authority=ca.pem \
  --embed-certs=true \
  --server=https://${KUBERNETES_PUBLIC_ADDRESS}:6443 \
  --kubeconfig=worker-0.kubeconfig

kubectl config set-credentials system:node:worker-0 \
  --client-certificate=worker-0.pem \
  --client-key=worker-0-key.pem \
  --embed-certs=true \
  --kubeconfig=worker-0.kubeconfig

kubectl config set-context default \
  --cluster=kubernetes-the-hard-way \
  --user=system:node:worker-0 \
  --kubeconfig=worker-0.kubeconfig

kubectl config use-context default --kubeconfig=worker-0.kubeconfig
  • kube-proxy用kubeconfigの生成
kubectl config set-cluster kubernetes-the-hard-way \
  --certificate-authority=ca.pem \
  --embed-certs=true \
  --server=https://${KUBERNETES_PUBLIC_ADDRESS}:6443 \
  --kubeconfig=kube-proxy.kubeconfig

kubectl config set-credentials system:kube-proxy \
  --client-certificate=kube-proxy.pem \
  --client-key=kube-proxy-key.pem \
  --embed-certs=true \
  --kubeconfig=kube-proxy.kubeconfig

kubectl config set-context default \
  --cluster=kubernetes-the-hard-way \
  --user=system:kube-proxy \
  --kubeconfig=kube-proxy.kubeconfig

kubectl config use-context default --kubeconfig=kube-proxy.kubeconfig
  • kube-controller-manager用kubeconfigの生成
kubectl config set-cluster kubernetes-the-hard-way \
  --certificate-authority=ca.pem \
  --embed-certs=true \
  --server=https://127.0.0.1:6443 \
  --kubeconfig=kube-controller-manager.kubeconfig

kubectl config set-credentials system:kube-controller-manager \
  --client-certificate=kube-controller-manager.pem \
  --client-key=kube-controller-manager-key.pem \
  --embed-certs=true \
  --kubeconfig=kube-controller-manager.kubeconfig

kubectl config set-context default \
  --cluster=kubernetes-the-hard-way \
  --user=system:kube-controller-manager \
  --kubeconfig=kube-controller-manager.kubeconfig

kubectl config use-context default --kubeconfig=kube-controller-manager.kubeconfig
  • kube-scheduler用kubeconfigの生成
kubectl config set-cluster kubernetes-the-hard-way \
  --certificate-authority=ca.pem \
  --embed-certs=true \
  --server=https://127.0.0.1:6443 \
  --kubeconfig=kube-scheduler.kubeconfig

kubectl config set-credentials system:kube-scheduler \
  --client-certificate=kube-scheduler.pem \
  --client-key=kube-scheduler-key.pem \
  --embed-certs=true \
  --kubeconfig=kube-scheduler.kubeconfig

kubectl config set-context default \
  --cluster=kubernetes-the-hard-way \
  --user=system:kube-scheduler \
  --kubeconfig=kube-scheduler.kubeconfig

kubectl config use-context default --kubeconfig=kube-scheduler.kubeconfig
  • admin用kubeconfigの生成
kubectl config set-cluster kubernetes-the-hard-way \
  --certificate-authority=ca.pem \
  --embed-certs=true \
  --server=https://${KUBERNETES_PUBLIC_ADDRESS}:6443 \
  --kubeconfig=admin.kubeconfig

kubectl config set-credentials admin \
  --client-certificate=admin.pem \
  --client-key=admin-key.pem \
  --embed-certs=true \
  --kubeconfig=admin.kubeconfig

kubectl config set-context default \
  --cluster=kubernetes-the-hard-way \
  --user=admin \
  --kubeconfig=admin.kubeconfig

kubectl config use-context default --kubeconfig=admin.kubeconfig

Generating the Data Encryption Config and Key

概要

暗号化キーの生成と暗号化設定ファイルを作成する。
Kubernetesは、etcdに保存される機密情報(Secrets)を暗号化できる。
これにより:
- etcdのバックアップが漏洩しても、Secretの内容は保護される.
- etcdに直接アクセスされても、データは暗号化されている.

  • 暗号化キーの生成
ENCPYPTION_KEY=$(head -c 32 /dev/urandom | base64)

echo $ENCPYPTION_KEY
  • 暗号化設定ファイルの作成
cat > encryption-config.yaml <<EOF
kind: EncryptionConfig
apiVersion: v1
resources:
  - resources:
      - secrets
    providers:
      - aescbc:
          keys:
            - name: key1
              secret: ${ENCPYPTION_KEY}
      - identity: {}
EOF

Bootstrapping the etcd Cluster

概要

etcdは、Kubernetesの全てのクラスター状態を保存する分散キーバリューストア。
このステップでは:
1. 必要なファイルをcontrollerノードに配布.
2. etcdバイナリのダウンロード・インストール.
3. 3ノード構成の高可用性etcdクラスターを構築.

  • 証明書とファイルの配布
# controller-0への配布
scp ca.pem kubernetes-key.pem kubernetes.pem ubuntu@192.168.8.10:~/


# controller-1への配布
scp ca.pem kubernetes-key.pem kubernetes.pem ubuntu@192.168.8.11:~/

# controller-2への配布
scp ca.pem kubernetes-key.pem kubernetes.pem ubuntu@192.168.8.12:~/

---

ubuntu@gateway-01:~/k8s-certs$ scp ca.pem kubernetes-key.pem kubernetes.pem ubuntu@192.168.8.10:~/
ca.pem                                                                           100% 1306     1.9MB/s   00:00
kubernetes-key.pem                                                               100% 1679     3.6MB/s   00:00
kubernetes.pem                                                                   100% 1659     4.4MB/s   00:00
ubuntu@gateway-01:~/k8s-certs$ scp ca.pem kubernetes-key.pem kubernetes.pem ubuntu@192.168.8.11:~/
ca.pem                                                                           100% 1306     3.4MB/s   00:00
kubernetes-key.pem                                                               100% 1679     5.6MB/s   00:00
kubernetes.pem                                                                   100% 1659     7.9MB/s   00:00
ubuntu@gateway-01:~/k8s-certs$ scp ca.pem kubernetes-key.pem kubernetes.pem ubuntu@192.168.8.12:~/
ca.pem                                                                           100% 1306     3.6MB/s   00:00
kubernetes-key.pem                                                               100% 1679     6.7MB/s   00:00
kubernetes.pem                                                                   100% 1659     7.0MB/s   00:00
ubuntu@gateway-01:~/k8s-certs$
  • ウィンドウを分割して、etcdバイナリのダウンロードとインストール
wget -q --show-progress --https-only --timestamping \
  "https://github.com/etcd-io/etcd/releases/download/v3.5.12/etcd-v3.5.12-linux-amd64.tar.gz"

tar -xvf etcd-v3.5.12-linux-amd64.tar.gz

sudo mv etcd-v3.5.12-linux-amd64/etcd* /usr/local/bin/

etcd --version
etcdctl version

---

# controller-0の出力

ubuntu@controller-0:~$ wget -q --show-progress --https-only --timestamping \
  "https://github.com/etcd-io/etcd/releases/download/v3.5.12/etcd-v3.5.12-linux-amd64.tar.gz"
etcd-v3.5.12-linux-amd64.tar 100%[=============================================>]  19.40M  17.9MB/s    in 1.1s
ubuntu@controller-0:~$ ll
total 19912
drwxr-x--- 4 ubuntu ubuntu     4096 Oct 20 21:54 ./
drwxr-xr-x 3 root   root       4096 Oct 14 21:45 ../
-rw------- 1 ubuntu ubuntu      827 Oct 17 22:11 .bash_history
-rw-r--r-- 1 ubuntu ubuntu      220 Jan  6  2022 .bash_logout
-rw-r--r-- 1 ubuntu ubuntu     3771 Jan  6  2022 .bashrc
drwx------ 2 ubuntu ubuntu     4096 Oct 14 21:45 .cache/
-rw-rw-r-- 1 ubuntu ubuntu     1306 Oct 20 21:46 ca.pem
-rw-rw-r-- 1 ubuntu ubuntu 20337842 Jan 31  2024 etcd-v3.5.12-linux-amd64.tar.gz
-rw------- 1 ubuntu ubuntu     1679 Oct 20 21:46 kubernetes-key.pem
-rw-rw-r-- 1 ubuntu ubuntu     1659 Oct 20 21:46 kubernetes.pem
-rw-r--r-- 1 ubuntu ubuntu      807 Jan  6  2022 .profile
drwx------ 2 ubuntu ubuntu     4096 Oct 14 21:45 .ssh/
-rw-r--r-- 1 ubuntu ubuntu        0 Oct 14 21:50 .sudo_as_admin_successful
-rw-rw-r-- 1 ubuntu ubuntu      165 Oct 20 21:54 .wget-hsts
ubuntu@controller-0:~$ tar -xvf etcd-v3.5.12-linux-amd64.tar.gz
etcd-v3.5.12-linux-amd64/
etcd-v3.5.12-linux-amd64/README.md
etcd-v3.5.12-linux-amd64/READMEv2-etcdctl.md
etcd-v3.5.12-linux-amd64/etcdutl
etcd-v3.5.12-linux-amd64/etcdctl
etcd-v3.5.12-linux-amd64/Documentation/
etcd-v3.5.12-linux-amd64/Documentation/README.md
etcd-v3.5.12-linux-amd64/Documentation/dev-guide/
etcd-v3.5.12-linux-amd64/Documentation/dev-guide/apispec/
etcd-v3.5.12-linux-amd64/Documentation/dev-guide/apispec/swagger/
etcd-v3.5.12-linux-amd64/Documentation/dev-guide/apispec/swagger/v3election.swagger.json
etcd-v3.5.12-linux-amd64/Documentation/dev-guide/apispec/swagger/rpc.swagger.json
etcd-v3.5.12-linux-amd64/Documentation/dev-guide/apispec/swagger/v3lock.swagger.json
etcd-v3.5.12-linux-amd64/README-etcdutl.md
etcd-v3.5.12-linux-amd64/README-etcdctl.md
etcd-v3.5.12-linux-amd64/etcd
ubuntu@controller-0:~$ sudo mv etcd-v3.5.12-linux-amd64/etcd* /usr/local/bin/
[sudo] password for ubuntu:
ubuntu@controller-0:~$ etcd --version
etcdctl version
etcd Version: 3.5.12
Git SHA: e7b3bb6cc
Go Version: go1.20.13
Go OS/Arch: linux/amd64
etcdctl version: 3.5.12
API version: 3.5
ubuntu@controller-0:~$
  • etcdの設定
# 設定ディレクトリとデータディレクトリの作成
sudo mkdir -p /etc/etcd /var/lib/etcd
sudo chmod 700 /var/lib/etcd

# 証明書のコピー
sudo cp ~/ca.pem ~/kubernetes-key.pem ~/kubernetes.pem /etc/etcd/

---
# controller-0の出力 cpで途中入力を求められたが無事に/etc/etcdにコピーされている
ubuntu@controller-0:~$ sudo mkdir -p /etc/etcd /var/lib/etcd
ubuntu@controller-0:~$ sudo chmod 700 /var/lib/etcd
ubuntu@controller-0:~$ sudo cp ~/ca.pem ~/kubernetes-key.pem ~/kubernetes.pem /etc/etcd/
>
> ^C
ubuntu@controller-0:~$ ll
total 19916
drwxr-x--- 5 ubuntu ubuntu     4096 Oct 20 21:55 ./
drwxr-xr-x 3 root   root       4096 Oct 14 21:45 ../
-rw------- 1 ubuntu ubuntu      827 Oct 17 22:11 .bash_history
-rw-r--r-- 1 ubuntu ubuntu      220 Jan  6  2022 .bash_logout
-rw-r--r-- 1 ubuntu ubuntu     3771 Jan  6  2022 .bashrc
drwx------ 2 ubuntu ubuntu     4096 Oct 14 21:45 .cache/
-rw-rw-r-- 1 ubuntu ubuntu     1306 Oct 20 21:46 ca.pem
drwxr-xr-x 3 ubuntu ubuntu     4096 Oct 20 21:55 etcd-v3.5.12-linux-amd64/
-rw-rw-r-- 1 ubuntu ubuntu 20337842 Jan 31  2024 etcd-v3.5.12-linux-amd64.tar.gz
-rw------- 1 ubuntu ubuntu     1679 Oct 20 21:46 kubernetes-key.pem
-rw-rw-r-- 1 ubuntu ubuntu     1659 Oct 20 21:46 kubernetes.pem
-rw-r--r-- 1 ubuntu ubuntu      807 Jan  6  2022 .profile
drwx------ 2 ubuntu ubuntu     4096 Oct 14 21:45 .ssh/
-rw-r--r-- 1 ubuntu ubuntu        0 Oct 14 21:50 .sudo_as_admin_successful
-rw-rw-r-- 1 ubuntu ubuntu      165 Oct 20 21:54 .wget-hsts
ubuntu@controller-0:~$ ll /etc/etcd
total 20
drwxr-xr-x  2 root root 4096 Oct 20 21:59 ./
drwxr-xr-x 97 root root 4096 Oct 20 21:59 ../
-rw-r--r--  1 root root 1306 Oct 20 21:59 ca.pem
-rw-------  1 root root 1679 Oct 20 21:59 kubernetes-key.pem
-rw-r--r--  1 root root 1659 Oct 20 21:59 kubernetes.pem
ubuntu@controller-0:~$
  • etcdのsystemdサービスファイル作成 同期モードは一時解除

  • controller-0での作業

INTERNAL_IP=192.168.8.10
ETCD_NAME=controller-0

cat <<EOF | sudo tee /etc/systemd/system/etcd.service
[Unit]
Description=etcd
Documentation=https://github.cm/coreos

[Service]
Type=notify
ExecStart=/usr/local/bin/etcd \\
  --name ${ETCD_NAME} \\
  --cert-file=/etc/etcd/kubernetes.pem \\
  --key-file=/etc/etcd/kubernetes-key.pem \\
  --peer-cert-file=/etc/etcd/kubernetes.pem \\
  --peer-key-file=/etc/etcd/kubernetes-key.pem \\
  --trusted-ca-file=/etc/etcd/ca.pem \\
  --peer-trusted-ca-file=/etc/etcd/ca.pem \\
  --peer-client-cert-auth \\
  --client-cert-auth \\
  --initial-advertise-peer-urls https://${INTERNAL_IP}:2380 \\
  --listen-peer-urls https://${INTERNAL_IP}:2380 \\
  --listen-client-urls https://${INTERNAL_IP}:2379,https://127.0.0.1:2379 \\
  --advertise-client-urls https://${INTERNAL_IP}:2379 \\
  --initial-cluster-token etcd-cluster-0 \\
  --initial-cluster controller-0=https://192.168.8.10:2380,controller-1=https://192.168.8.11:2380,controller-2=https://192.168.8.12:2380 \\
  --initial-cluster-state new \\
  --data-dir=/var/lib/etcd
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF
  • etcdサービスの起動 同期モードを有効化しておく

  • 全controllerノードで同時実行

sudo systemctl daemon-reload
sudo systemctl enable etcd
sudo systemctl start etcd
sudo systemctl status etcd

---
#controller-0の出力

ubuntu@controller-0:~$ sudo systemctl daemon-reload
ubuntu@controller-0:~$ sudo systemctl enable etcd
Created symlink /etc/systemd/system/multi-user.target.wants/etcd.service → /etc/systemd/system/etcd.service.
ubuntu@controller-0:~$ sudo systemctl start etcd
ubuntu@controller-0:~$ sudo systemctl status etcd
● etcd.service - etcd
     Loaded: loaded (/etc/systemd/system/etcd.service; enabled; vendor preset: enabled)
     Active: active (running) since Mon 2025-10-20 22:33:49 UTC; 26s ago
       Docs: https://github.cm/coreos
   Main PID: 2285 (etcd)
      Tasks: 8 (limit: 2218)
     Memory: 12.8M
        CPU: 433ms
     CGroup: /system.slice/etcd.service
             └─2285 /usr/local/bin/etcd --name controller-0 --cert-file=/etc/etcd/kubernetes.pem --key-file=/etc/e>

Oct 20 22:33:49 controller-0 etcd[2285]: {"level":"info","ts":"2025-10-20T22:33:49.03866Z","caller":"etcdserver/se>
Oct 20 22:33:49 controller-0 etcd[2285]: {"level":"info","ts":"2025-10-20T22:33:49.040276Z","caller":"embed/serve.>
Oct 20 22:33:49 controller-0 etcd[2285]: {"level":"info","ts":"2025-10-20T22:33:49.040356Z","caller":"etcdmain/mai>
Oct 20 22:33:49 controller-0 etcd[2285]: {"level":"info","ts":"2025-10-20T22:33:49.040454Z","caller":"etcdmain/mai>
Oct 20 22:33:49 controller-0 systemd[1]: Started etcd.
Oct 20 22:33:49 controller-0 etcd[2285]: {"level":"info","ts":"2025-10-20T22:33:49.046876Z","caller":"embed/serve.>
Oct 20 22:33:49 controller-0 etcd[2285]: {"level":"info","ts":"2025-10-20T22:33:49.054099Z","caller":"etcdserver/s>
Oct 20 22:33:49 controller-0 etcd[2285]: {"level":"info","ts":"2025-10-20T22:33:49.058485Z","caller":"membership/c>
Oct 20 22:33:49 controller-0 etcd[2285]: {"level":"info","ts":"2025-10-20T22:33:49.058665Z","caller":"api/capabili>
Oct 20 22:33:49 controller-0 etcd[2285]: {"level":"info","ts":"2025-10-20T22:33:49.058807Z","caller":"etcdserver/s>
ubuntu@controller-0:~$
sudo ETCDCTL_API=3 etcdctl member list \
  --endpoints=https://127.0.0.1:2379 \
  --cacert=/etc/etcd/ca.pem \
  --cert=/etc/etcd/kubernetes.pem \
  --key=/etc/etcd/kubernetes-key.pem

---
# controller-0の出力
ubuntu@controller-0:~$ sudo ETCDCTL_API=3 etcdctl member list \
  --endpoints=https://127.0.0.1:2379 \
  --cacert=/etc/etcd/ca.pem \
  --cert=/etc/etcd/kubernetes.pem \
  --key=/etc/etcd/kubernetes-key.pem
286ea08a76969776, started, controller-1, https://192.168.8.11:2380, https://192.168.8.11:2379, false
671e6154d5107277, started, controller-2, https://192.168.8.12:2380, https://192.168.8.12:2379, false
7e87d57c936a3019, started, controller-0, https://192.168.8.10:2380, https://192.168.8.10:2379, false
ubuntu@controller-0:~$

Bootstrapping the Kubernetes Control Plane

概要

このステップでは、3つのcontrollerノードに以下のコンポーネントをインストールする:
1. kube-apiserver - Kubernetes APIのフロントエンド.
2. kube-controller-manager - クラスターの状態を管理.
3. kube-scheduler - Podの配置を決定.
4. RBACの設定.
5. nginxでkubeAPI用のロードバランサーを作成.

  • 必要なファイルの配布
# controller-0への配布
scp ca.pem ca-key.pem kubernetes-key.pem kubernetes.pem \
  service-account-key.pem service-account.pem \
  encryption-config.yaml \
  kube-controller-manager.kubeconfig \
  kube-scheduler.kubeconfig \
  ubuntu@192.168.8.10:~/


# controller-1への配布
scp ca.pem ca-key.pem kubernetes-key.pem kubernetes.pem \
  service-account-key.pem service-account.pem \
  encryption-config.yaml \
  kube-controller-manager.kubeconfig \
  kube-scheduler.kubeconfig \
  ubuntu@192.168.8.11:~/


# controller-2への配布
scp ca.pem ca-key.pem kubernetes-key.pem kubernetes.pem \
  service-account-key.pem service-account.pem \
  encryption-config.yaml \
  kube-controller-manager.kubeconfig \
  kube-scheduler.kubeconfig \
  ubuntu@192.168.8.12:~/

---

ubuntu@gateway-01:~/k8s-certs$ scp ca.pem ca-key.pem kubernetes-key.pem kubernetes.pem \
  service-account-key.pem service-account.pem \
  encryption-config.yaml \
  kube-controller-manager.kubeconfig \
  kube-scheduler.kubeconfig \
  ubuntu@192.168.8.10:~/

ca.pem                                                                           100% 1306     1.6MB/s   00:00
ca-key.pem                                                                       100% 1675     3.4MB/s   00:00
kubernetes-key.pem                                                               100% 1679     4.4MB/s   00:00
kubernetes.pem                                                                   100% 1659     4.7MB/s   00:00
service-account-key.pem                                                          100% 1675     4.1MB/s   00:00
service-account.pem                                                              100% 1428     4.0MB/s   00:00
encryption-config.yaml                                                           100%  240   582.7KB/s   00:00
kube-controller-manager.kubeconfig                                               100% 6355    14.9MB/s   00:00
kube-scheduler.kubeconfig                                                        100% 6305    13.9MB/s   00:00
ubuntu@gateway-01:~/k8s-certs$ scp ca.pem ca-key.pem kubernetes-key.pem kubernetes.pem \
  service-account-key.pem service-account.pem \
  encryption-config.yaml \
  kube-controller-manager.kubeconfig \
  kube-scheduler.kubeconfig \
  ubuntu@192.168.8.11:~/

ca.pem                                                                           100% 1306     3.5MB/s   00:00
ca-key.pem                                                                       100% 1675     6.4MB/s   00:00
kubernetes-key.pem                                                               100% 1679     6.2MB/s   00:00
kubernetes.pem                                                                   100% 1659     6.8MB/s   00:00
service-account-key.pem                                                          100% 1675     8.2MB/s   00:00
service-account.pem                                                              100% 1428     6.9MB/s   00:00
encryption-config.yaml                                                           100%  240     1.3MB/s   00:00
kube-controller-manager.kubeconfig                                               100% 6355    24.7MB/s   00:00
kube-scheduler.kubeconfig                                                        100% 6305    28.0MB/s   00:00
ubuntu@gateway-01:~/k8s-certs$ scp ca.pem ca-key.pem kubernetes-key.pem kubernetes.pem \
  service-account-key.pem service-account.pem \
  encryption-config.yaml \
  kube-controller-manager.kubeconfig \
  kube-scheduler.kubeconfig \
  ubuntu@192.168.8.12:~/

ca.pem                                                                           100% 1306     3.6MB/s   00:00
ca-key.pem                                                                       100% 1675     6.5MB/s   00:00
kubernetes-key.pem                                                               100% 1679     7.3MB/s   00:00
kubernetes.pem                                                                   100% 1659     7.9MB/s   00:00
service-account-key.pem                                                          100% 1675     8.2MB/s   00:00
service-account.pem                                                              100% 1428     7.2MB/s   00:00
encryption-config.yaml                                                           100%  240     1.3MB/s   00:00
kube-controller-manager.kubeconfig                                               100% 6355    25.2MB/s   00:00
kube-scheduler.kubeconfig                                                        100% 6305    28.1MB/s   00:00
ubuntu@gateway-01:~/k8s-certs$
  • Kubernetesバイナリのダウンロードとインストール.
    同期モードを有効化しておく.
  • Kubernetesバイナリのダウンロード.
sudo mkdir -p /etc/kubernetes/config

# Kubernetes v1.29.1バイナリ
wget -q --show-progress --https-only --timestamping \
  "https://dl.k8s.io/v1.29.1/bin/linux/amd64/kube-apiserver" \
  "https://dl.k8s.io/v1.29.1/bin/linux/amd64/kube-controller-manager" \
  "https://dl.k8s.io/v1.29.1/bin/linux/amd64/kube-scheduler" \
  "https://dl.k8s.io/v1.29.1/bin/linux/amd64/kubectl" 

---
# controller-0の出力

ubuntu@controller-0:~$ sudo mkdir -p /etc/kubernetes/config
[sudo] password for ubuntu:
ubuntu@controller-0:~$ ll /etc/kubernetes/config/
total 8
drwxr-xr-x 2 root root 4096 Oct 21 22:21 ./
drwxr-xr-x 3 root root 4096 Oct 21 22:21 ../
ubuntu@controller-0:~$ wget -q --show-progress --https-only --timestamping \
  "https://dl.k8s.io/v1.29.1/bin/linux/amd64/kube-apiserver" \
  "https://dl.k8s.io/v1.29.1/bin/linux/amd64/kube-controller-manager" \
  "https://dl.k8s.io/v1.29.1/bin/linux/amd64/kube-scheduler" \
  "https://dl.k8s.io/v1.29.1/bin/linux/amd64/kubectl"

kube-apiserver               100%[=============================================>] 117.99M  3.11MB/s    in 41s
kube-controller-manager      100%[=============================================>] 112.87M  2.21MB/s    in 42s
kube-scheduler               100%[=============================================>]  53.35M  3.06MB/s    in 19s
kubectl                      100%[=============================================>]  47.40M  5.32MB/s    in 8.2s
ubuntu@controller-0:~$

  • バイナリのインストール
chmod +x kube-apiserver kube-controller-manager kube-scheduler kubectl

sudo mv kube-apiserver kube-controller-manager kube-scheduler kubectl /usr/local/bin/

kubectl version --client

---

# controller-0の出力
ubuntu@controller-0:~$ chmod +x kube-apiserver kube-controller-manager kube-scheduler kubectl
ubuntu@controller-0:~$ sudo mv kube-apiserver kube-controller-manager kube-scheduler kubectl /usr/local/bin/
ubuntu@controller-0:~$ kubectl version --client
Client Version: v1.29.1
Kustomize Version: v5.0.4-0.20230601165947-6ce0bf390ce3
ubuntu@controller-0:~$
  • kube-apiserverの設定.
  • 証明書と設定ファイルの配置.
sudo mkdir -p /var/lib/kubernetes/

sudo cp ca.pem ca-key.pem kubernetes-key.pem kubernetes.pem \
  service-account-key.pem service-account.pem \
  encryption-config.yaml /var/lib/kubernetes/

---
# controller-0の出力

ubuntu@controller-0:~$ sudo mkdir -p /var/lib/kubernetes/
ubuntu@controller-0:~$ sudo cp ca.pem ca-key.pem kubernetes-key.pem kubernetes.pem \
  service-account-key.pem service-account.pem \
  encryption-config.yaml /var/lib/kubernetes/

ubuntu@controller-0:~$ ll /var/lib/kubernetes/
total 36
drwxr-xr-x  2 root root 4096 Oct 21 22:37 ./
drwxr-xr-x 42 root root 4096 Oct 21 22:37 ../
-rw-------  1 root root 1675 Oct 21 22:37 ca-key.pem
-rw-r--r--  1 root root 1306 Oct 21 22:37 ca.pem
-rw-------  1 root root  240 Oct 21 22:37 encryption-config.yaml
-rw-------  1 root root 1679 Oct 21 22:37 kubernetes-key.pem
-rw-r--r--  1 root root 1659 Oct 21 22:37 kubernetes.pem
-rw-------  1 root root 1675 Oct 21 22:37 service-account-key.pem
-rw-r--r--  1 root root 1428 Oct 21 22:37 service-account.pem
ubuntu@controller-0:~$
  • kube-apiserver systemdサービスファイルの作成.
  • controller-0での作業.
INTERNAL_IP=192.168.8.10

cat <<EOF | sudo tee /etc/systemd/system/kube-apiserver.service
[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/kubernetes/kubernetes

[Service]
ExecStart=/usr/local/bin/kube-apiserver \\
  --advertise-address=${INTERNAL_IP} \\
  --allow-privileged=true \\
  --apiserver-count=3 \\
  --audit-log-maxage=30 \\
  --audit-log-maxbackup=3 \\
  --audit-log-maxsize=100 \\
  --audit-log-path=/var/log/audit.log \\
  --authorization-mode=Node,RBAC \\
  --bind-address=0.0.0.0 \\
  --client-ca-file=/var/lib/kubernetes/ca.pem \\
  --enable-admission-plugins=NamespaceLifecycle,NodeRestriction,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota \\
  --etcd-cafile=/var/lib/kubernetes/ca.pem \\
  --etcd-certfile=/var/lib/kubernetes/kubernetes.pem \\
  --etcd-keyfile=/var/lib/kubernetes/kubernetes-key.pem \\
  --etcd-servers=https://192.168.8.10:2379,https://192.168.8.11:2379,https://192.168.8.12:2379 \\
  --event-ttl=1h \\
  --encryption-provider-config=/var/lib/kubernetes/encryption-config.yaml \\
  --kubelet-certificate-authority=/var/lib/kubernetes/ca.pem \\
  --kubelet-client-certificate=/var/lib/kubernetes/kubernetes.pem \\
  --kubelet-client-key=/var/lib/kubernetes/kubernetes-key.pem \\
  --runtime-config='api/all=true' \\
  --service-account-key-file=/var/lib/kubernetes/service-account.pem \\
  --service-account-signing-key-file=/var/lib/kubernetes/service-account-key.pem \\
  --service-account-issuer=https://${INTERNAL_IP}:6443 \\
  --service-cluster-ip-range=10.32.0.0/24 \\
  --service-node-port-range=30000-32767 \\
  --tls-cert-file=/var/lib/kubernetes/kubernetes.pem \\
  --tls-private-key-file=/var/lib/kubernetes/kubernetes-key.pem \\
  --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF
  • kube-controller-managerの設定.
    同期モードを有効化しておく.

  • kubeconfigの配置

sudo cp ~/kube-controller-manager.kubeconfig /var/lib/kubernetes/
  • kube-controller-manager systemdサービスファイルの作成
cat <<EOF | sudo tee /etc/systemd/system/kube-controller-manager.service
[Unit]
Description=Kubernetes Controller Manager
Documentation=https://github.com/kubernetes/kubernetes

[Service]
ExecStart=/usr/local/bin/kube-controller-manager \\
  --bind-address=0.0.0.0 \\
  --cluster-cidr=10.200.0.0/16 \\
  --cluster-name=kubernetes \\
  --cluster-signing-cert-file=/var/lib/kubernetes/ca.pem \\
  --cluster-signing-key-file=/var/lib/kubernetes/ca-key.pem \\
  --kubeconfig=/var/lib/kubernetes/kube-controller-manager.kubeconfig \\
  --leader-elect=true \\
  --root-ca-file=/var/lib/kubernetes/ca.pem \\
  --service-account-private-key-file=/var/lib/kubernetes/service-account-key.pem \\
  --service-cluster-ip-range=10.32.0.0/24 \\
  --use-service-account-credentials=true \\
  --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

重要なパラメータ .
--cluster-cidr=10.200.0.0/16: Pod用のIPレンジ.
--service-cluster-ip-range=10.32.0.0/24: Service用のIPレン.
--leader-elect=true: 高可用性のためのリーダー選出.

  • kube-schedulerの設定.
  • kubeconfigの配置.
sudo cp ~/kube-scheduler.kubeconfig /var/lib/kubernetes/
  • kube-scheduler設定ファイルの作成
cat <<EOF | sudo tee /etc/kubernetes/config/kube-scheduler.yaml
apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
clinetConnection:
  kubeconfig: "/var/lib/kubernetes/kube-scheduler.kubeconfig"
leaderElection:
  leaderElect: true
EOF
  • kube-scheduler systemdサービスファイルの作成
cat <<EOF | sudo tee /etc/systemd/system/kube-scheduler.service
[Unit]
Description=Kubernetes Scheduler
Documentation=https://github.com/kubernetes/kubernetes

[Service]
ExecStart=/usr/local/bin/kube-scheduler \\
  --config=/etc/kubernetes/config/kube-scheduler.yaml \\
  --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable kube-apiserver kube-controller-manager kube-scheduler
sudo systemctl start kube-apiserver kube-controller-manager kube-scheduler

sleep 10

# サービスの状態確認
sudo systemctl status kube-apiserver --no-pager
sudo systemctl status kube-controller-manager --no-pager
sudo systemctl status kube-scheduler --no-pager

---

# controller-0の出力
ubuntu@controller-0:~$ sudo systemctl daemon-reload
ubuntu@controller-0:~$ sudo systemctl enable kube-apiserver kube-controller-manager kube-scheduler
Created symlink /etc/systemd/system/multi-user.target.wants/kube-apiserver.service → /etc/systemd/system/kube-apiserver.service.
Created symlink /etc/systemd/system/multi-user.target.wants/kube-controller-manager.service → /etc/systemd/system/kube-controller-manager.service.
Created symlink /etc/systemd/system/multi-user.target.wants/kube-scheduler.service → /etc/systemd/system/kube-scheduler.service.
ubuntu@controller-0:~$ sudo systemctl start kube-apiserver kube-controller-manager kube-scheduler
ubuntu@controller-0:~$ sleep 10
ubuntu@controller-0:~$ sudo systemctl status kube-apiserver --no-pager
● kube-apiserver.service - Kubernetes API Server
     Loaded: loaded (/etc/systemd/system/kube-apiserver.service; enabled; vendor preset: enabled)
     Active: active (running) since Wed 2025-10-22 22:43:11 UTC; 27s ago
       Docs: https://github.com/kubernetes/kubernetes
   Main PID: 17536 (kube-apiserver)
      Tasks: 9 (limit: 2218)
     Memory: 302.0M
        CPU: 3.310s
     CGroup: /system.slice/kube-apiserver.service
             └─17536 /usr/local/bin/kube-apiserver --advertise-address=192.168.8.10 --allow-privileged=true --apis…

Oct 22 22:43:16 controller-0 kube-apiserver[17536]: [-]poststarthook/rbac/bootstrap-roles failed: not finished
Oct 22 22:43:16 controller-0 kube-apiserver[17536]: I1022 22:43:16.425237   17536 healthz.go:261] poststarth…readyz
Oct 22 22:43:16 controller-0 kube-apiserver[17536]: [-]poststarthook/rbac/bootstrap-roles failed: not finished
Oct 22 22:43:16 controller-0 kube-apiserver[17536]: I1022 22:43:16.492598   17536 controller.go:624] quota a…k8s.io
Oct 22 22:43:16 controller-0 kube-apiserver[17536]: I1022 22:43:16.524474   17536 healthz.go:261] poststarth…readyz
Oct 22 22:43:16 controller-0 kube-apiserver[17536]: [-]poststarthook/rbac/bootstrap-roles failed: not finished
Oct 22 22:43:16 controller-0 kube-apiserver[17536]: I1022 22:43:16.639181   17536 alloc.go:330] "allocated c….0.1"}
Oct 22 22:43:16 controller-0 kube-apiserver[17536]: W1022 22:43:16.674497   17536 lease.go:265] Resetting en….8.12]
Oct 22 22:43:16 controller-0 kube-apiserver[17536]: I1022 22:43:16.675441   17536 controller.go:624] quota a…points
Oct 22 22:43:16 controller-0 kube-apiserver[17536]: I1022 22:43:16.702904   17536 controller.go:624] quota a…k8s.io
Hint: Some lines were ellipsized, use -l to show in full.
ubuntu@controller-0:~$ sudo systemctl status kube-controller-manager --no-pager
● kube-controller-manager.service - Kubernetes Controller Manager
     Loaded: loaded (/etc/systemd/system/kube-controller-manager.service; enabled; vendor preset: enabled)
     Active: active (running) since Wed 2025-10-22 22:43:11 UTC; 34s ago
       Docs: https://github.com/kubernetes/kubernetes
   Main PID: 17537 (kube-controller)
      Tasks: 5 (limit: 2218)
     Memory: 87.1M
        CPU: 531ms
     CGroup: /system.slice/kube-controller-manager.service
             └─17537 /usr/local/bin/kube-controller-manager --bind-address=0.0.0.0 --cluster-cidr=10.200.0.0/16 --…

Oct 22 22:43:12 controller-0 kube-controller-manager[17537]: W1022 22:43:12.245345   17537 authentication.go:…work.
Oct 22 22:43:12 controller-0 kube-controller-manager[17537]: W1022 22:43:12.245576   17537 authorization.go:1…work.
Oct 22 22:43:12 controller-0 kube-controller-manager[17537]: I1022 22:43:12.248029   17537 controllermanager.…29.1"
Oct 22 22:43:12 controller-0 kube-controller-manager[17537]: I1022 22:43:12.248191   17537 controllermanager.…CK=""
Oct 22 22:43:12 controller-0 kube-controller-manager[17537]: I1022 22:43:12.249957   17537 tlsconfig.go:200] "Load…
Oct 22 22:43:12 controller-0 kube-controller-manager[17537]: I1022 22:43:12.250459   17537 named_certificates.go:5…
Oct 22 22:43:12 controller-0 kube-controller-manager[17537]: I1022 22:43:12.250644   17537 secure_serving.go:…10257
Oct 22 22:43:12 controller-0 kube-controller-manager[17537]: I1022 22:43:12.250711   17537 tlsconfig.go:240] …ller"
Oct 22 22:43:12 controller-0 kube-controller-manager[17537]: I1022 22:43:12.253739   17537 leaderelection.go:…er...
Oct 22 22:43:13 controller-0 kube-controller-manager[17537]: E1022 22:43:13.856984   17537 leaderelection.go:332] …
Hint: Some lines were ellipsized, use -l to show in full.
ubuntu@controller-0:~$ sudo systemctl status kube-scheduler --no-pager
● kube-scheduler.service - Kubernetes Scheduler
     Loaded: loaded (/etc/systemd/system/kube-scheduler.service; enabled; vendor preset: enabled)
     Active: activating (auto-restart) (Result: exit-code) since Wed 2025-10-22 22:43:49 UTC; 194ms ago
       Docs: https://github.com/kubernetes/kubernetes
    Process: 17615 ExecStart=/usr/local/bin/kube-scheduler --config=/etc/kubernetes/config/kube-scheduler.yaml --v=2 (code=exited, status=1/FAILURE)
   Main PID: 17615 (code=exited, status=1/FAILURE)
        CPU: 300ms
ubuntu@controller-0:~$

controller-0とcontroller-2でkube-schedulerが動いていない。

ubuntu@controller-0:~$ sudo systemctl status kube-scheduler --no-pager
● kube-scheduler.service - Kubernetes Scheduler
     Loaded: loaded (/etc/systemd/system/kube-scheduler.service; enabled; vendor preset: enabled)
     Active: activating (auto-restart) (Result: exit-code) since Wed 2025-10-22 22:43:49 UTC; 194ms ago
       Docs: https://github.com/kubernetes/kubernetes
    Process: 17615 ExecStart=/usr/local/bin/kube-scheduler --config=/etc/kubernetes/config/kube-scheduler.yaml --v=2 (code=exited, status=1/FAILURE)
   Main PID: 17615 (code=exited, status=1/FAILURE)
        CPU: 300ms
ubuntu@controller-0:~$

---

ubuntu@controller-2:~$ sudo systemctl status kube-scheduler --no-pager
● kube-scheduler.service - Kubernetes Scheduler
     Loaded: loaded (/etc/systemd/system/kube-scheduler.service; enabled; vendor preset: enabled)
     Active: activating (auto-restart) (Result: exit-code) since Fri 2025-10-24 19:36:16 UTC; 1s ago
       Docs: https://github.com/kubernetes/kubernetes
    Process: 251006 ExecStart=/usr/local/bin/kube-scheduler --config=/etc/kubernetes/config/kube-scheduler.yaml --v=2 (code=exited, status=1/FAILURE)
   Main PID: 251006 (code=exited, status=1/FAILURE)
        CPU: 403ms
ubuntu@controller-2:~$
  • エラーログ解析 controller-0のjounalctlを見る
sudo journalctl -u kube-scheduler -n 50 --no-pager

コマンドが違いそう

ubuntu@controller-0:~$ sudo journalctl -u kube-scheduler -n 50 --no-pager
[中略]
Oct 24 19:39:16 controller-0 kube-scheduler[251632]: E1024 19:39:16.825427  251632 run.go:74] "command failed" err="strict decoding error: unknown field \"clinetConnection\""
Oct 24 19:39:16 controller-0 systemd[1]: kube-scheduler.service: Main process exited, code=exited, status=1/FAILURE
Oct 24 19:39:16 controller-0 systemd[1]: kube-scheduler.service: Failed with result 'exit-code'.
ubuntu@controller-0:~$
  • 設定ファイルの確認
cat /etc/kubernetes/config/kube-scheduler.yaml
  • 再度設定ファイルを作成.
    同期モードにしておく.
cat <<EOF | sudo tee /etc/kubernetes/config/kube-scheduler.yaml
apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
clientConnection:
  kubeconfig: "/var/lib/kubernetes/kube-scheduler.kubeconfig"
leaderElection:
  leaderElect: true
EOF
  • 再起動
sudo systemctl restart kube-scheduler
sudo systemctl status kube-scheduler

全てactiveになった

  • 動作確認.
    同期モードを解除しておく.
# controller-0で確認

kubectl cluster-info --kubeconfig ~/admin.kubeconfig
# エラーの場合下記
sudo kubectl get componentstatuses --kubeconfig /var/lib/kubernetes/kube-controller-manager.kubeconfig

curl -k https://127.0.0.1:6443/version

---
ubuntu@controller-0:~$ sudo kubectl get componentstatuses --kubeconfig /var/lib/kubernetes/kube-controller-manager.kubeconfig
Warning: v1 ComponentStatus is deprecated in v1.19+
NAME                 STATUS    MESSAGE   ERROR
scheduler            Healthy   ok
etcd-0               Healthy   ok
controller-manager   Healthy   ok
ubuntu@controller-0:~$ curl -k https://127.0.0.1:6443/version
{
  "major": "1",
  "minor": "29",
  "gitVersion": "v1.29.1",
  "gitCommit": "bc401b91f2782410b3fb3f9acf43a995c4de90d2",
  "gitTreeState": "clean",
  "buildDate": "2024-01-17T15:41:12Z",
  "goVersion": "go1.21.6",
  "compiler": "gc",
  "platform": "linux/amd64"
}ubuntu@controller-0:~$
  • RBAC for Kubelet Authorization.
    kubelete APIへのアクセうを許可するRBAC設定を作成 controller-0で実施.
cat <<EOF | sudo kubectl apply --kubeconfig /var/lib/kubernetes/kube-controller-manager.kubeconfig -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
  name: system:kube-apiserver-to-kubelet
rules:
  - apiGroups:
      - ""
    resources:
      - nodes/proxy
      - nodes/stats
      - nodes/log
      - nodes/spec
      - nodes/metrics
    verbs:
      - "*"
EOF

---
Error from server (Forbidden): error when retrieving current configuration of:
Resource: "rbac.authorization.k8s.io/v1, Resource=clusterroles", GroupVersionKind: "rbac.authorization.k8s.io/v1, Kind=ClusterRole"
Name: "system:kube-apiserver-to-kubelet", Namespace: ""
from server for: "STDIN": clusterroles.rbac.authorization.k8s.io "system:kube-apiserver-to-kubelet" is forbidden: User "system:kube-controller-manager" cannot get resource "clusterroles" in API group "rbac.authorization.k8s.io" at the cluster scope
ubuntu@controller-0:~$
  • admin.kubeconfigをcontroller-0に配布.
    gateway-01で実行.
scp admin.kubeconfig ubuntu@192.168.8.10:~/

~/admin.kubeconfigを実行

cat <<EOF | kubectl apply --kubeconfig ~/admin.kubeconfig -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
  name: system:kube-apiserver-to-kubelet
rules:
  - apiGroups:
      - ""
    resources:
      - nodes/proxy
      - nodes/stats
      - nodes/log
      - nodes/spec
      - nodes/metrics
    verbs:
      - "*"
EOF


---
ubuntu@controller-0:~$ cat <<EOF | kubectl apply --kubeconfig ~/admin.kubeconfig -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
  name: system:kube-apiserver-to-kubelet
rules:
  - apiGroups:
EOF   - "*"es/metrics
error: error validating "STDIN": error validating data: failed to download openapi: Get "https://192.168.3.18:6443/openapi/v2?timeout=32s": dial tcp 192.168.3.18:6443: connect: connection refused; if you choose to ignore these errors, turn validation off with --validate=false
ubuntu@controller-0:~$

gatewaty-01で実行

cd ~/k8s-certs

cat <<EOF | kubectl apply --kubeconfig admin.kubeconfig -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
  name: system:kube-apiserver-to-kubelet
rules:
  - apiGroups:
      - ""
    resources:
      - nodes/proxy
      - nodes/stats
      - nodes/log
      - nodes/spec
      - nodes/metrics
    verbs:
      - "*"
EOF

---

ubuntu@gateway-01:~/k8s-certs$ cat <<EOF | kubectl apply --kubeconfig admin.kubeconfig -f -                        apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
  name: system:kube-apiserver-to-kubelet
rules:
  - apiGroups:
      - ""
    resources:
      - nodes/proxy
      - nodes/stats
      - nodes/log
      - nodes/spec
      - nodes/metrics
    verbs:
      - "*"
EOF
error: error validating "STDIN": error validating data: failed to download openapi: Get "https://192.168.3.18:6443/openapi/v2?timeout=32s": dial tcp 192.168.3.18:6443: connect: connection refused; if you choose to ignore these errors, turn validation off with --validate=false
ubuntu@gateway-01:~/k8s-certs$
  • HAProxy設定ファイルの作成
cat <<EOF | sudo tee /etc/haproxy/haproxy.cfg
global
  log /dev/log local0
  log /dev/log local1 notice
  chroot /var/lib/haproxy
  stats socket /run/haproxy/admin.sock mode 660 level admin
  stats timeout 30s
  user haproxy
  group haproxy
  daemon

defaults
  log     global
  mode    http
  option  httplog
  option  dontlognull
  timeout connect 5000
  timeout client 50000
  timeout server 50000

frontend kubernetes-apiserver
  bind *:6443
  mode tcp
  option tcplog
  default_backend kubernetes-apiserver

backend kubernetes-apiserver
  mode tcp
  option tcp-check
  balance roundrobin
  server controller-0 192.168.8.10:6443 check fall 3 rise 2
  server controller-1 192.168.8.11:6443 check fall 3 rise 2
  server controller-2 192.168.8.12:6443 check fall 3 rise 2
EOF

実行の確認

ubuntu@gateway-01:~/k8s-certs$ sudo systemctl restart haproxy
ubuntu@gateway-01:~/k8s-certs$ sudo systemctl enable haproxy
Synchronizing state of haproxy.service with SysV service script with /lib/systemd/systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install enable haproxy
ubuntu@gateway-01:~/k8s-certs$ sudo systemctl status haproxy
● haproxy.service - HAProxy Load Balancer
     Loaded: loaded (/lib/systemd/system/haproxy.service; enabled; vendor preset: enabled)
     Active: active (running) since Fri 2025-10-24 20:25:21 UTC; 7s ago
       Docs: man:haproxy(1)
             file:/usr/share/doc/haproxy/configuration.txt.gz
   Main PID: 20213 (haproxy)
      Tasks: 2 (limit: 2220)
     Memory: 71.2M
        CPU: 66ms
     CGroup: /system.slice/haproxy.service
             ├─20213 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -S /run/haproxy-master.>
             └─20215 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -S /run/haproxy-master.>

Oct 24 20:25:21 gateway-01 haproxy[20110]: [WARNING]  (20110) : Exiting Master process...
Oct 24 20:25:21 gateway-01 haproxy[20110]: [NOTICE]   (20110) : haproxy version is 2.4.24-0ubuntu0.22.04.3
Oct 24 20:25:21 gateway-01 haproxy[20110]: [NOTICE]   (20110) : path to executable is /usr/sbin/haproxy
Oct 24 20:25:21 gateway-01 haproxy[20110]: [ALERT]    (20110) : Current worker #1 (20112) exited with code 143 (Te>
Oct 24 20:25:21 gateway-01 haproxy[20110]: [WARNING]  (20110) : All workers exited. Exiting... (0)
Oct 24 20:25:21 gateway-01 systemd[1]: haproxy.service: Deactivated successfully.
Oct 24 20:25:21 gateway-01 systemd[1]: Stopped HAProxy Load Balancer.
Oct 24 20:25:21 gateway-01 systemd[1]: Starting HAProxy Load Balancer...
Oct 24 20:25:21 gateway-01 haproxy[20213]: [NOTICE]   (20213) : New worker #1 (20215) forked
Oct 24 20:25:21 gateway-01 systemd[1]: Started HAProxy Load Balancer.
lines 1-23/23 (END)
ubuntu@gateway-01:~/k8s-certs$

ClusterRole設定できた

}ubuntu@gateway-01:~/k8s-certs$cat <<EOF | kubectl apply --kubeconfig admin.kubeconfig -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
  name: system:kube-apiserver-to-kubelet
rules:
  - apiGroups:
      - ""
    resources:
      - nodes/proxy
      - nodes/stats
      - nodes/log
      - nodes/spec
      - nodes/metrics
    verbs:
      - "*"
EOF
clusterrole.rbac.authorization.k8s.io/system:kube-apiserver-to-kubelet created
ubuntu@gateway-01:~/k8s-certs$

ClusterRoleBindingの作成

cat <<EOF | kubectl apply --kubeconfig admin.kubeconfig -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: system:kube-apiserver
  namespace: ""
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:kube-apiserver-to-kubelet
subjects:
  - apiGroup: rbac.authorization.k8s.io
    kind: User
    name: kubernetes
EOF

リソース確認

ubuntu@gateway-01:~/k8s-certs$ kubectl get clusterrole system:kube-apiserver-to-kubelet --kubeconfig admin.kubeconfig
NAME                               CREATED AT
system:kube-apiserver-to-kubelet   2025-10-24T20:32:56Z
ubuntu@gateway-01:~/k8s-certs$ kubectl get clusterrolebinding system:kube-apiserver --kubeconfig admin.kubeconfig
NAME                    ROLE                                           AGE
system:kube-apiserver   ClusterRole/system:kube-apiserver-to-kubelet   48s
ubuntu@gateway-01:~/k8s-certs$
  • gateway-01でのHTTPヘルスチェック設定
  • CA証明書の配置.
sudo mkdir -p /var/lib/kubernetes
sudo cp ca.pem /var/lib/kubernetes
  • nginxのインストール
sudo apt update
sudo apt install -y nginx
  • nginx設定ファイルの作成
cat <<EOF | sudo tee /etc/nginx/sites-available/kubernetes.default.svc.cluster.local
server {
  listen 80;
  server_name kubernetes.default.svc.cluster.local;

  location /healthz {
    proxy_pass https://127.0.0.1:6443/healthz;
    proxy_ssl_trusted_certificate /var/lib/kubernetes/ca.pem;
  }
}
EOF
sudo ln -sf /etc/nginx/sites-available/kubernetes.default.svc.cluster.local /etc/nginx/sites-enabled/
  • nginxの再起動
sudo nginx -t  # 設定テスト
sudo systemctl restart nginx
sudo systemctl enable nginx

---
ubuntu@gateway-01:~/k8s-certs$ sudo nginx -t  # 設定テスト
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
ubuntu@gateway-01:~/k8s-certs$ sudo systemctl restart nginx
ubuntu@gateway-01:~/k8s-certs$ sudo systemctl enable nginx
Synchronizing state of nginx.service with SysV service script with /lib/systemd/systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install enable nginx
ubuntu@gateway-01:~/k8s-certs$
curl -H "Host: kubernetes.default.svc.cluster.local" http://127.0.0.1/healthz

---
ubuntu@gateway-01:~/k8s-certs$ curl -H "Host: kubernetes.default.svc.cluster.local" http://127.0.0.1/healthz
okubuntu@gateway-01:~/k8s-certs$

Bootstrapping the Kubernetes Worker Nodes

概要

このステップでは、3つのworkerノードに以下をインストールする:
1. 依存パッケージ(socat, conntrack, ipset).
2. containerd(コンテナランタイム).
3. CNIプラグイン(ネットワーク).
4. kubelet(Podの管理).
5. kube-proxy(ネットワークプロキシ).

  • 証明書とkubeconfigの配布
#worker-0
scp cap.pem worker-0-key.pem worker-0.pem \
  worker-0.kubeconfig kube-proxy.kubeconfig \
  ubuntu@192.168.8.20:~/


#worker-1
scp cap.pem worker-1-key.pem worker-1.pem \
  worker-1.kubeconfig kube-proxy.kubeconfig \
  ubuntu@192.168.8.21:~/


#worker-2
scp cap.pem worker-2-key.pem worker-2.pem \
  worker-2.kubeconfig kube-proxy.kubeconfig \
  ubuntu@192.168.8.22:~/

workerノードを3つのペインに分割する.
同期モードを有効化しておく.

  • 依存パッケージのインストール
sudo apt update
sudo apt install -y socat conntrack ipset
  • swapの無効化確認
sudo swapon --show
free -h
sudo mkdir -p \
  /etc/cni/net.d \
  /opt/cni/bin \
  /var/lib/kubelet \
  /var/lib/kube-proxy \
  /var/lib/kubernetes \
  /var/run/kubernetes

ディレクトリの説明:
- /etc/cni/net.d: CNI設定ファイル.
- /opt/cni/bin: CNIプラグインバイナリ.
- /var/lib/kubelet: kubelet用データ.
- /var/lib/kube-proxy: kube-proxy用データ.

  • バイナリのダウンロードとインストール.
    containerd、CNIプラグイン、kubelet、kube-proxyのダウンロード
wget -q --show-progress --https-only --timestamping \
  https://github.com/kubernetes-sigs/cri-tools/releases/download/v1.29.0/crictl-v1.29.0-linux-amd64.tar.gz \
  https://github.com/opencontainers/runc/releases/download/v1.1.12/runc.amd64 \
  https://github.com/containernetworking/plugins/releases/download/v1.4.0/cni-plugins-linux-amd64-v1.4.0.tgz \
  https://github.com/containerd/containerd/releases/download/v1.7.13/containerd-1.7.13-linux-amd64.tar.gz \
  https://dl.k8s.io/v1.29.1/bin/linux/amd64/kubectl \
  https://dl.k8s.io/v1.29.1/bin/linux/amd64/kube-proxy \
  https://dl.k8s.io/v1.29.1/bin/linux/amd64/kubelet
sudo mkdir -p /etc/containerd

sudo mv runc.amd64 runc
chmod +x runc kubectl kube-proxy kubelet
sudo mv runc kubectl kube-proxy kubelet /usr/local/bin/

sudo tar -xvf cni-plugins-linux-amd64-v1.4.0.tgz -C /opt/cni/bin/
sudo tar -xvf containerd-1.7.13-linux-amd64.tar.gz -C /usr/local/aws-cli/

tar -xvf crictl-v1.29.0-linux-amd64.tar.gz
sudo mv crictl /usr/local/bin/
  • CNIネットワークの設定.
    同期モードを解除しておく.

  • worker-0

POD_CIDR=10.200.0.0/24

cat <<EOF | sudo tee /etc/cni/net.d/10-bridge.conf
{
  "cniVersion": "1.0.0",
  "name": "bridge",
  "type": "bridge",
  "bridge": "cnio0",
  "isGateway": true,
  "ipMasq": true,
  "ipam": {
    "type": "host-local",
    "ranges": [
      [{"subnet": "${POD_CIDR}"}]
    ],
    "routes": [{"dst": "0.0.0.0/0"}]
  }
}
EOF
  • loopback設定(全worker共通)
cat <<EOF | sudo tee /etc/cni/net.d/99-loopback.conf
{
  "cniVersion": "1.0.0",
  "name": "lo",
  "type": "loopback"
}
EOF
  • containerdの設定.
    同期モードを有効化しておく.

  • containerd設定ファイルの作成

cat <<EOF | sudo tee /etc/containerd/config.toml
version = 2

[plugins]
  [plugins."io.containerd.grpc.v1.cri"]
    [plugins."io.containerd.grpc.v1.cri".containerd]
      snapshotter = "overlayfs"
      [plugins."io.containerd.grpc.v1.cri".containerd.default_runtime]
        runtime_type = "io.containerd.runc.v2"
      [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
        runtime_type = "io.containerd.runc.v2"
        [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
          SystemdCgroup = true
EOF

  • containerd systemdサービスファイルの作成
cat <<EOF | sudo tee /etc/systemd/system/containerd.service
[Unit]
Description=containerd container runtime
Documentation=https://containerd.io
After=network.target

[Service]
ExecStartPre=/sbin/modprobe overlay
ExecStart=/usr/local/bin/containerd
Restart=always
RestartSec=5
Delegate=yes
KillMode=process
OOMScoreAdjust=-999
LimitNOFILE=1048576
LimitNPROC=infinity
LimitCORE=infinity

[Install]
WantedBy=multi-user.target
EOF

  • kubeletの設定. 同期モードを解除しておく.

  • worker-0での設定

sudo cp ~/worker-0-key.pem ~/worker-0.pem /var/lib/kubelet/
sudo cp ~/worker-0.kubeconfig /var/lib/kubelet/kubeconfig
sudo cp ~/ca.pem /var/lib/kubernetes/

# kubelet設定ファイルの作成
cat <<EOF | sudo tee /var/lib/kubelet/kubelet-config.yaml
kind: KubeletConfiguration
apiVersion: kubelet.config.k8s.io/v1beta1
authentication:
  anonymous:
    enabled: false
  webhook:
    enabled: true
  x509:
    clientCAFile: "/var/lib/kubernetes/ca.pem"
authorization:
  mode: Webhook
clusterDomain: "cluster.local"
clusterDNS:
  - "10.32.0.10"
podCIDR: "10.200.0.0/24"
resolvConf: "/run/systemd/resolve/resolv.conf"
runtimeRequestTimeout: "15m"
tlsCertFile: "/var/lib/kubelet/worker-0.pem"
tlsPrivateKeyFile: "/var/lib/kubelet/worker-0-key.pem"
EOF
  • kubelet systemdサービスファイルの作成
cat <<EOF | sudo tee /etc/systemd/system/kubelet.service
[Unit]
Description=Kubernetes Kubelet
Documentation=https://github.com/kubernetes/kubernetes
After=containerd.service
Requires=containerd.service

[Service]
ExecStart=/usr/local/bin/kubelet \\
  --config=/var/lib/kubelet/kubelet-config.yaml \\
  --container-runtime-endpoint=unix:///var/run/containerd/containerd.sock \\
  --kubeconfig=/var/lib/kubelet/kubeconfig \\
  --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF
  • kube-proxyの設定.
  • kube-proxy kubeconfigの配置.
sudo cp ~/kube-proxy.kubeconfig /var/lib/kube-proxy/kubeconfig
  • kube-proxy設定ファイルの作成
cat <<EOF | sudo tee /var/lib/kube-proxy/kube-proxy-config.yaml
kind: KubeProxyConfiguration
apiVersion: kubeproxy.config.k8s.io/v1alpha1
clientConnection:
  kubeconfig: "/var/lib/kube-proxy/kubeconfig"
mode: "iptables"
clusterCIDR: "10.200.0.0/16"
EOF

設定の説明:
- mode: "iptables": iptablesモードを使用(デフォルト).
- clusterCIDR: 全Podの IPレンジ(10.200.0.0/16).

  • kube-proxy systemdサービスファイルの作成.
cat <<EOF | sudo tee /etc/systemd/system/kube-proxy.service
[Unit]
Description=Kubernetes Kube Proxy
Documentation=https://github.com/kubernetes/kubernetes

[Service]
ExecStart=/usr/local/bin/kube-proxy \\
  --config=/var/lib/kube-proxy/kube-proxy-config.yaml
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF
  • サービスの起動
sudo systemctl daemon-reload
sudo systemctl enable containerd kubelet kube-proxy
sudo systemctl start containerd kubelet kube-proxy
  • サービスの状態確認
sudo systemctl status containerd --no-pager
sudo systemctl status kubelet --no-pager
sudo systemctl status kube-proxy --no-pager

---
ubuntu@worker-0:~$ sudo systemctl status containerd --no-pager
● containerd.service - containerd container runtime
     Loaded: loaded (/etc/systemd/system/containerd.service; enabled; vendor preset: enabled)
     Active: active (running) since Sat 2025-10-25 05:19:53 UTC; 2min 14s ago
       Docs: https://containerd.io
    Process: 20802 ExecStartPre=/sbin/modprobe overlay (code=exited, status=0/SUCCESS)
   Main PID: 20807 (containerd)
      Tasks: 8 (limit: 4555)
     Memory: 16.5M
        CPU: 250ms
     CGroup: /system.slice/containerd.service
             └─20807 /usr/local/bin/containerd

Oct 25 05:19:53 worker-0 containerd[20807]: time="2025-10-25T05:19:53.485675164Z" level=info msg="skipping …plugin"
Oct 25 05:19:53 worker-0 containerd[20807]: time="2025-10-25T05:19:53.486020448Z" level=info msg="Start sub… event"
Oct 25 05:19:53 worker-0 containerd[20807]: time="2025-10-25T05:19:53.486087043Z" level=info msg="Start rec… state"
Oct 25 05:19:53 worker-0 containerd[20807]: time="2025-10-25T05:19:53.486163629Z" level=info msg="Start eve…onitor"
Oct 25 05:19:53 worker-0 containerd[20807]: time="2025-10-25T05:19:53.486179639Z" level=info msg="Start sna…syncer"
Oct 25 05:19:53 worker-0 containerd[20807]: time="2025-10-25T05:19:53.486187694Z" level=info msg="Start cni…efault"
Oct 25 05:19:53 worker-0 containerd[20807]: time="2025-10-25T05:19:53.486196431Z" level=info msg="Start str…server"
Oct 25 05:19:53 worker-0 containerd[20807]: time="2025-10-25T05:19:53.486435935Z" level=info msg=serving...…k.ttrpc
Oct 25 05:19:53 worker-0 containerd[20807]: time="2025-10-25T05:19:53.486516688Z" level=info msg=serving...…rd.sock
Oct 25 05:19:53 worker-0 containerd[20807]: time="2025-10-25T05:19:53.486542227Z" level=info msg="container…56411s"
Hint: Some lines were ellipsized, use -l to show in full.
ubuntu@worker-0:~$ sudo systemctl status kubelet --no-pager
● kubelet.service - Kubernetes Kubelet
     Loaded: loaded (/etc/systemd/system/kubelet.service; enabled; vendor preset: enabled)
     Active: activating (auto-restart) (Result: exit-code) since Sat 2025-10-25 05:22:15 UTC; 1s ago
       Docs: https://github.com/kubernetes/kubernetes
    Process: 21179 ExecStart=/usr/local/bin/kubelet --config=/var/lib/kubelet/kubelet-config.yaml --container-runtime-endpoint=unix:///var/run/containerd/containerd.sock --kubeconfig=/var/lib/kubelet/kubeconfig --v=2 (code=exited, status=1/FAILURE)
   Main PID: 21179 (code=exited, status=1/FAILURE)
        CPU: 64ms
ubuntu@worker-0:~$ sudo systemctl status kube-proxy --no-pager
● kube-proxy.service - Kubernetes Kube Proxy
     Loaded: loaded (/etc/systemd/system/kube-proxy.service; enabled; vendor preset: enabled)
     Active: activating (auto-restart) (Result: exit-code) since Sat 2025-10-25 05:22:25 UTC; 3s ago
       Docs: https://github.com/kubernetes/kubernetes
    Process: 21208 ExecStart=/usr/local/bin/kube-proxy --config=/var/lib/kube-proxy/kube-proxy-config.yaml (code=exited, status=1/FAILURE)
   Main PID: 21208 (code=exited, status=1/FAILURE)
        CPU: 37ms
ubuntu@worker-0:~$

エラーが発生したのでkubeletとkube-proxyのログをみる

sudo journalctl -u kubelet -n 50 --no-pager | tail -30
sudo journalctl -u kube-proxy -n 50 --no-pager | tail -30

---
ubuntu@worker-0:~$ sudo journalctl -u kubelet -n 50 --no-pager | tail -30
sudo journalctl -u kube-proxy -n 50 --no-pager | tail -30
[中略]
Oct 25 06:24:22 worker-0 kubelet[30795]: E1025 06:24:22.098220   30795 run.go:74] "command failed" err="failed to run Kubelet: running with swap on is not supported, please disable swap! or set --fail-swap-on flag to false. /proc/swaps contained: [Filename\t\t\t\tType\t\tSize\t\tUsed\t\tPriority /swap.img                               file\t\t1867772\t\t0\t\t-2]"
Oct 25 06:24:22 worker-0 systemd[1]: kubelet.service: Main process exited, code=exited, status=1/FAILURE
Oct 25 06:24:22 worker-0 systemd[1]: kubelet.service: Failed with result 'exit-code'.
Oct 25 06:24:01 worker-0 systemd[1]: kube-proxy.service: Main process exited, code=exited, status=1/FAILURE
Oct 25 06:24:01 worker-0 systemd[1]: kube-proxy.service: Failed with result 'exit-code'.
Oct 25 06:24:06 worker-0 systemd[1]: kube-proxy.service: Scheduled restart job, restart counter is at 734.
Oct 25 06:24:06 worker-0 systemd[1]: Stopped Kubernetes Kube Proxy.
Oct 25 06:24:06 worker-0 systemd[1]: Started Kubernetes Kube Proxy.
Oct 25 06:24:06 worker-0 kube-proxy[30752]: E1025 06:24:06.298494   30752 server.go:556] "Error running ProxyServer" err="stat /var/lib/kube-proxy/kubeconfig: no such file or directory"
Oct 25 06:24:06 worker-0 kube-proxy[30752]: E1025 06:24:06.299567   30752 run.go:74] "command failed" err="stat /var/lib/kube-proxy/kubeconfig: no such file or directory"
Oct 25 06:24:06 worker-0 systemd[1]: kube-proxy.service: Main process exited, code=exited, status=1/FAILURE
Oct 25 06:24:06 worker-0 systemd[1]: kube-proxy.service: Failed with result 'exit-code'.
Oct 25 06:24:11 worker-0 systemd[1]: kube-proxy.service: Scheduled restart job, restart counter is at 735.
Oct 25 06:24:11 worker-0 systemd[1]: Stopped Kubernetes Kube Proxy.
Oct 25 06:24:11 worker-0 systemd[1]: Started Kubernetes Kube Proxy.
Oct 25 06:24:11 worker-0 kube-proxy[30766]: E1025 06:24:11.552057   30766 server.go:556] "Error running ProxyServer" err="stat /var/lib/kube-proxy/kubeconfig: no such file or directory"
Oct 25 06:24:11 worker-0 kube-proxy[30766]: E1025 06:24:11.552522   30766 run.go:74] "command failed" err="stat /var/lib/kube-proxy/kubeconfig: no such file or directory"
Oct 25 06:24:11 worker-0 systemd[1]: kube-proxy.service: Main process exited, code=exited, status=1/FAILURE
Oct 25 06:24:11 worker-0 systemd[1]: kube-proxy.service: Failed with result 'exit-code'.
Oct 25 06:24:16 worker-0 systemd[1]: kube-proxy.service: Scheduled restart job, restart counter is at 736.
Oct 25 06:24:16 worker-0 systemd[1]: Stopped Kubernetes Kube Proxy.
Oct 25 06:24:16 worker-0 systemd[1]: Started Kubernetes Kube Proxy.
Oct 25 06:24:16 worker-0 kube-proxy[30780]: E1025 06:24:16.807890   30780 server.go:556] "Error running ProxyServer" err="stat /var/lib/kube-proxy/kubeconfig: no such file or directory"
Oct 25 06:24:16 worker-0 kube-proxy[30780]: E1025 06:24:16.808560   30780 run.go:74] "command failed" err="stat /var/lib/kube-proxy/kubeconfig: no such file or directory"
Oct 25 06:24:16 worker-0 systemd[1]: kube-proxy.service: Main process exited, code=exited, status=1/FAILURE
Oct 25 06:24:16 worker-0 systemd[1]: kube-proxy.service: Failed with result 'exit-code'.
Oct 25 06:24:22 worker-0 systemd[1]: kube-proxy.service: Scheduled restart job, restart counter is at 737.
Oct 25 06:24:22 worker-0 systemd[1]: Stopped Kubernetes Kube Proxy.
Oct 25 06:24:22 worker-0 systemd[1]: Started Kubernetes Kube Proxy.
Oct 25 06:24:22 worker-0 kube-proxy[30794]: E1025 06:24:22.052981   30794 server.go:556] "Error running ProxyServer" err="stat /var/lib/kube-proxy/kubeconfig: no such file or directory"
Oct 25 06:24:22 worker-0 kube-proxy[30794]: E1025 06:24:22.053426   30794 run.go:74] "command failed" err="stat /var/lib/kube-proxy/kubeconfig: no such file or directory"
Oct 25 06:24:22 worker-0 systemd[1]: kube-proxy.service: Main process exited, code=exited, status=1/FAILURE
Oct 25 06:24:22 worker-0 systemd[1]: kube-proxy.service: Failed with result 'exit-code'.
ubuntu@worker-0:~$
  • 問題1: swapが有効になっている(kubelet).
  • 問題2: kube-proxy kubeconfigが存在しない.

解決方法

  • swapを無効化
sudo swapoff -a

sudo sed -i '/swap/d' /etc/fstab

sudo rm -f /swap.img

free -h
sudo swapon --show
  • kube-proxy kubeconfigの配置確認
ls -l ~/kube-proxy.kubeconfig

sudo cp ~/kube-proxy.kubeconfig /var/lib/kube-proxy/kubeconfig
sudo ls -l /var/lib/kube-proxy/kubeconfig
  • サービスの再起動
sudo systemctl restart kubelet kube-proxy

sudo systemctl status kubelet --no-pager
sudo systemctl status kube-proxy --no-pager

gateway-01でノードの登録を確認

kubectl get nodes --kubeconfig ~/k8s-certs/admin.kuberconfig

---
ubuntu@gateway-01:~/k8s-certs$ kubectl get nodes --kubeconfig ~/k8s-certs/admin.kubeconfig
NAME       STATUS   ROLES    AGE     VERSION
worker-0   Ready    <none>   5m3s    v1.29.1
worker-1   Ready    <none>   4m42s   v1.29.1
worker-2   Ready    <none>   4m42s   v1.29.1
ubuntu@gateway-01:~/k8s-certs$

Configuring kubectl for Remote Access

概要

このステップでは、ローカルPCからKubernetesクラスターを操作できるようにkubectlを設定する。
現在、admin.kubeconfigはgateway-01に存在するが、これを:
- ローカルPCにコピー.
- kubectlで使用できるように設定.

kubectlはローカルPCにインストールしているのでローカルPCで実施した。

  1. admin.kubeconfigをローカルPCにコピー.
# ~/.kubeはすでに作成している

scp ubuntu@192.168.3.18:~/k8s-certs/admin.kubeconfig ~/.kube/config

chmod 600 ~/.kube/config
  1. 接続確認.
# クラスター情報の確認
kubectl cluster-info

# ノード一覧の確認
kubectl get nodes

# コンポーネントの状態確認
kubectl get componentstatuses

# 全リソースの確認
kubectl get all --all-namespaces

---
on ☸ admin on kubernetes-the-hard-way in default () memo-cho on  master [!?]
♥ ❯ kubectl cluster-info

Kubernetes control plane is running at https://192.168.3.18:6443

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

on ☸ admin on kubernetes-the-hard-way in default () memo-cho on  master [!?]
♥ ❯ kubectl get nodes

NAME       STATUS   ROLES    AGE   VERSION
worker-0   Ready    <none>   15m   v1.29.1
worker-1   Ready    <none>   15m   v1.29.1
worker-2   Ready    <none>   15m   v1.29.1

on ☸ admin on kubernetes-the-hard-way in default () memo-cho on  master [!?]
♥ ❯ kubectl get componentstatuses

Warning: v1 ComponentStatus is deprecated in v1.19+
NAME                 STATUS    MESSAGE   ERROR
scheduler            Healthy   ok
etcd-0               Healthy   ok
controller-manager   Healthy   ok

on ☸ admin on kubernetes-the-hard-way in default () memo-cho on  master [!?]
♥ ❯ kubectl get all --all-namespaces

NAMESPACE   NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
default     service/kubernetes   ClusterIP   10.32.0.1    <none>        443/TCP   2d8h

on ☸ admin on kubernetes-the-hard-way in default () memo-cho on  master [!?]
♥

3.kubeconfigの内容確認.

# 設定の確認
kubectl config view

# 現在のコンテキスト確認
kubectl config current-context

# クラスター一覧
kubectl config get-clusters

# ユーザー一覧
kubectl config get-users

Provisioning Pod Network Routes

概要

現在、各workerノードのPodは自分のノード内でしか通信できない。
異なるworkerノード間のPod通信を可能にするため、gateway-01にルーティング設定を追加する。

  • Pod CIDRの割り当て
Worker Node Pod CIDR IPレンジ
worker-0 10.200.0.0/24 10.200.0.1 ~ 10.200.0.254
worker-1 10.200.1.0/24 10.200.1.1 ~ 10.200.1.254
worker-2 10.200.2.0/24 10.200.2.1 ~ 10.200.2.254
  • gateway-01でのルーティング設定.
  • ルーティングテーブルの追加.
# worker-0へのルート
sudo ip route add 10.200.0.0/24 via 192.168.8.20
# worker-1へのルート
sudo ip route add 10.200.1.0/24 via 192.168.8.21
# worker-2へのルート
sudo ip route add 10.200.2.0/24 via 192.168.8.22
  • ルーティングテーブルの確認
ip route | grep "10.200"

---
ubuntu@gateway-01:~$ ip route | grep "10.200"
10.200.0.0/24 via 192.168.8.20 dev ens19
10.200.1.0/24 via 192.168.8.21 dev ens19
10.200.2.0/24 via 192.168.8.22 dev ens19
ubuntu@gateway-01:~$
  • ルートの永続化.
  • Netplan設定ファイルの編集.
sudo vim /etc/netplan/01-netcfg.yaml

cat結果

ubuntu@gateway-01:~$ cat /etc/netplan/01-netcfg.yaml
network:
  version: 2
  ethernets:
    ens18:
      dhcp4: true
      dhcp4-overrides:
        route-metric: 100
    ens19:
      addresses:
        - 192.168.8.1/24
      dhcp4: false
      routes:
        - to: 10.200.0.0/24
          via: 192.168.8.20
        - to: 10.200.1.0/24
          via: 192.168.8.21
        - to: 10.200.2.0/24
          via: 192.168.8.22
ubuntu@gateway-01:~$
  • 設定の適用、再度確認
sudo netplan apply
ip route | grep "10.200"

---
ubuntu@gateway-01:~$ sudo netplan apply

** (generate:22253): WARNING **: 10:46:01.329: Permissions for /etc/netplan/01-netcfg.yaml are too open. Netplan configuration should NOT be accessible by others.
WARNING:root:Cannot call Open vSwitch: ovsdb-server.service is not running.

** (process:22251): WARNING **: 10:46:01.647: Permissions for /etc/netplan/01-netcfg.yaml are too open. Netplan configuration should NOT be accessible by others.

** (process:22251): WARNING **: 10:46:01.775: Permissions for /etc/netplan/01-netcfg.yaml are too open. Netplan configuration should NOT be accessible by others.

** (process:22251): WARNING **: 10:46:01.775: Permissions for /etc/netplan/01-netcfg.yaml are too open. Netplan configuration should NOT be accessible by others.
ubuntu@gateway-01:~$ ip route | grep "10.200"
10.200.0.0/24 via 192.168.8.20 dev ens19 proto static
10.200.1.0/24 via 192.168.8.21 dev ens19 proto static
10.200.2.0/24 via 192.168.8.22 dev ens19 proto static
ubuntu@gateway-01:~$
  • IP Forwardingの確認
# IP Forwardingが有効か確認
cat /proc/sys/net/ipv4/ip_forward

---
ubuntu@gateway-01:~$ cat /proc/sys/net/ipv4/ip_forward
1
ubuntu@gateway-01:~$

ステップ12: Deploying the DNS Cluster Add-on

概要

CoreDNSマニフェストを作成する。
CoreDNSは、Kubernetesクラスター内のDNSサーバーです。これにより:
- ServiceをDNS名で参照できる(例: nginx.default.svc.cluster.local).
- Pod間の名前解決が可能になる.
- 外部DNSへのクエリも転送される.

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
  name: coredns
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
  name: system:coredns
rules:
  - apiGroups:
    - ""
    resources:
    - endpoints
    - services
    - pods
    - namespaces
    verbs:
    - list
    - watch
  - apiGroups:
    - discovery.k8s.io
    resources:
    - endpointslices
    verbs:
    - list
    - watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
  name: system:coredns
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:coredns
subjects:
- kind: ServiceAccount
  name: coredns
  namespace: kube-system
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: coredns
  namespace: kube-system
data:
  Corefile: |
    .:53 {
      errors
      health {
        lameduck 5s
      }
      ready
      kubernetes cluster.local in-addr.arpa ip6.arpa {
        pods insecure
        fallthrough in-addr.arpa ip6.arpa
        ttl 30
      }
      prometheus :9153
      forward . /etc/resolv.conf {
        max_concurrent 1000
      }
      cache 30
      loop
      reload
      loadbalance
    }
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: coredns
  namespace: kube-system
  labels:
    k8s-app: kube-dns
    kubernetes.io/name: "CoreDNS"
spec:
  replicas: 2
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
  selector:
    matchLabels:
      k8s-app: kube-dns
  template:
    metadata:
      labels:
        k8s-app: kube-dns
    spec:
      priorityClassName: system-cluster-critical
      serviceAccountName: coredns
      tolerations:
        - key: "CriticalAddonsOnly"
          operator: "Exists"
      nodeSelector:
        kubernetes.io/os: linux
      containers:
      - name: coredns
        image: coredns/coredns:1.11.1
        imagePullPolicy: IfNotPresent
        resources:
          limits:
            memory: 170Mi
          requests:
            cpu: 100m
            memory: 70Mi
        args: [ "-conf", "/etc/coredns/Corefile" ]
        volumeMounts:
        - name: config-volume
          mountPath: /etc/coredns
          readOnly: true
        ports:
        - containerPort: 53
          name: dns
          protocol: UDP
        - containerPort: 53
          name: dns-tcp
          protocol: TCP
        - containerPort: 9153
          name: metrics
          protocol: TCP
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            add:
            - NET_BIND_SERVICE
            drop:
            - all
          readOnlyRootFilesystem: true
        livenessProbe:
          httpGet:
            path: /health
            port: 8080
            scheme: HTTP
          initialDelaySeconds: 60
          timeoutSeconds: 5
          successThreshold: 1
          failureThreshold: 5
        readinessProbe:
          httpGet:
            path: /ready
            port: 8181
            scheme: HTTP
      dnsPolicy: Default
      volumes:
        - name: config-volume
          configMap:
            name: coredns
            items:
            - key: Corefile
              path: Corefile
---
apiVersion: v1
kind: Service
metadata:
  name: kube-dns
  namespace: kube-system
  annotations:
    prometheus.io/port: "9153"
    prometheus.io/scrape: "true"
  labels:
    k8s-app: kube-dns
    kubernetes.io/cluster-service: "true"
    kubernetes.io/name: "CoreDNS"
spec:
  selector:
    k8s-app: kube-dns
  clusterIP: 10.32.0.10
  ports:
  - name: dns
    port: 53
    protocol: UDP
  - name: dns-tcp
    port: 53
    protocol: TCP
  - name: metrics
    port: 9153
    protocol: TCP
EOF

---
serviceaccount/coredns created
clusterrole.rbac.authorization.k8s.io/system:coredns created
clusterrolebinding.rbac.authorization.k8s.io/system:coredns created
configmap/coredns created
deployment.apps/coredns created
service/kube-dns created

on ☸ admin on kubernetes-the-hard-way in default () new_lab/2025/kubernetes-hard-way on  master [?⇣]
♥

重要: clusterIP: 10.32.0.10 はkubelet設定の clusterDNS と一致させる必要があります。

  • デプロイの確認 pod,service,deploymentの確認
on ☸ admin on kubernetes-the-hard-way in default () new_lab/2025/kubernetes-hard-way on  master [?⇣]
♥ ❯ k get pods -n kube-system -l k8s-app=kube-dns
NAME                       READY   STATUS    RESTARTS   AGE
coredns-6d84d9c4b7-bnh7d   1/1     Running   0          42s
coredns-6d84d9c4b7-tzg6w   1/1     Running   0          42s

on ☸ admin on kubernetes-the-hard-way in default () new_lab/2025/kubernetes-hard-way on  master [?⇣]
♥ ❯ k get service -n kube-system kube-dns
NAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE
kube-dns   ClusterIP   10.32.0.10   <none>        53/UDP,53/TCP,9153/TCP   61s

on ☸ admin on kubernetes-the-hard-way in default () new_lab/2025/kubernetes-hard-way on  master [?⇣]
♥ ❯ k get deployment -n kube-system coredns
NAME      READY   UP-TO-DATE   AVAILABLE   AGE
coredns   2/2     2            2           84s

on ☸ admin on kubernetes-the-hard-way in default () new_lab/2025/kubernetes-hard-way on  master [?⇣]
♥
on ☸ admin on kubernetes-the-hard-way in default () new_lab/2025/kubernetes-hard-way on  master [?⇣]
♥ ❯ k run busybox --image=busybox:1.28 --command -- sleep 3600
pod/busybox created

on ☸ admin on kubernetes-the-hard-way in default () new_lab/2025/kubernetes-hard-way on  master [?⇣]
❯ k get pods busybox
NAME      READY   STATUS    RESTARTS   AGE
busybox   1/1     Running   0          37s

on ☸ admin on kubernetes-the-hard-way in default () new_lab/2025/kubernetes-hard-way on  master [?⇣]
♥ ❯ k exec busybox -- nslookup kubernetes
Server:    10.32.0.10
Address 1: 10.32.0.10 kube-dns.kube-system.svc.cluster.local

Name:      kubernetes
Address 1: 10.32.0.1 kubernetes.default.svc.cluster.local

on ☸ admin on kubernetes-the-hard-way in default () new_lab/2025/kubernetes-hard-way on  master [?⇣]
♥ ❯ k exec busybox -- nslookup kube-dns.kube-system.svc.cluster.local
Server:    10.32.0.10
Address 1: 10.32.0.10 kube-dns.kube-system.svc.cluster.local

Name:      kube-dns.kube-system.svc.cluster.local
Address 1: 10.32.0.10 kube-dns.kube-system.svc.cluster.local

on ☸ admin on kubernetes-the-hard-way in default () new_lab/2025/kubernetes-hard-way on  master [?⇣]
♥

Smoke Test

テスト項目

  1. Data Encryption(データ暗号化)
  2. Deployments(デプロイメント)
  3. Port Forwarding(ポート転送)
  4. Logs(ログ取得)
  5. Exec(コマンド実行)
  6. Services(サービス)

  7. Data Encryptionのテスト etcd内のSecretが暗号化されているか確認する。

kubectl create secret generic kubernetes-the-hard-way \
  --from-literal="mykey=mydata"

---
on ☸ admin on kubernetes-the-hard-way in default () new_lab/2025/kubernetes-hard-way on  master [?]
♥ ❯ kubectl create secret generic kubernetes-the-hard-way \
  --from-literal="mykey=mydata"

secret/kubernetes-the-hard-way created

on ☸ admin on kubernetes-the-hard-way in default () new_lab/2025/kubernetes-hard-way on  master [?]
♥
  • etcd内のデータを確認(controller-0で) gateway-01 -> controller-0にssh

  • Deploymentsのテスト

  • nginxデプロイメントの作成
kubectl create deployment nginx --image=nginx:latest
kubectl get pods -l app=nginx

---
on ☸ admin on kubernetes-the-hard-way in default () new_lab/2025/kubernetes-hard-way on  master [?]
♥ ❯ kubectl create deployment nginx --image=nginx:latest

deployment.apps/nginx created

on ☸ admin on kubernetes-the-hard-way in default () new_lab/2025/kubernetes-hard-way on  master [?]
♥ ❯ kubectl get pods -l app=nginx

NAME                     READY   STATUS    RESTARTS   AGE
nginx-56fcf95486-nqght   1/1     Running   0          12s

on ☸ admin on kubernetes-the-hard-way in default () new_lab/2025/kubernetes-hard-way on  master [?]
♥
  • Port Forwardingのテスト
  • nginxへのポート転送
POD_NAME=$(kubectl get pods -l app=nginx -o jsonpath="{.items[0].metadata.name}")
kubectl port-forward $POD_NAME 8080:80 &

curl --head http://127.0.0.1:8080

---
on ☸ admin on kubernetes-the-hard-way in default () haskell-sandbox/playground/algogogo on  master via λ took 7d11h24m36s
♥ ❯ curl --head http://127.0.0.1:8080

HTTP/1.1 200 OK
Server: nginx/1.29.2
Date: Sat, 25 Oct 2025 23:37:30 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 07 Oct 2025 17:04:07 GMT
Connection: keep-alive
ETag: "68e54807-267"
Accept-Ranges: bytes


on ☸ admin on kubernetes-the-hard-way in default () haskell-sandbox/playground/algogogo on  master via λ
♥
  • ポート転送を停止
pkill -f "fort-forward"
  • Logsのテスト
# nginxのログ
kubectl logs $POD_NAME

---
on ☸ admin on kubernetes-the-hard-way in default () new_lab/2025/kubernetes-hard-way on  master [?]
✦ ♥ ❯ kubectl logs $POD_NAME

/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2025/10/25 23:33:15 [notice] 1#1: using the "epoll" event method
2025/10/25 23:33:15 [notice] 1#1: nginx/1.29.2
2025/10/25 23:33:15 [notice] 1#1: built by gcc 14.2.0 (Debian 14.2.0-19)
2025/10/25 23:33:15 [notice] 1#1: OS: Linux 5.15.0-157-generic
2025/10/25 23:33:15 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2025/10/25 23:33:15 [notice] 1#1: start worker processes
2025/10/25 23:33:15 [notice] 1#1: start worker process 29
2025/10/25 23:33:15 [notice] 1#1: start worker process 30
127.0.0.1 - - [25/Oct/2025:23:37:30 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/8.7.1" "-"

on ☸ admin on kubernetes-the-hard-way in default () new_lab/2025/kubernetes-hard-way on  master [?]
✦
  • Execのテスト
  • Pod内でコマンド実行
kubectl exec -ti $POD_NAME -- nginx -v

---
on ☸ admin on kubernetes-the-hard-way in default () new_lab/2025/kubernetes-hard-way on  master [?]
✦ ♥ ❯ kubectl exec -ti $POD_NAME -- nginx -v

nginx version: nginx/1.29.2

on ☸ admin on kubernetes-the-hard-way in default () new_lab/2025/kubernetes-hard-way on  master [?]
✦
  • Servicesのテスト
  • NodePort Serviceの作成
kubectl expose deployment nginx --port 80 --type NodePort
kubectl get service nginx

---
on ☸ admin on kubernetes-the-hard-way in default () new_lab/2025/kubernetes-hard-way on  master [?]
✦ ♥ ❯ kubectl expose deployment nginx --port 80 --type NodePort

service/nginx exposed

on ☸ admin on kubernetes-the-hard-way in default () new_lab/2025/kubernetes-hard-way on  master [?]
✦ ♥ ❯ kubectl get service nginx

NAME    TYPE       CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
nginx   NodePort   10.32.0.189   <none>        80:31531/TCP   22s

on ☸ admin on kubernetes-the-hard-way in default () new_lab/2025/kubernetes-hard-way on  master [?]
✦

workerノードに接続できなかったのはPod Network Routesが不完全だったことが原因だった。

調査から

  1. tcpdump: SYNパケットは到達するが、SYN-ACKが返らない
  2. iptablesルール: 正しく設定されている
  3. Podへの直接アクセス失敗: curl http://10.200.1.3:80タイムアウト
  4. → これで「Pod間通信の問題」だと判明

解決方法

各workerノードに他のworkerのPod CIDRへのルートを追加

  • 作業ログ
ubuntu@worker-0:~$ ip route
default via 192.168.8.1 dev ens18 proto static
10.200.0.0/24 dev cnio0 proto kernel scope link src 10.200.0.1
192.168.8.0/24 dev ens18 proto kernel scope link src 192.168.8.20
ubuntu@worker-0:~$ sudo ip route add 10.200.1.0/24 via 192.168.8.21
ubuntu@worker-0:~$ sudo ip route add 10.200.2.0/24 via 192.168.8.22
ubuntu@worker-0:~$ ip route
default via 192.168.8.1 dev ens18 proto static
10.200.0.0/24 dev cnio0 proto kernel scope link src 10.200.0.1
10.200.1.0/24 via 192.168.8.21 dev ens18
10.200.2.0/24 via 192.168.8.22 dev ens18
192.168.8.0/24 dev ens18 proto kernel scope link src 192.168.8.20
ubuntu@worker-0:~$ sudo vim  /etc/netplan/01-netcfg.yaml
ubuntu@worker-0:~$ sudo netplan apply

** (generate:39850): WARNING **: 00:56:01.769: Permissions for /etc/netplan/01-netcfg.yaml are too open. Netplan configuration should NOT be accessible by others.
WARNING:root:Cannot call Open vSwitch: ovsdb-server.service is not running.

** (process:39848): WARNING **: 00:56:01.976: Permissions for /etc/netplan/01-netcfg.yaml are too open. Netplan configuration should NOT be accessible by others.

** (process:39848): WARNING **: 00:56:02.106: Permissions for /etc/netplan/01-netcfg.yaml are too open. Netplan configuration should NOT be accessible by others.

** (process:39848): WARNING **: 00:56:02.106: Permissions for /etc/netplan/01-netcfg.yaml are too open. Netplan configuration should NOT be accessible by others.
ubuntu@worker-0:~$ curl -I http://10.200.1.3:80
HTTP/1.1 200 OK
Server: nginx/1.29.2
Date: Sun, 26 Oct 2025 00:56:11 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 07 Oct 2025 17:04:07 GMT
Connection: keep-alive
ETag: "68e54807-267"
Accept-Ranges: bytes

ubuntu@worker-0:~$ curl -I http://192.168.8.20:31531
HTTP/1.1 200 OK
Server: nginx/1.29.2
Date: Sun, 26 Oct 2025 00:56:15 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 07 Oct 2025 17:04:07 GMT
Connection: keep-alive
ETag: "68e54807-267"
Accept-Ranges: bytes

ubuntu@worker-0:~$
  • 外部からのアクセステスト(オプション) gateway-01で実行
NODE_PORT=31531
sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 192.168.8.20:$NODE_PORT
sudo netfilter-persistent save

---
ubuntu@gateway-01:~$ NODE_PORT=31531
ubuntu@gateway-01:~$ sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 192.168.8.20:$NODE_PORT
[sudo] password for ubuntu:
ubuntu@gateway-01:~$ sudo netfilter-persistent save
run-parts: executing /usr/share/netfilter-persistent/plugins.d/15-ip4tables save
run-parts: executing /usr/share/netfilter-persistent/plugins.d/25-ip6tables save
u

これにて完了!🎊


達成したこと

あなたは以下をゼロから手動で構築した:

Infrastructure

  • 7台のVM(1 gateway + 3 controllers + 3 workers)
  • 2つのネットワーク(パブリック + プライベート)
  • NAT Gateway + Load Balancer

Kubernetes Control Plane

  • 高可用性etcdクラスター(3ノード)
  • kube-apiserver(3ノード)
  • kube-controller-manager(3ノード)
  • kube-scheduler(3ノード)

Kubernetes Workers

  • containerd(コンテナランタイム)
  • kubelet(3ノード)
  • kube-proxy(3ノード)
  • CNIネットワーク

Security & Networking

  • PKI infrastructure(20個の証明書)
  • TLS暗号化通信
  • RBAC認証
  • Secret暗号化
  • Pod Network Routes
  • HAProxy(ロードバランシング)

Add-ons


学んだこと

このチュートリアルを通して、以下を少し理解できた:

  1. Kubernetesアーキテクチャ
  2. Control PlaneとWorker Nodesの役割
  3. コンポーネントの連携

  4. PKI/TLS証明書

  5. 証明書の生成と配布
  6. 相互認証の仕組み

  7. ネットワーク

  8. Pod CIDR、Service CIDR
  9. ルーティング、NAT
  10. NodePort、ClusterIP

  11. セキュリティ

  12. RBAC
  13. データ暗号化
  14. ネットワーク分離

  15. 高可用性

  16. etcdクラスタリング
  17. リーダー選出
  18. ロードバランシング

今後の学び

  1. Ingress Controllerの追加
  2. nginx-ingress、Traefik等

  3. Persistent Volumeの設定

  4. ストレージの永続化

  5. Monitoring & Logging

  6. Prometheus + Grafana
  7. EFK Stack

  8. GitOpsの導入

  9. ArgoCD、Flux

  10. Service Mesh

  11. Istio、Linkerd

  12. 本番環境への応用

  13. クラウド環境での構築
  14. オートスケーリング
  15. バックアップ・リストア

今までなんとなく仕事で感じていたモヤモヤを言語化できた話

0. この記事について

ソフトウェアエンジニアが向き合う抽象的な課題では、「抽象的な目線」と「具体的な作業」を行き来することで課題の本質を明確にし、作業の方向性をブレさせないことが重要です。この記事では、この考え方や実践方法について私の経験や考えた事を記載しています。

1. はじめに

新しい会社で働くようになり、あることを強く実感しました。
タスクを完了してレビューを受ける際に、「あれ?AC(アクセプタンス・クライテリア)と一致していない?」や「そもそもこのタスクのACを満たしていなかった? このタスクはACを満たすための事前調査だったのか? 実は調査→資料作成→関係者への展開までが1セットなのでは……」といったように、チームが期待しているタスク内容と自分が実施しているタスク内容に大きな乖離があることに気づきました。

「インフラエンジニアという未経験の分野だから仕方がない」「ウォーターフォール型開発が中心だった自分が、初めてスクラム開発を経験しているから仕方がない」など、言い訳を挙げればキリがありませんが、自分だけがチームの歩調に合っていない現状に焦りを感じていました。
上司が想定している成果物と私が提出した成果物の間には、なぜこれほどの乖離があるのか悩んでいました。


2. 問題の本質を探る

2.1 過去の具体的なタスク例

これまで私が受けていた仕事の依頼は、次のように非常に具体的な内容が多かったです。
- 「キャンペーン用にこのようなページを作成してください。テーブルはこうして……画面デザインはこうしてください。」
- 「Pythonを使って、ここからパケットを取得するツールを作成してください。」
- 「こういったシステムを作成したいので、外部設計書を作成してください。」

2.2 現在の抽象的な課題

一方、現在の会社では、以下のような「課題解決を委ねられる」依頼が増えていると感じています。
- 「○○がEOLになるのでどうにか対応してほしい。」
- 「△△というサービスが終了するため、移行を進めたい。」

こうした依頼に対して、とりあえず今まで通り「まずはやってみる」というスタンスで進めてみたものの、気づけば「調査資料を作成すること」が目的になってしまい、本来の目的である「関係者への周知や行動の促進」が抜け落ちてしまいました。そのため、作成すべき資料の内容も、インフラ以外の関係者に配慮した抽象的な内容が求められていたことに後から気づく始末でした。


3. 自己研鑽の試み

こうした課題を克服したい一心で、「課題解決」と名のつく自己啓発書やビジネス書を片っ端から読みました。しかし、どれも似たような内容で腑に落ちず、悶々とした日々を過ごしていました。そんな中、ある日出会った本に衝撃を受けました。それが、具体と抽象という一冊です。


4. 「具体」と「抽象」の視点

4.1 上司と自分の視点の違い

この本を通じて、「抽象的な視点」と「具体的な視点」という二つの視点の存在を知りました。この概念を知ったことで、上司と私の間で成果物に対する認識がズレている理由を理解することができました。

上司は抽象的な視点でタスクを見ており、タスクそのものではなく、それが包含している課題にフォーカスしています。そのため、後続のタスクや背景を意識しながら、課題に対して適切な成果物を作成できます。
一方で、私は具体的な視点しか持たず、タスク一つひとつに集中していました。その結果、解決すべき課題の本筋から外れた成果物を作成してしまい、後続のタスクに活用できない状況が生まれていました。

4.2 抽象的課題を具体化するプロセス

抽象という視点を知ることで、これまでの働き方におけるタスクの本質を理解できた気がします。たとえば、以下のように考えれば腑に落ちます。
- 「キャンペーンをやるのでページを作成してほしい」
→「売上を上げるために施策を打ちたい」
→「顧客が登録すれば売上が上がるかもしれない」
→「登録者数を増やすためにキャンペーンを打とう」
→「そのためのページ作成」という具体的なタスク。


5. 課題解決に向けての実践

5.1 本質を明確にする重要性

抽象的な課題を具体的な課題に変えるためには、「本質を明確にすること」が重要です。その上で、以下のような施策も有効だと感じています。

5.2 その他の実践的な施策

  • アウトラインの確認を行う。
  • 部分ごとに進捗を確認する(定期的な状況共有)。
  • ビッグバンリリースを避け、叩き台を作成する。
  • 手段が目的化しないように、一歩引いた視点でタスクを見直す。

6. おわりに

私自身、まだまだ実践できていないことも多いですが、これらを意識して仕事に取り組んでいこうと思います。
ソフトウェアエンジニアの仕事は本当に難しいですね……。

AWSネットワーク入門 第2版の所感

AWSネットワーク入門 第2版を読んでAWSのネットワークについて学んだので、 各章で学んだことや所感を書こうと思います。

※ 本にはリソースを削除するお掃除について、一部のリソースは記載がないのでハンズオンが一通り終わったらお掃除をしましょう!

所感

AWSのネットワークの基礎を学ぶにはいい本だと思います。 1~6章を読んでハンズオンをやるとWordPressが動かせるまで構築が完了するので、他のアプリにも応用ができそうです。 インフラエンジニアやクラウドエンジニアは7,8章も併せて読んでおくてAWSおよびドメイン周りの理解が深まります。 入門と書いてある通り業務で使うような突っ込んだ知識は得にくいのかなと感じました。特に7章のALBやRoute53周りで加重ルーティングの説明は欲しかったですが入門書などのそこまで深い知識はいらないですね。 業務でインフラ周りを担当しているエンジニアはAWSのネットワークについてさらに突っ込んだ本を読むか公式のハンズオンを実施する方が知識が身につくのかなという所感でした。

1章

AWSとオンプレの比較やネットワークの基礎知識を学びました。 ネットワークの本に書いてあることがつらつらと書いてありました。 データセンターを例にAWSのネットワークを説明しててわかりやすかったです。 グローバル、リージョン、アベイラビリティゾーンサービスの区別を覚えました。(今までなんとなくで覚えてました。 今までAWSアーキテクチャ図を軽くではありますが読んできたので、本に書いてある簡易なアーキテクチャは苦も無く理解できました。

2章

VPCについて学びました。 実際に手を動かしてVPCやサブネットを構築するハンズオンを実施したり、CIDRなどの座学をざっくりと学びました。 デフォルトVPCは削除しても再作成が可能だとわかりました。

3章

EC2やEBSについて学びました。 T,M,C,X,R,G,I,Dシリーズの用途を知れて勉強になりました。 ハンズオンでEC2を構築して、ENIの確認などをしました。

4章

パブリックIPアドレス割り当て→IGW設定→ルートテーブル設定→Elastic IPの割り当てまで行いました。 あまりElastic IPの割り当てまでは実施しないので勉強になりました。 AWSネットワーク上にはメタデータを配信するHTTPサーバーが存在するそうです。 https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html

5章

セキュリティグループとネットワークACLについて学びました。 セキュリティグループ:ENI単位で設定するパケットフィルタリング機能 ネットワークACL:サブネット単位で設定するパケットフィルタリング機能 Appacheサーバーを導入して、セキュリティグループのインバウンドに HTTPとHTTPSを追加して接続できることを確認しました。

6章

プライベートサブネットのDBサーバーをNATゲートウェイから通信させました。 DBサーバーにMariaDBをインストールしてWordPressを起動するチュートリアルがありましたが、既知の情報だったので飛ばしました。 Elastic IPやNATゲートウェイはお金がかかるので閉じ忘れないように注意しないといけないです。

7章

Route53とELBについて学びました。 Route53を使用してドメインを取得していましたが、その部分はスキップしています。 ELBはALBを使用してwebserverを2台に冗長化させて構築しました。

8章

S3などの非VPCサービスを接続する方法として、インターフェイスエンドポイントとゲートウェイエンドポイントを構築して通信しました。 後半はVPCピアリングや外部ネットワークとの接続方法を書いてありましたが、ハンズオンは実施しませんでした。

「Team Geek ―Googleのギークたちはいかにしてチームを作るのか」を読んだので感想

未経験でインフラチームのリーダーになるという無茶振りを受けた際に、本の背に書いてあったGoogleのギークたちはいかにしてチームを作るのかの文に惹かれて買って読んでから半年後にはなりますが感想を書いていこうと思います。

先に読んだ感想を先に書くとこんな組織で働いてみたい/こういう組織を作らなきゃと思いました!

特に私は現職がパワハラ長時間労働で退職してしまうので、この本に書いてある組織に所属していたらもう少し長く働けてたのになぁと思うのと、今後私が組織作りに携わることになったらこのような組織を作っていかないと心理的安全性は担保できないなと思いました。

1章ずつ参考になった箇所や感動した部分をメモ書き程度に書いてきます。最後に書く余力があれば感想でも一行くらい書ければなと思います。

1章

  • エンジニアリングチームの成功
    • 謙虚尊敬信頼の原則が必要
      • この原則は何度も出てき来るのでとても重要な考え方です。
  • イデアは隠さない
    • 早い段階で、高速に、何度も失敗せよの精神が大切
      • この精神のおかげで私の作るものは早めに作り切ることにしました。
  • チームで開発する意味
    • 一人で仕事するのはリスクが高い
    • フィードバックがもらえない
  • 自分の価値をコードに結びつけない
    • 切り離して考える
      • コードレビューのコメントや指摘は丁寧に攻撃的にならないように心がけたいです。

2章

  • チーム全員でプロダクトの成功に強い責任感を持つ
    • 客先常駐だとなかなかできない考え方だなと思いました。
  • 見栄を張るような文化は攻撃的な人を惹きつける
    • 私のいた会社がまさにこのような会社でした。
  • 3~4時間はスケジュールをブロックして、仕事を片付ける
    • これは是非次に行く会社や現場でやってみようと思います。

3章

  • 伝統的なマネージャーはどうやって仕事を完了させるか考える、リーダーは何ができるか考える。(仕事の完了させ方はチームに考えてもらう)
    • 私も前者の考えになりがちなので、もっとチームメンバーに相談するべきでした…
  • サーバントリーダー
    • チームに奉仕し続けること。HRTの雰囲気を作る
      • 今までのSIerとは求められるリーダーの理想像が逆ですよね。
  • アンチパターンについて
    • 自分の言いなりになる人の採用、採用を妥協する
      • 会社がまさに10人入って10人出ていく会社だったのでこれに当てはまると思います。
    • パフォーマンスの低い人の無視、人間の問題を無視する
      • PMがまさにこの問題を持っていて、プロダクトの成長にしか興味がない人でした。
    • みんなの友達になる
      • 私がよくやってしまうパターンです。中々人に意見を言えませんでした。
  • エゴをなくす
    • 個人のエゴではなく、チームのエゴを育てる
      • 今後を私がチームリーダーになった時に課題にしたいです。
  • 失敗の責任は追及しない。
    • 詰めることはダメ絶対ですよね
  • 褒めた言葉のサンドイッチではなく伝えたいことがははっきり言う
    • 本当に伝えたいことが伝わらない。
    • 建設的な批判をするときは親身になって相手の立場に立って考える
  • 1vs1ミーティングの後に「何か必要なものはある?」と聞いてみたらいい
    • リーダーになった際はやってみようと思います。

4章

  • 排除するのはあくまでふるまいであって、個人ではない
    • 個人の人格攻撃をしてはいけない
      • なぜなぜ分析などは人格否定になりがちなので気をつけたいです。
  • 短期的なメリットで文化を妥協しない
    • 長期的に考えた組織づくり、文化づくりをする。
      • 妥協して誰でもいいから採用するというのはよくないですね。

5章

  • 大人らしく振る舞う、質問する、マネージャーはエスパーではない
    • 自分が期待することを伝える。
      • 伝えないと相手はわからないですよね。
    • 納得できないことをマネージャーが決めたら、根拠について質問したり討論したりする。
      • これは私がやるべきでした。
    • リーダーに聞かれる前に、こちらから何をしているか報告する。
      • 新人の頃に言われたことだが、最近中々できてないです。
  • 悪い習慣をやめることはできない。良い習慣と置き換えなければいけない。
    • 私にとっては断酒することがこれにあたると思います。
  • できないことは約束しない。
    • 適当に見積もって締め切りを延ばすのではなく、Noと言う。
    • 約束は小さくして、届けるものは大きくする。
      • Noと言えない性格なので、これは難しいですね。
  • 会社を辞めるときは、つながりを絶やさないようにしよう。
    • うーん。現職では難しいかも…

6章

  • Lispは今もなお最高のプログラミング言語
    • 自分も少し触ってみようかな
  • その人が言っていることを文字通りに解釈するのではなく、何を意図しているかを理解する
    • とても大事だと思います。特に今の日本のSNSは文字通りに受け取り口論になる人が多いように感じます。
  • そのソフトウェアは君のためではない。チームのためではない。会社のためではない。ユーザーの生活を豊かにするためである。
    • 自分や会社のためと思って作りがちですが、ユーザーのために作ることを意識していきたいです。プロダクト開発の現場では必須の考え方だと思います。

感想

HRT(謙虚尊敬信頼)を用いて、自分の内面からチームについて、リーダーについて、アンチパターンについて考えさせられる本でした。

どうしてもチームでリーダーとして働いていると、生産性を出せていない人に対してその振る舞いを指摘することができず、その人の振る舞いを無視してチームを考えることが多かったのですが、HRTを用いてその人の気持ちに寄り添いながら、その人がどういう状況でそのような振る舞いについて親身なって指摘することができるようになりたいと思いました。

またHRTの文化のあるチームに所属することやまたチームを変えていくには、自分自身がHRTを体現することが必要だと考えました。

本気で学ぶ Linux実践入門 サーバ運用のための業務レベル管理術をよんだので感想

本気で学ぶ Linux実践入門 サーバ運用のための業務レベル管理術を少し前に読んだので感想を書きいていきます。
(かなりうろ覚えです)

この本はUbuntuDebian系)とCentOS(レッドバット系)の二つのOSの視点から各コマンドの動作を確認できるので、現場にあるほとんどのサーバーに対して知識をつけることができます。
自分は今回やらなかったのですが、DockerやVirtualBoxを使って仮想環境を構築して本に記載されているコマンドを実行してみると更に深く学べると思います。

個人的に良かったと思う点はsystemdとブートシーケンスについて書かれている点だと思います。
コマンドが網羅されているコマンド集にはsystemdも言及はないため勉強になりました。
実際にsystemctlコマンドを使用してhttpdなど各種デーモンを起動、実行していくチュートリアルもあります。

今後もLinux環境を構築するときに手元に置いてリファレンス的に読んでいくにはいい本だと思いました。
時間があるときにDockerで仮想環境を建てて色々なコマンドを試してみよう思います!