1. Bootstrap Kubernetes the hard way
00. Kind K8s 설치
WSL2를 이용해서 진행(기설치 된kind를 통해서 실습을 진행한다.)
(⎈|N/A:N/A) zosys@4:~$ kind version kind v0.30.0 go1.24.6 linux/amd64 (⎈|N/A:N/A) zosys@4:~$ helm version version.BuildInfo{Version:"v3.19.0", GitCommit:"3d8990f0836691f0229297773f3524598f46bda6", GitTreeState:"clean", GoVersion:"go1.24.7"}1주차 실습을 위한 kind k8s 배포(WSL2)
(⎈|N/A:N/A) zosys@4:~$ kind create cluster --name myk8s --image kindest/node:v1.32.8 --config - <<EOF kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 nodes: - role: control-plane extraPortMappings: - containerPort: 30000 hostPort: 30000 - containerPort: 30001 hostPort: 30001 - role: worker EOF Creating cluster "myk8s" ... ✓ Ensuring node image (kindest/node:v1.32.8) 🖼 ✓ Preparing nodes 📦 📦 ✓ Writing configuration 📜 ✓ Starting control-plane 🕹️ ✓ Installing CNI 🔌 ✓ Installing StorageClass 💾 ✓ Joining worker nodes 🚜 Set kubectl context to "kind-myk8s" You can now use your cluster with: (⎈|kind-myk8s:N/A) zosys@4:~$ kind get nodes --name myk8s myk8s-control-plane myk8s-worker (⎈|kind-myk8s:default) zosys@4:~$ kubectl get node -o wide NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME myk8s-control-plane Ready control-plane 2m30s v1.32.8 172.18.0.3 <none> Debian GNU/Linux 12 (bookworm) 6.6.87.2-microsoft-standard-WSL2 containerd://2.1.3 myk8s-worker Ready <none> 2m14s v1.32.8 172.18.0.2 <none> Debian GNU/Linux 12 (bookworm) 6.6.87.2-microsoft-standard-WSL2 containerd://2.1.3 (⎈|kind-myk8s:default) zosys@4:~$ docker exec -it myk8s-control-plane ss -tnlp State Recv-Q Send-Q Local Address:Port Peer Address:Port Process LISTEN 0 4096 127.0.0.1:45859 0.0.0.0:* users:(("containerd",pid=106,fd=11)) LISTEN 0 4096 172.18.0.3:2379 0.0.0.0:* users:(("etcd",pid=645,fd=9)) LISTEN 0 4096 172.18.0.3:2380 0.0.0.0:* users:(("etcd",pid=645,fd=7)) LISTEN 0 4096 127.0.0.11:46007 0.0.0.0:* LISTEN 0 4096 127.0.0.1:10248 0.0.0.0:* users:(("kubelet",pid=706,fd=20)) LISTEN 0 4096 127.0.0.1:10249 0.0.0.0:* users:(("kube-proxy",pid=899,fd=17)) LISTEN 0 4096 127.0.0.1:10259 0.0.0.0:* users:(("kube-scheduler",pid=514,fd=3)) LISTEN 0 4096 127.0.0.1:10257 0.0.0.0:* users:(("kube-controller",pid=554,fd=3)) LISTEN 0 4096 127.0.0.1:2379 0.0.0.0:* users:(("etcd",pid=645,fd=8)) LISTEN 0 4096 127.0.0.1:2381 0.0.0.0:* users:(("etcd",pid=645,fd=16)) LISTEN 0 4096 *:6443 *:* users:(("kube-apiserver",pid=566,fd=3)) LISTEN 0 4096 *:10256 *:* users:(("kube-proxy",pid=899,fd=16)) LISTEN 0 4096 *:10250 *:* users:(("kubelet",pid=706,fd=22))
01. Pre requisites
실습용 Vagrant배포의 경우 리소스 문제로 다른 PC에서 진행한다.
PS C:\Users\bom\Desktop\스터디\onpremisk8s> dir 디렉터리: C:\Users\bom\Desktop\스터디\onpremisk8s Mode LastWriteTime Length Name ---- ------------- ------ ---- -a---- 2026-01-05 오후 11:09 1172 init_cfg.sh -a---- 2026-01-05 오후 11:08 3234 Vagrantfile PS C:\Users\bom\Desktop\스터디\onpremisk8s> vagrant.exe up Bringing machine 'jumpbox' up with 'virtualbox' provider... Bringing machine 'server' up with 'virtualbox' provider... Bringing machine 'node-0' up with 'virtualbox' provider... Bringing machine 'node-1' up with 'virtualbox' provider... ==> jumpbox: Box 'bento/debian-12' could not be found. Attempting to find and install... jumpbox: Box Provider: virtualbox jumpbox: Box Version: 202510.26.0 ==> jumpbox: Loading metadata for box 'bento/debian-12' jumpbox: URL: https://vagrantcloud.com/api/v2/vagrant/bento/debian-12 ==> jumpbox: Adding box 'bento/debian-12' (v202510.26.0) for provider: virtualbox (amd64) jumpbox: Downloading: https://vagrantcloud.com/bento/boxes/debian-12/versions/202510.26.0/providers/virtualbox/amd64/vagrant.box ############################중략############################################ #배포 가상머신 확인 PS C:\Users\bom\Desktop\스터디\onpremisk8s> vagrant status Current machine states: jumpbox running (virtualbox) server running (virtualbox) node-0 running (virtualbox) node-1 running (virtualbox)jumpbox 가상머신 접속 : vagrant ssh jumpbox
PS C:\Users\bom\Desktop\스터디\onpremisk8s> vagrant ssh jumpbox Linux jumpbox 6.1.0-40-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.153-1 (2025-09-20) x86_64 This system is built by the Bento project by Chef Software More information can be found at https://github.com/chef/bento Use of this system is acceptance of the OS vendor EULA and License Agreements. The programs included with the Debian GNU/Linux system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law. root@jumpbox:~# whoami root root@jumpbox:~# pwd /root root@jumpbox:~#
02 - Set up The jumpbox
vagrant ssh jumpbox
root@jumpbox:~# whoami root root@jumpbox:~# pwd /root root@jumpbox:~# cat /home/vagrant/.bashrc | tail -n 1 sudo su - root@jumpbox:~# git clone --depth 1 https://github.com/kelseyhightower/kubernetes-the-hard-way.git Cloning into 'kubernetes-the-hard-way'... remote: Enumerating objects: 41, done. remote: Counting objects: 100% (41/41), done. remote: Compressing objects: 100% (40/40), done. remote: Total 41 (delta 3), reused 14 (delta 1), pack-reused 0 (from 0) Receiving objects: 100% (41/41), 29.27 KiB | 14.63 MiB/s, done. Resolving deltas: 100% (3/3), done. root@jumpbox:~# cd kubernetes-the-hard-way/ root@jumpbox:~/kubernetes-the-hard-way# tree . ├── ca.conf ├── configs │ ├── 10-bridge.conf │ ├── 99-loopback.conf │ ├── containerd-config.toml │ ├── encryption-config.yaml │ ├── kube-apiserver-to-kubelet.yaml │ ├── kubelet-config.yaml │ ├── kube-proxy-config.yaml │ └── kube-scheduler.yaml ├── CONTRIBUTING.md ├── COPYRIGHT.md ├── docs │ ├── 01-prerequisites.md │ ├── 02-jumpbox.md │ ├── 03-compute-resources.md │ ├── 04-certificate-authority.md │ ├── 05-kubernetes-configuration-files.md │ ├── 06-data-encryption-keys.md │ ├── 07-bootstrapping-etcd.md │ ├── 08-bootstrapping-kubernetes-controllers.md │ ├── 09-bootstrapping-kubernetes-workers.md │ ├── 10-configuring-kubectl.md │ ├── 11-pod-network-routes.md │ ├── 12-smoke-test.md │ └── 13-cleanup.md ├── downloads-amd64.txt ├── downloads-arm64.txt ├── LICENSE ├── README.md └── units ├── containerd.service ├── etcd.service ├── kube-apiserver.service ├── kube-controller-manager.service ├── kubelet.service ├── kube-proxy.service └── kube-scheduler.service 4 directories, 35 files #CPU 아키텍쳐 확인 root@jumpbox:~/kubernetes-the-hard-way# dpkg --print-architecture amd64 root@jumpbox:~/kubernetes-the-hard-way# ls -l downloads-* -rw-r--r-- 1 root root 839 Jan 5 23:25 downloads-amd64.txt -rw-r--r-- 1 root root 839 Jan 5 23:25 downloads-arm64.txt root@jumpbox:~/kubernetes-the-hard-way# cat downloads-$(dpkg --print-architecture).txt https://dl.k8s.io/v1.32.3/bin/linux/amd64/kubectl https://dl.k8s.io/v1.32.3/bin/linux/amd64/kube-apiserver https://dl.k8s.io/v1.32.3/bin/linux/amd64/kube-controller-manager https://dl.k8s.io/v1.32.3/bin/linux/amd64/kube-scheduler https://dl.k8s.io/v1.32.3/bin/linux/amd64/kube-proxy https://dl.k8s.io/v1.32.3/bin/linux/amd64/kubelet https://github.com/kubernetes-sigs/cri-tools/releases/download/v1.32.0/crictl-v1.32.0-linux-amd64.tar.gz https://github.com/opencontainers/runc/releases/download/v1.3.0-rc.1/runc.amd64 https://github.com/containernetworking/plugins/releases/download/v1.6.2/cni-plugins-linux-amd64-v1.6.2.tgz https://github.com/containerd/containerd/releases/download/v2.1.0-beta.0/containerd-2.1.0-beta.0-linux-amd64.tar.gz https://github.com/etcd-io/etcd/releases/download/v3.6.0-rc.3/etcd-v3.6.0-rc.3-linux-amd64.tar.gz root@jumpbox:~/kubernetes-the-hard-way# wget -q --show-progress \ --https-only \ --timestamping \ -P downloads \ -i downloads-$(dpkg --print-architecture).txt kubectl 100%[=================================================>] 54.67M 64.4MB/s in 0.8s kube-apiserver 100%[=================================================>] 88.94M 28.8MB/s in 3.1s kube-controller-manager 100%[=================================================>] 82.00M 17.7MB/s in 4.6s kube-scheduler 100%[=================================================>] 62.79M 22.0MB/s in 2.9s kube-proxy 100%[=================================================>] 63.75M 25.1MB/s in 2.5s kubelet 100%[=================================================>] 73.82M 12.8MB/s in 6.5s crictl-v1.32.0-linux-amd64.ta 100%[=================================================>] 18.21M 55.1MB/s in 0.3s runc.amd64 100%[=================================================>] 11.30M 66.3MB/s in 0.2s cni-plugins-linux-amd64-v1.6. 100%[=================================================>] 50.35M 36.3MB/s in 1.4s containerd-2.1.0-beta.0-linux 100%[=================================================>] 37.01M 56.7MB/s in 0.7s etcd-v3.6.0-rc.3-linux-amd64. 100%[=================================================>] 22.48M 47.2MB/s in 0.5s root@jumpbox:~/kubernetes-the-hard-way# ls -oh downloads total 566M -rw-r--r-- 1 root 51M Jan 7 2025 cni-plugins-linux-amd64-v1.6.2.tgz -rw-r--r-- 1 root 38M Mar 18 2025 containerd-2.1.0-beta.0-linux-amd64.tar.gz -rw-r--r-- 1 root 19M Dec 9 2024 crictl-v1.32.0-linux-amd64.tar.gz -rw-r--r-- 1 root 23M Mar 28 2025 etcd-v3.6.0-rc.3-linux-amd64.tar.gz -rw-r--r-- 1 root 89M Mar 12 2025 kube-apiserver -rw-r--r-- 1 root 83M Mar 12 2025 kube-controller-manager -rw-r--r-- 1 root 55M Mar 12 2025 kubectl -rw-r--r-- 1 root 74M Mar 12 2025 kubelet -rw-r--r-- 1 root 64M Mar 12 2025 kube-proxy -rw-r--r-- 1 root 63M Mar 12 2025 kube-scheduler -rw-r--r-- 1 root 12M Mar 4 2025 runc.amd64 root@jumpbox:~/kubernetes-the-hard-way# mkdir -p downloads/{client,cni-plugins,controller,worker} root@jumpbox:~/kubernetes-the-hard-way# tree -d downloads downloads ├── client ├── cni-plugins ├── controller └── worker 5 directories #압축풀기 root@jumpbox:~/kubernetes-the-hard-way# tar -xvf downloads/crictl-v1.32.0-linux-${ARCH}.tar.gz \ -C downloads/worker/ && tree -ug downloads crictl [root root ] downloads ├── [root root ] client ├── [root root ] cni-plugins ├── [root root ] cni-plugins-linux-amd64-v1.6.2.tgz ├── [root root ] containerd-2.1.0-beta.0-linux-amd64.tar.gz ├── [root root ] controller ├── [root root ] crictl-v1.32.0-linux-amd64.tar.gz ├── [root root ] etcd-v3.6.0-rc.3-linux-amd64.tar.gz ├── [root root ] kube-apiserver ├── [root root ] kube-controller-manager ├── [root root ] kubectl ├── [root root ] kubelet ├── [root root ] kube-proxy ├── [root root ] kube-scheduler ├── [root root ] runc.amd64 └── [root root ] worker └── [1001 127 ] crictl 5 directories, 12 files ################그외 중략 ######################## #압축해제 후 확인진행 root@jumpbox:~/kubernetes-the-hard-way# tree downloads/worker/ downloads/worker/ ├── containerd ├── containerd-shim-runc-v2 ├── containerd-stress ├── crictl └── ctr 1 directory, 5 files root@jumpbox:~/kubernetes-the-hard-way# tree downloads/cni-plugins downloads/cni-plugins ├── bandwidth ├── bridge ├── dhcp ├── dummy ├── firewall ├── host-device ├── host-local ├── ipvlan ├── LICENSE ├── loopback ├── macvlan ├── portmap ├── ptp ├── README.md ├── sbr ├── static ├── tap ├── tuning ├── vlan └── vrf 1 directory, 20 files #파일 이동 및 확인 root@jumpbox:~/kubernetes-the-hard-way# mv downloads/{etcdctl,kubectl} downloads/client/ mv downloads/{etcd,kube-apiserver,kube-controller-manager,kube-scheduler} downloads/controller/ mv downloads/{kubelet,kube-proxy} downloads/worker/ mv downloads/runc.${ARCH} downloads/worker/runc root@jumpbox:~/kubernetes-the-hard-way# tree downloads/client/ tree downloads/controller/ tree downloads/worker/ downloads/client/ ├── etcdctl └── kubectl 1 directory, 2 files downloads/controller/ ├── etcd ├── kube-apiserver ├── kube-controller-manager └── kube-scheduler 1 directory, 4 files downloads/worker/ ├── containerd ├── containerd-shim-runc-v2 ├── containerd-stress ├── crictl ├── ctr ├── kubelet ├── kube-proxy └── runc 1 directory, 8 files #그외 작업 진행후 최종 kubtectl 확인 root@jumpbox:~/kubernetes-the-hard-way# kubectl version --client Client Version: v1.32.3 Kustomize Version: v5.5.0
03 - Provisioning Compute Resources
SSH 접속 환경 설정
root@jumpbox:~/kubernetes-the-hard-way# cat <<EOF > machines.txt 192.168.10.100 server.kubernetes.local server 192.168.10.101 node-0.kubernetes.local node-0 10.200.0.0/24 192.168.10.102 node-1.kubernetes.local node-1 10.200.1.0/24 EOF root@jumpbox:~/kubernetes-the-hard-way# cat machines.txt 192.168.10.100 server.kubernetes.local server 192.168.10.101 node-0.kubernetes.local node-0 10.200.0.0/24 192.168.10.102 node-1.kubernetes.local node-1 10.200.1.0/24 root@jumpbox:~/kubernetes-the-hard-way# while read IP FQDN HOST SUBNET; do echo "${IP} ${FQDN} ${HOST} ${SUBNET}" done < machines.txt 192.168.10.100 server.kubernetes.local server 192.168.10.101 node-0.kubernetes.local node-0 10.200.0.0/24 192.168.10.102 node-1.kubernetes.local node-1 10.200.1.0/24 root@jumpbox:~/kubernetes-the-hard-way# ssh-keygen -t rsa -N "" -f /root/.ssh/id_rsa Generating public/private rsa key pair. Your identification has been saved in /root/.ssh/id_rsa Your public key has been saved in /root/.ssh/id_rsa.pub The key fingerprint is: SHA256:------------------------------------ root@jumpbox The key's randomart image is: +---[RSA 3072]----+ | .+o.B=*++++| | oooEo Xo=oB | | ooo =.+o*..| | . o..o . .=.| | ..So . .o| | . . . | | + o | | + + | | . . | +----[SHA256]-----+ root@jumpbox:~/kubernetes-the-hard-way# while read IP FQDN HOST SUBNET; do sshpass -p 'qwe123' ssh-copy-id -o StrictHostKeyChecking=no root@${IP} done < machines.txt /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub" /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys Number of key(s) added: 1 Now try logging into the machine, with: "ssh -o 'StrictHostKeyChecking=no' 'root@192.168.10.100'" and check to make sure that only the key(s) you wanted were added. /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub" /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys Number of key(s) added: 1 Now try logging into the machine, with: "ssh -o 'StrictHostKeyChecking=no' 'root@192.168.10.101'" and check to make sure that only the key(s) you wanted were added. /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub" /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys Number of key(s) added: 1 Now try logging into the machine, with: "ssh -o 'StrictHostKeyChecking=no' 'root@192.168.10.102'" and check to make sure that only the key(s) you wanted were added. root@jumpbox:~/kubernetes-the-hard-way# while read IP FQDN HOST SUBNET; do ssh -n root@${IP} cat /root/.ssh/authorized_keys done < machines.txt ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCUoQb+fRLPJN03IsqZiCa0nxOuMA7Mo5VpVml+8XsCPa0JCoGxlHn5C8+xmPbp5qg4VhNVRVBIyt3/ipgURJbhgxw/Yo+3Tcq0C5BcmxzrDZGfK8mUAGXPWrHPDtECgZP4+kRyFcGMOwJCJvjTlbFXc/cDypp9RpDtbAXsBR/P+M9gYHtcAI2VRJMjHS0yTvFzf01WwoCYBWg5QG7NgIKVS2qMS75kAdnveBT+nu5E5TN2TmCi5vaD64LC1uuhg3NHDdUw14U0wAENNphQleERk0Y0jvcnFsf5XT6+KNYCfZjgkBPvBCcJRq2szo8Df740lGVoe8vWttAg79DkCB/QZV3UT+k+UN89gskAFtnWKv3MnSsAsjcevxSMsky3eEbZJ5lrN+NC32bTUkovb0paQUhDUf/gHsPQtwD/8FIolNWXopB2cZkwFZIkqs8JIV1N+C5fDczVsioJRgJmJQ53P/lliQXn82hlfe1/ZB+ZxO4mTHHHWC765b8dV0CVn2k= root@jumpbox ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCUoQb+fRLPJN03IsqZiCa0nxOuMA7Mo5VpVml+8XsCPa0JCoGxlHn5C8+xmPbp5qg4VhNVRVBIyt3/ipgURJbhgxw/Yo+3Tcq0C5BcmxzrDZGfK8mUAGXPWrHPDtECgZP4+kRyFcGMOwJCJvjTlbFXc/cDypp9RpDtbAXsBR/P+M9gYHtcAI2VRJMjHS0yTvFzf01WwoCYBWg5QG7NgIKVS2qMS75kAdnveBT+nu5E5TN2TmCi5vaD64LC1uuhg3NHDdUw14U0wAENNphQleERk0Y0jvcnFsf5XT6+KNYCfZjgkBPvBCcJRq2szo8Df740lGVoe8vWttAg79DkCB/QZV3UT+k+UN89gskAFtnWKv3MnSsAsjcevxSMsky3eEbZJ5lrN+NC32bTUkovb0paQUhDUf/gHsPQtwD/8FIolNWXopB2cZkwFZIkqs8JIV1N+C5fDczVsioJRgJmJQ53P/lliQXn82hlfe1/ZB+ZxO4mTHHHWC765b8dV0CVn2k= root@jumpbox ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCUoQb+fRLPJN03IsqZiCa0nxOuMA7Mo5VpVml+8XsCPa0JCoGxlHn5C8+xmPbp5qg4VhNVRVBIyt3/ipgURJbhgxw/Yo+3Tcq0C5BcmxzrDZGfK8mUAGXPWrHPDtECgZP4+kRyFcGMOwJCJvjTlbFXc/cDypp9RpDtbAXsBR/P+M9gYHtcAI2VRJMjHS0yTvFzf01WwoCYBWg5QG7NgIKVS2qMS75kAdnveBT+nu5E5TN2TmCi5vaD64LC1uuhg3NHDdUw14U0wAENNphQleERk0Y0jvcnFsf5XT6+KNYCfZjgkBPvBCcJRq2szo8Df740lGVoe8vWttAg79DkCB/QZV3UT+k+UN89gskAFtnWKv3MnSsAsjcevxSMsky3eEbZJ5lrN+NC32bTUkovb0paQUhDUf/gHsPQtwD/8FIolNWXopB2cZkwFZIkqs8JIV1N+C5fDczVsioJRgJmJQ53P/lliQXn82hlfe1/ZB+ZxO4mTHHHWC765b8dV0CVn2k= root@jumpbox root@jumpbox:~/kubernetes-the-hard-way# while read IP FQDN HOST SUBNET; do ssh -n root@${IP} hostname done < machines.txt server node-0 node-1 #확인진행 root@jumpbox:~/kubernetes-the-hard-way# while read IP FQDN HOST SUBNET; do ssh -n root@${IP} hostname --fqdn done < machines.txt server.kubernetes.local node-0.kubernetes.local node-1.kubernetes.local root@jumpbox:~/kubernetes-the-hard-way# cat /etc/hosts while read IP FQDN HOST SUBNET; do sshpass -p 'qwe123' ssh -n -o StrictHostKeyChecking=no root@${HOST} hostname done < machines.txt 127.0.0.1 localhost # The following lines are desirable for IPv6 capable hosts ::1 localhost ip6-localhost ip6-loopback ff02::1 ip6-allnodes ff02::2 ip6-allrouters 192.168.10.10 jumpbox 192.168.10.100 server.kubernetes.local server 192.168.10.101 node-0.kubernetes.local node-0 192.168.10.102 node-1.kubernetes.local node-1 Warning: Permanently added 'server' (ED25519) to the list of known hosts. server Warning: Permanently added 'node-0' (ED25519) to the list of known hosts. node-0 Warning: Permanently added 'node-1' (ED25519) to the list of known hosts. node-1
04 - Provisioning a CA and Generating TLS Certificates
- 상호 TLS 인증(MTLS)를 사용하여 통신을 진행한다. 즉 통신하는 컴포넌트의 인증서는 전부 생성이 필요하며, 일반적인 k8s의 경우 kubeadm이 생성해준다. 아래는 생성해야하는 목록이다.
| | 개인키 | CSR | 인증서 | 참고 정보 |
| --- | --- | --- | --- | --- |
| Root CA | ca.key | X | ca.crt | |
| admin | admin.key | admin.csr | admin.crt | CN = admin, O = system:masters |
| node-0 | node-0.key | node-0.csr | node-0.crt | CN = system:node:node-0, O = system:nodes |
| node-1 | node-1.key | node-1.csr | node-1.crt | CN = system:node:node-1, O = system:nodes |
| kube-proxy | kube-proxy.key | kube-proxy.csr | kube-proxy.crt | CN = system:kube-proxy, O = system:node-proxier |
| kube-scheduler | kube-scheduler.key | kube-scheduler | kube-scheduler.crt | CN = system:kube-scheduler, O = system:kube-scheduler |
| kube-controller-manager | kube-controller-manager.key | kube-controller-manager.csr | kube-controller-manager.crt | CN = system:kube-controller-manager, O = system:kube-controller-manager |
| kube-api-server | kube-api-server.key | kube-api-server.csr | kube-api-server.crt | CN = kubernetes, SAN: IP(127.0.0.1, **10.32.0.1**), DNS(kubernetes,..) |
| service-accounts | service-accounts.key | service-accounts.csr | service-accounts.crt | CN = service-accounts |
- kind환경의 인증서 확인
```bash
(⎈|kind-myk8s:default) zosys@4:~$ docker exec -i myk8s-control-plane kubeadm certs check-expiration
[check-expiration] Reading configuration from the "kubeadm-config" ConfigMap in namespace "kube-system"...
[check-expiration] Use 'kubeadm init phase upload-config --config your-config.yaml' to re-upload it.
CERTIFICATE EXPIRES RESIDUAL TIME CERTIFICATE AUTHORITY EXTERNALLY MANAGED
admin.conf Jan 05, 2027 13:52 UTC 364d ca no
apiserver Jan 05, 2027 13:52 UTC 364d ca no
apiserver-etcd-client Jan 05, 2027 13:52 UTC 364d etcd-ca no
apiserver-kubelet-client Jan 05, 2027 13:52 UTC 364d ca no
controller-manager.conf Jan 05, 2027 13:52 UTC 364d ca no
etcd-healthcheck-client Jan 05, 2027 13:52 UTC 364d etcd-ca no
etcd-peer Jan 05, 2027 13:52 UTC 364d etcd-ca no
etcd-server Jan 05, 2027 13:52 UTC 364d etcd-ca no
front-proxy-client Jan 05, 2027 13:52 UTC 364d front-proxy-ca no
scheduler.conf Jan 05, 2027 13:52 UTC 364d ca no
super-admin.conf Jan 05, 2027 13:52 UTC 364d ca no
CERTIFICATE AUTHORITY EXPIRES RESIDUAL TIME EXTERNALLY MANAGED
ca Jan 03, 2036 13:52 UTC 9y no
etcd-ca Jan 03, 2036 13:52 UTC 9y no
front-proxy-ca Jan 03, 2036 13:52 UTC 9y no
```CA 생성
root@jumpbox:~/kubernetes-the-hard-way# openssl genrsa -out ca.key 4096 root@jumpbox:~/kubernetes-the-hard-way# ls -l ca.key -rw------- 1 root root 3272 Jan 6 00:05 ca.key root@jumpbox:~/kubernetes-the-hard-way# openssl rsa -in ca.key -text -noout Private-Key: (4096 bit, 2 primes) modulus: 00:bb:3b:8f:cf:85:b5:3e:48:2e:9a:ff:ce:c7:99: 5b:3a:de:7b:28:47:1e:92:a5:a0:9b:b5:d1:fd:9e: 10:af:49:b1:6b:12:2d:cb:78:cb:e0:a4:c5:9d:d4: b8:52:60:46:38:37:bb:f8:c7:a9:1e:d7:d5:55:82: 30:8c:80:ae:66:8d:83:25:18:2a:21:d4:66:8c:db: 3c:c2:4c:d0:e0:15:a4:b2:d0:1b:9d:ae:9d:9e:bd: 2b:57:f1:b6:b8:f0:ad:9b:06:90:43:7e:8c:58:5d: #################중략######################### root@jumpbox:~/kubernetes-the-hard-way# openssl req -x509 -new -sha512 -noenc \ -key ca.key -days 3653 \ -config ca.conf \ -out ca.crt root@jumpbox:~/kubernetes-the-hard-way# ls -l ca.crt -rw-r--r-- 1 root root 1899 Jan 6 00:06 ca.crt #인증서 전체내용 확인 root@jumpbox:~/kubernetes-the-hard-way# openssl x509 -in ca.crt -text -noout | more Certificate: Data: Version: 3 (0x2) Serial Number: 21:a5:b4:64:7c:a3:3d:a7:a4:3f:40:14:05:e9:25:b9:21:a9:7e:be Signature Algorithm: sha512WithRSAEncryption Issuer: C = US, ST = Washington, L = Seattle, CN = CA Validity Not Before: Jan 5 15:06:27 2026 GMT Not After : Jan 6 15:06:27 2036 GMT Subject: C = US, ST = Washington, L = Seattle, CN = CA Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (4096 bit) ############################중략 #################################참고) kind환경의 ca.crt 확인
(⎈|kind-myk8s:default) zosys@4:~$ docker exec -i myk8s-control-plane cat /etc/kubernetes/pki/ca.crt | openssl x509 -text -noout Certificate: Data: Version: 3 (0x2) Serial Number: 8519439439972151590 (0x763b210860fe3126) Signature Algorithm: sha256WithRSAEncryption Issuer: CN = kubernetes Validity Not Before: Jan 5 13:47:29 2026 GMT Not After : Jan 3 13:52:29 2036 GMT Subject: CN = kubernetes Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (2048 bit) Modulus: 00:d4:a5:b1:57:06:bc:c7:ff:85:ba:d6:44:74:8c: 0a:a4:3e:3c:c7:e7:15:09:f9:31:f1:a0:8e:92:d0: 90:f8:19:52:98:8e:29:92:17:37:8d:9d:fe:10:fa: d7:0f:1e:41:89:53:62:18:d9:b5:c4:b7:43:50:e6: 5c:fd:2c:87:46:a7:54:b0:ea:ea:6d:f6:d8:93:cc: 1f:2f:7a:18:28:6e:17:e7:e2:e8:3b:26:c8:ae:3d: ### 중략#####
admin인증서 생성
root@jumpbox:~/kubernetes-the-hard-way# openssl genrsa -out admin.key 4096 root@jumpbox:~/kubernetes-the-hard-way# openssl req -new -key admin.key -sha256 \ -config ca.conf -section admin \ -out admin.csr root@jumpbox:~/kubernetes-the-hard-way# ls -l admin.csr -rw-r--r-- 1 root root 1830 Jan 6 00:14 admin.csr root@jumpbox:~/kubernetes-the-hard-way# openssl req -in admin.csr -text -noout | more Certificate Request: Data: Version: 1 (0x0) Subject: CN = admin, O = system:masters Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (4096 bit) Modulus: 00:93:3b:e0:7a:87:5d:80:69:b1:ad:6a:38:74:55: c0:a5:d4:5f:f6:cc:9d:b7:3c:6a:dc:7c:f1:fd:cc: c1:dd:00:27:5e:6c:7f:2d:77:81:02:7c:ce:55:36: 79:75:dc:83:bf:60:23:67:df:32:53:cc:19:15:0e: 04:23:7f:d7:79:da:43:79:a9:57:9d:8e:dd:96:d2: ### 중략#### root@jumpbox:~/kubernetes-the-hard-way# openssl x509 -req -days 3653 -in admin.csr \ -copy_extensions copyall \ -sha256 -CA ca.crt \ -CAkey ca.key \ -CAcreateserial \ -out admin.crt Certificate request self-signature ok subject=CN = admin, O = system:masters root@jumpbox:~/kubernetes-the-hard-way# ls -l admin.crt openssl x509 -in admin.crt -text -noout | more -rw-r--r-- 1 root root 2021 Jan 6 00:16 admin.crt Certificate: Data: Version: 3 (0x2) Serial Number: 36:ea:c4:ee:d2:b3:c2:0c:0d:4c:4a:26:a3:56:3b:e1:a2:22:fa:c7 Signature Algorithm: sha256WithRSAEncryption Issuer: C = US, ST = Washington, L = Seattle, CN = CA Validity Not Before: Jan 5 15:16:49 2026 GMT Not After : Jan 6 15:16:49 2036 GMT Subject: CN = admin, O = system:masters Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (4096 bit) Modulus: 00:93:3b:e0:7a:87:5d:80:69:b1:ad:6a:38:74:55: c0:a5:d4:5f:f6:cc:9d:b7:3c:6a:dc:7c:f1:fd:cc: c1:dd:00:27:5e:6c:7f:2d:77:81:02:7c:ce:55:36: 79:75:dc:83:bf:60:23:67:df:32:53:cc:19:15:0e: 04:23:7f:d7:79:da:43:79:a9:57:9d:8e:dd:96:d2: 2f:74:8a:83:41:80:01:21:f3:96:63:87:b6:27:65: b0:e4:aa:5d:1d:31:a4:15:01:c5:98:66:ec:5a:9e: 27:78:2d:e8:2f:d1:e6:20:d6:15:d4:1e:43:2a:77: ### 중략####참고 ) kind환경의 admin인증서 확인
(⎈|kind-myk8s:default) zosys@4:~$ docker exec -i myk8s-control-plane cat /etc/kubernetes/super-admin.conf | grep client-certificate-data | cut -d ':' -f2 | tr -d ' ' | base64 -d | openssl x509 -text -noout Certificate: Data: Version: 3 (0x2) Serial Number: 1007749187623256237 (0xdfc3e8bfef900ad) Signature Algorithm: sha256WithRSAEncryption Issuer: CN = kubernetes Validity Not Before: Jan 5 13:47:29 2026 GMT Not After : Jan 5 13:52:29 2027 GMT Subject: O = system:masters, CN = kubernetes-super-admin Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (2048 bit) Modulus: 00:a4:12:67:9f:3d:22:5b:a0:f8:0c:05:5c:d0:11: 2c:cb:98:55:7e:d8:84:a9:cc:39:6d:89:c0:c2:12: 60:e1:32:ed:28:a4:33:2d:67:89:20:0e:f9:c1:d6: bb:08:a7:9e:ec:f5:0a:de:9c:ca:ea:ed:82:da:50: 35:d7:92:2c:85:f0:df:2c:e3:d1:7f:ca:e0:52:32: # krew rbac-tool 플러그인 활용하기 (⎈|kind-myk8s:default) zosys@4:~$ kubectl rbac-tool lookup system:masters SUBJECT | SUBJECT TYPE | SCOPE | NAMESPACE | ROLE | BINDING -----------------+--------------+-------------+-----------+---------------+---------------- system:masters | Group | ClusterRole | | cluster-admin | cluster-admin (⎈|kind-myk8s:default) zosys@4:~$ kubectl describe clusterroles cluster-admin Name: cluster-admin Labels: kubernetes.io/bootstrapping=rbac-defaults Annotations: rbac.authorization.kubernetes.io/autoupdate: true PolicyRule: Resources Non-Resource URLs Resource Names Verbs --------- ----------------- -------------- ----- *.* [] [] [*] [*] [] [*] (⎈|kind-myk8s:default) zosys@4:~$ kubectl describe clusterrolebindings cluster-admin Name: cluster-admin Labels: kubernetes.io/bootstrapping=rbac-defaults Annotations: rbac.authorization.kubernetes.io/autoupdate: true Role: Kind: ClusterRole Name: cluster-admin Subjects: Kind Name Namespace ---- ---- --------- Group system:masters
나머지 인증서 생성
#인증서 생성전 오타 변경 root@jumpbox:~/kubernetes-the-hard-way# sed -i 's/system:system:kube-scheduler/system:kube-scheduler/' ca.conf root@jumpbox:~/kubernetes-the-hard-way# cat ca.conf | grep system:kube-scheduler CN = system:kube-scheduler O = system:kube-scheduler root@jumpbox:~/kubernetes-the-hard-way# cat ca.conf | grep system:kube-scheduler CN = system:kube-scheduler O = system:kube-scheduler root@jumpbox:~/kubernetes-the-hard-way# certs=( "node-0" "node-1" "kube-proxy" "kube-scheduler" "kube-controller-manager" "kube-api-server" "service-accounts" ) root@jumpbox:~/kubernetes-the-hard-way# echo ${certs[*]} node-0 node-1 kube-proxy kube-scheduler kube-controller-manager kube-api-server service-accounts root@jumpbox:~/kubernetes-the-hard-way# for i in ${certs[*]}; do openssl genrsa -out "${i}.key" 4096 openssl req -new -key "${i}.key" -sha256 \ -config "ca.conf" -section ${i} \ -out "${i}.csr" openssl x509 -req -days 3653 -in "${i}.csr" \ -copy_extensions copyall \ -sha256 -CA "ca.crt" \ -CAkey "ca.key" \ -CAcreateserial \ -out "${i}.crt" done Certificate request self-signature ok subject=CN = system:node:node-0, O = system:nodes, C = US, ST = Washington, L = Seattle Certificate request self-signature ok subject=CN = system:node:node-1, O = system:nodes, C = US, ST = Washington, L = Seattle Certificate request self-signature ok subject=CN = system:kube-proxy, O = system:node-proxier, C = US, ST = Washington, L = Seattle Certificate request self-signature ok subject=CN = system:kube-scheduler, O = system:kube-scheduler, C = US, ST = Washington, L = Seattle Certificate request self-signature ok subject=CN = system:kube-controller-manager, O = system:kube-controller-manager, C = US, ST = Washington, L = Seattle Certificate request self-signature ok subject=CN = kubernetes, C = US, ST = Washington, L = Seattle Certificate request self-signature ok subject=CN = service-accounts참고 ) kind k8s 인증서 보기
(⎈|kind-myk8s:default) zosys@4:~$ docker exec -it myk8s-control-plane ls -al /etc/kubernetes total 60 drwxr-xr-x 1 root root 4096 Jan 5 13:52 . drwxr-xr-x 1 root root 4096 Jan 5 13:52 .. -rw------- 1 root root 5643 Jan 5 13:52 admin.conf -rw------- 1 root root 5658 Jan 5 13:52 controller-manager.conf -rw------- 1 root root 2007 Jan 5 13:52 kubelet.conf drwxr-xr-x 1 root root 4096 Jan 5 13:52 manifests drwxr-xr-x 3 root root 4096 Jan 5 13:52 pki -rw------- 1 root root 5602 Jan 5 13:52 scheduler.conf -rw------- 1 root root 5663 Jan 5 13:52 super-admin.conf (⎈|kind-myk8s:default) zosys@4:~$ docker exec -it myk8s-control-plane ls -al /var/lib/kubelet/pki total 20 drwxr-xr-x 2 root root 4096 Jan 5 13:52 . drwx------ 9 root root 4096 Jan 5 13:52 .. -rw------- 1 root root 2839 Jan 5 13:52 kubelet-client-2026-01-05-13-52-31.pem lrwxrwxrwx 1 root root 59 Jan 5 13:52 kubelet-client-current.pem -> /var/lib/kubelet/pki/kubelet-client-2026-01-05-13-52-31.pem -rw-r--r-- 1 root root 2343 Jan 5 13:52 kubelet.crt -rw------- 1 root root 1679 Jan 5 13:52 kubelet.key ## API서버에 Alternative Name확인 (⎈|kind-myk8s:default) zosys@4:~$ docker exec -i myk8s-control-plane cat /etc/kubernetes/pki/apiserver.crt | openssl x509 -text -noout Certificate: Data: Version: 3 (0x2) Serial Number: 8699350173748144468 (0x78ba4ce452fda954) Signature Algorithm: sha256WithRSAEncryption Issuer: CN = kubernetes Validity Not Before: Jan 5 13:47:29 2026 GMT Not After : Jan 5 13:52:29 2027 GMT Subject: CN = kube-apiserver Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (2048 bit) Modulus: 00:a5:26:b2:7b:33:e3:a8:c6:01:d5:ba:26:ba:e9: 2b:70:58:c1:0b:e3:35:a3:96:d1:de:c5:7e:80:44: 0b:61:af:12:1a:dd:e5:83:ed:88:bb:be:c7:c0:6f: 05:71:9b:4b:82:49:12:23:a0:46:44:91:ef:68:49: 12:45:26:2a:07:28:38:bd:33:c0:76:61:cb:51:af: 18:c9:4c:96:a6:db:98:e0:8c:82:50:2f:8a:3e:ed: 79:f3:d7:b6:89:45:9e:d2:fb:2c:0a:b2:1f:14:fa: fa:f1:29:cb:5c:2b:d2:26:81:50:e7:0f:98:57:9c: 20:90:89:d3:d1:7b:d7:2f:c7:a6:a3:aa:b0:9b:f8: 78:c4:57:73:fb:82:a8:9d:1f:c6:c6:38:67:24:49: 4f:0f:cb:d7:61:f6:5d:0c:89:cf:b8:01:c6:af:af: 51:91:12:b8:57:e0:ab:13:30:c7:a5:1f:a8:24:49: 85:1e:e1:8c:d1:19:f8:68:2f:be:b3:eb:37:79:e5: 5f:b1:85:78:9e:05:a3:dd:b2:c2:92:03:1f:e1:a3: 39:f8:b5:9f:23:b2:b2:1a:c4:05:3a:3e:6c:17:3f: 86:94:47:b6:a3:36:87:3e:59:3c:40:06:25:11:a3: 26:8f:02:da:cd:c7:00:d0:ca:db:71:75:41:a6:f3: 5f:03 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Key Usage: critical Digital Signature, Key Encipherment X509v3 Extended Key Usage: TLS Web Server Authentication X509v3 Basic Constraints: critical CA:FALSE X509v3 Authority Key Identifier: F3:A5:5A:DF:0E:70:F9:F5:ED:2C:DC:76:A8:34:22:CF:A4:3A:64:F1 X509v3 Subject Alternative Name: DNS:**kubernetes, DNS:kubernetes.default, DNS:kubernetes.default.svc, DNS:kubernetes.default.svc.cluster.local, DNS:localhost, DNS:myk8s-control-plane, IP Address:10.96.0.1, IP Address:172.18.0.3, IP Address:127.0.0.1** Signature Algorithm: sha256WithRSAEncryption Signature Value: 5c:9e:b9:6f:e7:42:51:84:81:e0:f2:82:be:f8:d9:07:62:8b: 51:23:0c:56:8f:f0:7a:43:e5:d7:93:b6:2a:0b:ba:98:55:9b: 81:fd:2a:52:0a:e1:7d:7a:ec:bb:02:dd:d1:72:64:28:ba:d0: 5a:50:4c:ca:f0:c4:3b:13:c7:9f:04:df:d5:5d:6f:9b:d7:bf: 18:c5:b4:a3:7c:af:b5:bb:ae:ad:b3:c9:88:ca:6d:25:6c:86: 5f:c8:d6:cb:ae:fa:2a:d1:ba:43:04:68:7f:78:78:75:9e:9a: 54:cb:1d:00:f8:f8:91:9e:4b:2c:cb:bd:b7:15:51:1c:c5:80: (⎈|kind-myk8s:default) zosys@4:~$ kubectl describe pod -n kube-system kube-apiserver-myk8s-control-plane Name: kube-apiserver-myk8s-control-plane Namespace: kube-system Priority: 2000001000 #####################중략 후 인증서정보 확인############################ --etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt --etcd-certfile=/etc/kubernetes/pki/apiserver-etcd-client.crt --etcd-keyfile=/etc/kubernetes/pki/apiserver-etcd-client.key --etcd-servers=https://127.0.0.1:2379 --kubelet-client-certificate=/etc/kubernetes/pki/apiserver-kubelet-client.crt --kubelet-client-key=/etc/kubernetes/pki/apiserver-kubelet-client.key --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname --proxy-client-cert-file=/etc/kubernetes/pki/front-proxy-client.crt --proxy-client-key-file=/etc/kubernetes/pki/front-proxy-client.key --requestheader-allowed-names=front-proxy-client --requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt
Distribute the Client and Server Certificates(인증서 배포)
root@jumpbox:~/kubernetes-the-hard-way# for host in node-0 node-1; do ssh root@${host} mkdir /var/lib/kubelet/ scp ca.crt root@${host}:/var/lib/kubelet/ scp ${host}.crt \ root@${host}:/var/lib/kubelet/kubelet.crt scp ${host}.key \ root@${host}:/var/lib/kubelet/kubelet.key done ca.crt 100% 1899 1.3MB/s 00:00 node-0.crt 100% 2147 1.1MB/s 00:00 node-0.key 100% 3272 1.9MB/s 00:00 ca.crt 100% 1899 1.4MB/s 00:00 node-1.crt 100% 2147 1.1MB/s 00:00 node-1.key 100% 3268 2.0MB/s 00:00 root@jumpbox:~/kubernetes-the-hard-way# ssh node-0 ls -l /var/lib/kubelet ssh node-1 ls -l /var/lib/kubelet total 12 -rw-r--r-- 1 root root 1899 Jan 6 00:37 ca.crt -rw-r--r-- 1 root root 2147 Jan 6 00:37 kubelet.crt -rw------- 1 root root 3272 Jan 6 00:37 kubelet.key total 12 -rw-r--r-- 1 root root 1899 Jan 6 00:37 ca.crt -rw-r--r-- 1 root root 2147 Jan 6 00:37 kubelet.crt -rw------- 1 root root 3268 Jan 6 00:37 kubelet.key root@jumpbox:~/kubernetes-the-hard-way# scp \ ca.key ca.crt \ kube-api-server.key kube-api-server.crt \ service-accounts.key service-accounts.crt \ root@server:~/ ca.key 100% 3272 1.3MB/s 00:00 ca.crt 100% 1899 1.4MB/s 00:00 kube-api-server.key 100% 3272 2.4MB/s 00:00 kube-api-server.crt 100% 2354 1.8MB/s 00:00 service-accounts.key 100% 3268 2.2MB/s 00:00 service-accounts.crt 100% 2004 1.4MB/s 00:00 root@jumpbox:~/kubernetes-the-hard-way# ssh server ls -l /root total 24 -rw-r--r-- 1 root root 1899 Jan 6 00:38 ca.crt -rw------- 1 root root 3272 Jan 6 00:38 ca.key -rw-r--r-- 1 root root 2354 Jan 6 00:38 kube-api-server.crt -rw------- 1 root root 3272 Jan 6 00:38 kube-api-server.key -rw-r--r-- 1 root root 2004 Jan 6 00:38 service-accounts.crt -rw------- 1 root root 3268 Jan 6 00:38 service-accounts.key
05 - Generating Kubernetes Configuration Files for Authentication
The kubelet Kubernetes Configuration File
kind환경의 kubelet설정 확인하기(⎈|kind-myk8s:default) zosys@4:~$ kubectl describe pod -n kube-system kube-apiserver-myk8s-control-plane Name: kube-apiserver-myk8s-control-plane Namespace: kube-system Priority: 2000001000 Priority Class Name: system-node-critical Node: myk8s-control-plane/172.18.0.3 Start Time: Mon, 05 Jan 2026 22:52:38 +0900 Labels: component=kube-apiserver tier=control-plane Annotations: kubeadm.kubernetes.io/kube-apiserver.advertise-address.endpoint: 172.18.0.3:6443 kubernetes.io/config.hash: 6dadff8c64cc62e7b3846733d2478bdd kubernetes.io/config.mirror: 6dadff8c64cc62e7b3846733d2478bdd kubernetes.io/config.seen: 2026-01-05T13:52:38.459844636Z kubernetes.io/config.source: file Status: Running SeccompProfile: RuntimeDefault IP: 172.18.0.3 IPs: IP: 172.18.0.3 Controlled By: Node/myk8s-control-plane Containers: kube-apiserver: Container ID: containerd://872e95b24c42f80855f00ffda199192af35f4b24ca9ee16587cfa03e13c692fe Image: registry.k8s.io/kube-apiserver:v1.32.8 Image ID: sha256:0d4edaa48e2f940c934e0f7cfd5209fc85e65ab5e842b980f41263d1764661f1 Port: <none> Host Port: <none> Command: kube-apiserver --advertise-address=172.18.0.3 --allow-privileged=true --authorization-mode=Node,RBAC#kubeconfig 생성 및 확인 root@jumpbox:~/kubernetes-the-hard-way# kubectl config set-cluster kubernetes-the-hard-way \ --certificate-authority=ca.crt \ --embed-certs=true \ --server=https://server.kubernetes.local:6443 \ --kubeconfig=node-0.kubeconfig && ls -l node-0.kubeconfig && cat node-0.kubeconfig Cluster "kubernetes-the-hard-way" set. #############################중략######################################## root@jumpbox:~/kubernetes-the-hard-way# ls -l *.kubeconfig -rw------- 1 root root 10161 Jan 7 23:02 node-0.kubeconfig -rw------- 1 root root 10157 Jan 7 23:03 node-1.kubeconfig #kind의 설정확인 (⎈|kind-myk8s:default) zosys@4:~$ cat .kube/config apiVersion: v1 clusters: - cluster: certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURCVENDQWUyZ0F3SUJBZ0lJZGpzaENHRCtNU1l3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB5TmpBeE1EVXhNelEzTWpsYUZ3MHpOakF4TURNeE16VXlNamxhTUJVeApFekFSQmdOVkJBTVRDbXQxWW1WeWJtVjBaWE13Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLCkFvSUJBUURVcGJGWEJyekgvNFc2MWtSMGpBcWtQanpINXhVSitUSHhvSTZTMEpENEdWS1lqaW1TRnplTm5mNFEKK3RjUEhrR0pVMklZMmJYRXQwTlE1bHo5TElkR3AxU3c2dXB0OXRpVHpCOHZlaGdvYmhmbjR1ZzdKc2l1UFNldwpYY2xnSkNjc0YvNDM5dGtrRVlETXVpSDFFVTZ6QXJ3YkJjSkVHWHk1Z3JrOHpQOG56N245U1UrSlNVOTR2S0RCCjFKb0hqS1doQnhtT3RiczJkSTByenFUcUVxRkRHWGo2b09HejdheGU4YUhBSDlVQ1IySUdFRnVyNHY3c1pTN2gKQ1AydllESEdCT1BXRS9vV20zSVJMZ0xVRnRzbVdSd0hqSTZWVmFyTlVqSXh2dzF0dFBlVDJSYUdRb0dJcExIUQpTdWFoT2NUV1VESkdnd2pCd3owSk80R2xGdnY1QWdNQkFBR2pXVEJYTUE0R0ExVWREd0VCL3dRRUF3SUNwREFQCkJnTlZIUk1CQWY4RUJUQURBUUgvTUIwR0ExVWREZ1FXQkJUenBWcmZEbkQ1OWUwczNIYW9OQ0xQcERwazhUQVYKQmdOVkhSRUVEakFNZ2dwcmRXSmxjbTVsZEdWek1BMEdDU3FHU0liM0RRRUJDd1VBQTRJQkFRQmlEMWRkZDkwUQpaS2UvU2pNbTQwYVVtZlU2YVhFNG9DMndJT1RwMlkxNjBobGMrUXF6aUZEdktGY3k2MjVzWEpRcDRmb2lBajFtCmxkWGdLcTZTVDM1aVFqdGU0OGhYNG95bzNXQ1lYYXYvWkJDVmZoZ2pBTmlKelAwUTAzc2lTdVk2RlNxTDBHTysKZktncEVGS3luclFKdmZ6ckVmU3gzTWJqRTdYOEk5QVZmUTUxLzhFNEVyb1JQUzBVRXZGbGdiUCtwWWQveTZsVgpUTm8rMjFCN0V0OThhU2Y5V3lrQnZpMTZZeUhGckJPOUkwRGdtNlFxSVl0QXd6S1N5dmRCTitXVk12UitHSFBmCkVwY3VONUcyQ2x6dUd5aTJNU0VCRzhnRDNnL29uSjQwL3p3MHdTMU1JT1lweU5FMnhtNExhYll3c3dqOWVBZkQKQ0hkbndaOFdLMU15Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K server: https://127.0.0.1:34991 name: kind-myk8s#(참고) kind system:node관련 정보 (⎈|kind-myk8s:default) zosys@4:~$ kubectl describe clusterroles system:node Name: system:node Labels: kubernetes.io/bootstrapping=rbac-defaults Annotations: rbac.authorization.kubernetes.io/autoupdate: true PolicyRule: Resources Non-Resource URLs Resource Names Verbs --------- ----------------- -------------- ----- leases.coordination.k8s.io [] [] [create delete get patch update] csinodes.storage.k8s.io [] [] [create delete get patch update] nodes [] [] [create get list watch patch update] certificatesigningrequests.certificates.k8s.io [] [] [create get list watch] events [] [] [create patch update] pods/eviction [] [] [create] serviceaccounts/token [] [] [create] tokenreviews.authentication.k8s.io [] [] [create] localsubjectaccessreviews.authorization.k8s.io [] [] [create] subjectaccessreviews.authorization.k8s.io [] [] [create] pods [] [] [get list watch create delete] configmaps [] [] [get list watch] secrets [] [] [get list watch] services [] [] [get list watch] runtimeclasses.node.k8s.io [] [] [get list watch] csidrivers.storage.k8s.io [] [] [get list watch] persistentvolumeclaims/status [] [] [get patch update] endpoints [] [] [get] persistentvolumeclaims [] [] [get] persistentvolumes [] [] [get] volumeattachments.storage.k8s.io [] [] [get] nodes/status [] [] [patch update] pods/status [] [] [patch update] #####################################중략###########################################kube-proxy configfile생성
root@jumpbox:~/kubernetes-the-hard-way# cat kube-proxy.kubeconfig apiVersion: v1 clusters - cluster: certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tL ######중략######kube-controller-manager configfile 생성
root@jumpbox:~/kubernetes-the-hard-way# cat kube-controller-manager.kubeconfig apiVersion: v1 clusters: - cluster: certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0URS0 ######중략######kube-scheduler configfile생성
root@jumpbox:~/kubernetes-the-hard-way# cat kube-scheduler.kubeconfig apiVersion: v1 clusters: - cluster: certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUZURENDQXpTZ0F3SUJBZ0lVSWFXMFpIeWpQYWVrUDBBVUJla2x1U0dwZnI0d0RRWUpLb1pJaHZjTkFRRU4KQlFBd1FURUxNQWtHQTFVRUJoTUNWVk14RXpBUkJnTlZCQWdNQ2xkaGMyaHBibWQwYjI0eEVEQU9CZ05WQkFjTQpCMU5sWVhSMGJHVXhDekFKQmdOVkJBTU1Ba05CTUI0WERUSTJNREV3TlRFMU1EWXlOMW9YRFRNMk1ERXdOakUxCk1EWXlOMW93UVRFTE1Ba0dBMVVFQmhNQ1ZWTXhFekFSQmdOVkJBZ01DbGRoYzJocGJtZDBiMjR4RURBT0JnTl ######중략#######admin configfile생성
root@jumpbox:~/kubernetes-the-hard-way# cat admin.kubeconfig apiVersion: v1 clusters: - cluster: certificate-authority-data: LS0tLS1CRUdJTiBDRV ######중략#########Distribute the Kubernetes Configuration Files
root@jumpbox:~/kubernetes-the-hard-way# ls -l *.kubeconfig -rw------- 1 root root 9953 Jan 7 23:12 admin.kubeconfig -rw------- 1 root root 10305 Jan 7 23:09 kube-controller-manager.kubeconfig -rw------- 1 root root 10187 Jan 7 23:08 kube-proxy.kubeconfig -rw------- 1 root root 10215 Jan 7 23:10 kube-scheduler.kubeconfig -rw------- 1 root root 10161 Jan 7 23:02 node-0.kubeconfig -rw------- 1 root root 10157 Jan 7 23:03 node-1.kubeconfig # 확인 root@jumpbox:~/kubernetes-the-hard-way# ssh node-0 ls -l /var/lib/*/kubeconfig ssh node-1 ls -l /var/lib/*/kubeconfig -rw------- 1 root root 10161 Jan 7 23:13 /var/lib/kubelet/kubeconfig -rw------- 1 root root 10187 Jan 7 23:13 /var/lib/kube-proxy/kubeconfig -rw------- 1 root root 10157 Jan 7 23:13 /var/lib/kubelet/kubeconfig -rw------- 1 root root 10187 Jan 7 23:13 /var/lib/kube-proxy/kubeconfig ssh server ls -l /root/*.kubeconfig
06 - Generating the Data Encryption Config and Key
root@jumpbox:~/kubernetes-the-hard-way# cat configs/encryption-config.yaml
kind: EncryptionConfiguration
apiVersion: apiserver.config.k8s.io/v1
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key1
secret: ${ENCRYPTION_KEY}
- identity: {}
root@jumpbox:~/kubernetes-the-hard-way# envsubst < configs/encryption-config.yaml > encryption-config.yaml
root@jumpbox:~/kubernetes-the-hard-way# cat encryption-config.yaml
kind: EncryptionConfiguration
apiVersion: apiserver.config.k8s.io/v1
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key1
secret:
- identity: {}
root@jumpbox:~/kubernetes-the-hard-way# scp encryption-config.yaml root@server:~/
encryption-config.yaml 100% 227 183.1KB/s 00:00
root@jumpbox:~/kubernetes-the-hard-way# ssh server ls -l /root/encryption-config.yaml
-rw-r--r-- 1 root root 227 Jan 7 23:26 /root/encryption-config.yaml
07 - Bootstrapping the etcd Cluster
##etcd 기동
root@jumpbox:~/kubernetes-the-hard-way# cat units/etcd.service | grep controller
--name controller \
--initial-cluster controller=http://127.0.0.1:2380 \
root@jumpbox:~/kubernetes-the-hard-way# ETCD_NAME=server
cat > units/etcd.service <<EOF
[Unit]
Description=etcd
Documentation=https://github.com/etcd-io/etcd
[Service]
Type=notify
ExecStart=/usr/local/bin/etcd \\
--name ${ETCD_NAME} \\
--initial-advertise-peer-urls http://127.0.0.1:2380 \\
--listen-peer-urls http://127.0.0.1:2380 \\
--listen-client-urls http://127.0.0.1:2379 \\
--advertise-client-urls http://127.0.0.1:2379 \\
--initial-cluster-token etcd-cluster-0 \\
--initial-cluster ${ETCD_NAME}=http://127.0.0.1:2380 \\
--initial-cluster-state new \\
--data-dir=/var/lib/etcd
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
root@jumpbox:~/kubernetes-the-hard-way# cat units/etcd.service | grep server
--name server \
--initial-cluster server=http://127.0.0.1:2380 \
root@jumpbox:~/kubernetes-the-hard-way# cat units/etcd.service | grep server
--name server \
--initial-cluster server=http://127.0.0.1:2380 \
root@jumpbox:~/kubernetes-the-hard-way# scp \
downloads/controller/etcd \
downloads/client/etcdctl \
units/etcd.service \
root@server:~/
etcd 100% 24MB 47.3MB/s 00:00
etcdctl 100% 16MB 63.4MB/s 00:00
etcd.service
root@jumpbox:~/kubernetes-the-hard-way# ssh root@server
root@server:~# mv etcd etcdctl /usr/local/bin/
root@server:~# mkdir -p /etc/etcd /var/lib/etcd
root@server:~# chmod 700 /var/lib/etcd
root@server:~# cp ca.crt kube-api-server.key kube-api-server.crt /etc/etcd/
root@server:~# systemctl status etcd --no-pager
● etcd.service - etcd
Loaded: loaded (/etc/systemd/system/etcd.service; enabled; preset: enabled)
Active: active (running) since Wed 2026-01-07 23:29:51 KST; 4s ago
Docs: https://github.com/etcd-io/etcd
Main PID: 2607 (etcd)
Tasks: 8 (limit: 2297)
Memory: 10.4M
CPU: 97ms
#######중략###########
root@server:~# etcdctl member list
6702b0a34e2cfd39, started, server, http://127.0.0.1:2380, http://127.0.0.1:2379, false
root@server:~# etcdctl member list -w table
+------------------+---------+--------+-----------------------+-----------------------+------------+
| ID | STATUS | NAME | PEER ADDRS | CLIENT ADDRS | IS LEARNER |
+------------------+---------+--------+-----------------------+-----------------------+------------+
| 6702b0a34e2cfd39 | started | server | http://127.0.0.1:2380 | http://127.0.0.1:2379 | false |
+------------------+---------+--------+-----------------------+-----------------------+------------+
root@server:~# etcdctl endpoint status -w table
+----------------+------------------+------------+-----------------+---------+--------+-----------------------+-------+-----------+------------+-----------+------------+--------------------+--------+--------------------------+-------------------+
| ENDPOINT | ID | VERSION | STORAGE VERSION | DB SIZE | IN USE | PERCENTAGE NOT IN USE | QUOTA | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS | DOWNGRADE TARGET VERSION | DOWNGRADE ENABLED |
+----------------+------------------+------------+-----------------+---------+--------+-----------------------+-------+-----------+------------+-----------+------------+--------------------+--------+--------------------------+-------------------+
| 127.0.0.1:2379 | 6702b0a34e2cfd39 | 3.6.0-rc.3 | 3.6.0 | 20 kB | 16 kB | 20% | 0 B | true | false | 2 | 4 | 4 | | | false |
+----------------+------------------+------------+-----------------+---------+--------+-----------------------+-------+-----------+------------+-----------+------------+--------------------+--------+--------------------------+-------------------+
08 - Bootstrapping the Kubernetes Control Plane
설정파일 작성 및 server전달
root@jumpbox:~/kubernetes-the-hard-way# cat ca.conf | grep '\[kube-api-server_alt_names' -A2 [kube-api-server_alt_names] IP.0 = 127.0.0.1 IP.1 = 10.32.0.1 root@jumpbox:~/kubernetes-the-hard-way# cat units/kube-apiserver.service [Unit] Description=Kubernetes API Server Documentation=https://github.com/kubernetes/kubernetes [Service] ExecStart=/usr/local/bin/kube-apiserver \ --allow-privileged=true \ --apiserver-count=1 \ --audit-log-maxage=30 \ --audit-log-maxbackup=3 \ --audit-log-maxsize=100 \ --audit-log-path=/var/log/audit.log \ --authorization-mode=Node,RBAC \ ##########중략################ root@jumpbox:~/kubernetes-the-hard-way# cat configs/kube-apiserver-to-kubelet.yaml ; echo 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: - "" #apiserver subject CN확인 root@jumpbox:~/kubernetes-the-hard-way# openssl x509 -in kube-api-server.crt -text -noout Certificate: Data: Version: 3 (0x2) Serial Number: 36:ea:c4:ee:d2:b3:c2:0c:0d:4c:4a:26:a3:56:3b:e1:a2:22:fa:cd Signature Algorithm: sha256WithRSAEncryption Issuer: C = US, ST = Washington, L = Seattle, CN = CA Validity Not Before: Jan 5 15:25:45 2026 GMT Not After : Jan 6 15:25:45 2036 GMT **Subject: CN = kubernetes, C = US, ST = Washington, L = Seattle** ####중략##### # kube-scheduler root@jumpbox:~/kubernetes-the-hard-way# cat units/kube-scheduler.service ; echo [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 root@jumpbox:~/kubernetes-the-hard-way# cat configs/kube-scheduler.yaml ; echo apiVersion: kubescheduler.config.k8s.io/v1 kind: KubeSchedulerConfiguration clientConnection: kubeconfig: "/var/lib/kubernetes/kube-scheduler.kubeconfig" leaderElection: leaderElect: true root@jumpbox:~/kubernetes-the-hard-way# cat units/kube-controller-manager.service ; echo [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.crt \ --cluster-signing-key-file=/var/lib/kubernetes/ca.key \ --kubeconfig=/var/lib/kubernetes/kube-controller-manager.kubeconfig \ --root-ca-file=/var/lib/kubernetes/ca.crt \ --service-account-private-key-file=/var/lib/kubernetes/service-accounts.key \ --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 #SCP전송후 확인 root@jumpbox:~/kubernetes-the-hard-way# ssh server ls -l /root total 295436 -rw------- 1 root root 9953 Jan 7 23:14 admin.kubeconfig -rw-r--r-- 1 root root 1899 Jan 6 00:38 ca.crt -rw------- 1 root root 3272 Jan 6 00:38 ca.key -rw-r--r-- 1 root root 227 Jan 7 23:26 encryption-config.yaml -rwxr-xr-x 1 root root 93261976 Jan 7 23:38 kube-apiserver -rw-r--r-- 1 root root 2354 Jan 6 00:38 kube-api-server.crt -rw------- 1 root root 3272 Jan 6 00:38 kube-api-server.key -rw-r--r-- 1 root root 1442 Jan 7 23:38 kube-apiserver.service -rw-r--r-- 1 root root 727 Jan 7 23:38 kube-apiserver-to-kubelet.yaml -rwxr-xr-x 1 root root 85987480 Jan 7 23:38 kube-controller-manager -rw------- 1 root root 10305 Jan 7 23:14 kube-controller-manager.kubeconfig -rw-r--r-- 1 root root 735 Jan 7 23:38 kube-controller-manager.service -rwxr-xr-x 1 root root 57323672 Jan 7 23:38 kubectl -rwxr-xr-x 1 root root 65843352 Jan 7 23:38 kube-scheduler -rw------- 1 root root 10215 Jan 7 23:14 kube-scheduler.kubeconfig -rw-r--r-- 1 root root 281 Jan 7 23:38 kube-scheduler.service -rw-r--r-- 1 root root 191 Jan 7 23:38 kube-scheduler.yaml -rw-r--r-- 1 root root 2004 Jan 6 00:38 service-accounts.crt -rw------- 1 root root 3268 Jan 6 00:38 service-accounts.keyProvision the Kubernetes Control Plane : kubectl 확인
root@server:~# mkdir -p /etc/kubernetes/config root@server:~# mv kube-apiserver \ kube-controller-manager \ kube-scheduler kubectl \ /usr/local/bin/ root@server:~# ls -l /usr/local/bin/kube-* -rwxr-xr-x 1 root root 93261976 Jan 7 23:38 /usr/local/bin/kube-apiserver -rwxr-xr-x 1 root root 85987480 Jan 7 23:38 /usr/local/bin/kube-controller-manager -rwxr-xr-x 1 root root 65843352 Jan 7 23:38 /usr/local/bin/kube-scheduler # Configure the Kubernetes API Server 확인 root@server:~# mkdir -p /var/lib/kubernetes/ root@server:~# mv ca.crt ca.key \ kube-api-server.key kube-api-server.crt \ service-accounts.key service-accounts.crt \ encryption-config.yaml \ /var/lib/kubernetes/ root@server:~# ls -l /var/lib/kubernetes/ total 28 -rw-r--r-- 1 root root 1899 Jan 6 00:38 ca.crt -rw------- 1 root root 3272 Jan 6 00:38 ca.key -rw-r--r-- 1 root root 227 Jan 7 23:26 encryption-config.yaml -rw-r--r-- 1 root root 2354 Jan 6 00:38 kube-api-server.crt -rw------- 1 root root 3272 Jan 6 00:38 kube-api-server.key -rw-r--r-- 1 root root 2004 Jan 6 00:38 service-accounts.crt -rw------- 1 root root 3268 Jan 6 00:38 service-accounts.key #파일 이동및 실행 root@server:~# mv kube-controller-manager.kubeconfig /var/lib/kubernetes/ root@server:~# mv kube-controller-manager.service /etc/systemd/system/ root@server:~# mv kube-scheduler.kubeconfig /var/lib/kubernetes/ root@server:~# mv kube-scheduler.yaml /etc/kubernetes/config/ root@server:~# mv kube-scheduler.service /etc/systemd/system/ root@server:~# systemctl daemon-reload root@server:~# 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. root@server:~# systemctl start kube-apiserver kube-controller-manager kube-scheduler root@server:~# ss -tlp | grep kube LISTEN 0 4096 *:6443 *:* users:(("kube-apiserver",pid=4929,fd=3)) LISTEN 0 4096 *:10259 *:* users:(("kube-scheduler",pid=2752,fd=3)) LISTEN 0 4096 *:10257 *:* users:(("kube-controller",pid=2751,fd=3)) root@server:~# kubectl get clusterroles --kubeconfig admin.kubeconfig NAME CREATED AT admin 2026-01-07T15:07:34Z cluster-admin 2026-01-07T15:07:34Z edit 2026-01-07T15:07:34Z system:aggregate-to-admin 2026-01-07T15:07:34Z system:aggregate-to-edit 2026-01-07T15:07:34Z system:aggregate-to-view 2026-01-07T15:07:34Z system:auth-delegator 2026-01-07T15:07:34Z system:basic-user 2026-01-07T15:07:34Z system:certificates.k8s.io:certificatesigningrequests:nodeclient 2026-01-07T15:07:34Z system:certificates.k8s.io:certificatesigningrequests:selfnodeclient 2026-01-07T15:07:34Z system:certificates.k8s.io:kube-apiserver-client-approver 2026-01-07T15:07:34ZRBAC for Kubelet Authorization
root@server:~# cat kube-apiserver-to-kubelet.yaml 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: - "*"
root@server:~# kubectl get clusterroles system:kube-apiserver-to-kubelet --kubeconfig admin.kubeconfig
NAME CREATED AT
system:kube-apiserver-to-kubelet 2026-01-07T15:10:03Z
root@server:~# kubectl get clusterrolebindings system:kube-apiserver --kubeconfig admin.kubeconfig
NAME ROLE AGE
system:kube-apiserver ClusterRole/system:kube-apiserver-to-kubelet 18s
```
- jumpbox 서버에서 컨트롤플레인 확인
```bash
root@jumpbox:~/kubernetes-the-hard-way# curl -s -k --cacert ca.crt https://server.kubernetes.local:6443/version | jq
{
"major": "1",
"minor": "32",
"gitVersion": "v1.32.3",
"gitCommit": "32cc146f75aad04beaaa245a7157eb35063a9f99",
"gitTreeState": "clean",
"buildDate": "2025-03-11T19:52:21Z",
"goVersion": "go1.23.6",
"compiler": "gc",
"platform": "linux/amd64"
}
```09 - Bootstrapping the Kubernetes Worker Nodes
워커노드세팅을 위한 사전준비
root@jumpbox:~/kubernetes-the-hard-way# cat configs/10-bridge.conf | jq { "cniVersion": "1.0.0", "name": "bridge", "type": "bridge", "bridge": "cni0", "isGateway": true, "ipMasq": true, "ipam": { "type": "host-local", "ranges": [ [ { "subnet": "SUBNET" } ] ], "routes": [ { "dst": "0.0.0.0/0" } ] } } root@jumpbox:~/kubernetes-the-hard-way# cat configs/kubelet-config.yaml | yq { "kind": "KubeletConfiguration", "apiVersion": "kubelet.config.k8s.io/v1beta1", "address": "0.0.0.0", "authentication": { "anonymous": { "enabled": false }, "webhook": { "enabled": true }, #######중략############# #파일전달 root@jumpbox:~/kubernetes-the-hard-way# ssh node-0 ls -l /root ssh node-1 ls -l /root total 8 -rw-r--r-- 1 root root 265 Jan 8 00:18 10-bridge.conf -rw-r--r-- 1 root root 610 Jan 8 00:18 kubelet-config.yaml total 8 -rw-r--r-- 1 root root 265 Jan 8 00:18 10-bridge.conf -rw-r--r-- 1 root root 610 Jan 8 00:18 kubelet-config.yaml root@jumpbox:~/kubernetes-the-hard-way# cat configs/99-loopback.conf ; echo cat configs/containerd-config.toml ; echo cat configs/kube-proxy-config.yaml ; echo { "cniVersion": "1.1.0", "name": "lo", "type": "loopback" } version = 2 [plugins."io.containerd.grpc.v1.cri"] [plugins."io.containerd.grpc.v1.cri".containerd] snapshotter = "overlayfs" default_runtime_name = "runc" [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 [plugins."io.containerd.grpc.v1.cri".cni] bin_dir = "/opt/cni/bin" conf_dir = "/etc/cni/net.d" kind: KubeProxyConfiguration apiVersion: kubeproxy.config.k8s.io/v1alpha1 clientConnection: kubeconfig: "/var/lib/kube-proxy/kubeconfig" mode: "iptables" clusterCIDR: "10.200.0.0/16" #파일전송 및 확인 root@jumpbox:~/kubernetes-the-hard-way# ssh node-0 ls -l /root ssh node-1 ls -l /root ssh node-0 ls -l /root/cni-plugins ssh node-1 ls -l /root/cni-plugins total 358584 -rw-r--r-- 1 root root 265 Jan 8 00:18 10-bridge.conf -rw-r--r-- 1 root root 65 Jan 8 00:18 99-loopback.conf drwxr-xr-x 2 root root 4096 Jan 8 00:19 cni-plugins -rwxr-xr-x 1 root root 58584656 Jan 8 00:18 containerd -rw-r--r-- 1 root root 470 Jan 8 00:18 containerd-config.toml #########중략##########node0 세팅
root@jumpbox:~/kubernetes-the-hard-way# ssh root@node-0 root@node-0:~# mkdir -p \ /etc/cni/net.d \ /opt/cni/bin \ /var/lib/kubelet \ /var/lib/kube-proxy \ /var/lib/kubernetes \ /var/run/kubernetes root@node-0:~# mv 10-bridge.conf 99-loopback.conf /etc/cni/net.d/ cat /etc/cni/net.d/10-bridge.conf { "cniVersion": "1.0.0", "name": "bridge", "type": "bridge", "bridge": "cni0", "isGateway": true, "ipMasq": true, "ipam": { "type": "host-local", "ranges": [ [{"subnet": "10.200.0.0/24"}] ], "routes": [{"dst": "0.0.0.0/0"}] } }root@node-0:~#lsmod | grep netfilterr modprobe br-netfilter echo "br-netfilter" >> /etc/modules-load.d/modules.conf lsmod | grep netfilter br_netfilter 36864 0 bridge 319488 1 br_netfilter root@node-0:~# mkdir -p /etc/containerd/ mv containerd-config.toml /etc/containerd/config.toml mv containerd.service /etc/systemd/system/ cat /etc/containerd/config.toml ; echo version = 2 [plugins."io.containerd.grpc.v1.cri"] [plugins."io.containerd.grpc.v1.cri".containerd] snapshotter = "overlayfs" default_runtime_name = "runc" [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 [plugins."io.containerd.grpc.v1.cri".cni] bin_dir = "/opt/cni/bin" conf_dir = "/etc/cni/net.d" ###############중략############################ #node0세팅확인 root@jumpbox:~/kubernetes-the-hard-way# ssh server "kubectl get nodes -owide --kubeconfig admin.kubeconfig" NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME node-0 Ready <none> 19s v1.32.3 192.168.10.101 <none> Debian GNU/Linux 12 (bookworm) 6.1.0-40-amd64 containerd://2.1.0-beta.0node1 세팅(node0과 동일하기에 결과값만 반환하고 세팅 생략)
root@jumpbox:~/kubernetes-the-hard-way# ssh server "kubectl get nodes -owide --kubeconfig admin.kubeconfig" NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME node-0 Ready <none> 2m7s v1.32.3 192.168.10.101 <none> Debian GNU/Linux 12 (bookworm) 6.1.0-40-amd64 containerd://2.1.0-beta.0 node-1 Ready <none> 7s v1.32.3 192.168.10.102 <none> Debian GNU/Linux 12 (bookworm) 6.1.0-40-amd64 containerd://2.1.0-beta.0
10 - Configuring kubectl for Remote Access
jumpbox에 admin자격증명 세팅진행(kubectl사용)
root@jumpbox:~/kubernetes-the-hard-way# curl -s --cacert ca.crt https://server.kubernetes.local:6443/version | jq { "major": "1", "minor": "32", "gitVersion": "v1.32.3", "gitCommit": "32cc146f75aad04beaaa245a7157eb35063a9f99", "gitTreeState": "clean", "buildDate": "2025-03-11T19:52:21Z", "goVersion": "go1.23.6", "compiler": "gc", "platform": "linux/amd64" } root@jumpbox:~/kubernetes-the-hard-way# kubectl config set-cluster kubernetes-the-hard-way \ --certificate-authority=ca.crt \ --embed-certs=true \ --server=https://server.kubernetes.local:6443 Cluster "kubernetes-the-hard-way" set. root@jumpbox:~/kubernetes-the-hard-way# kubectl config set-credentials admin \ --client-certificate=admin.crt \ --client-key=admin.key User "admin" set. root@jumpbox:~/kubernetes-the-hard-way# kubectl config set-credentials admin \ --client-certificate=admin.crt \ --client-key=admin.key User "admin" set. root@jumpbox:~/kubernetes-the-hard-way# kubectl config set-context kubernetes-the-hard-way \ --cluster=kubernetes-the-hard-way \ --user=admin Context "kubernetes-the-hard-way" created. root@jumpbox:~/kubernetes-the-hard-way# kubectl config use-context kubernetes-the-hard-way Switched to context "kubernetes-the-hard-way". root@jumpbox:~/kubernetes-the-hard-way# kubectl version Client Version: v1.32.3 Kustomize Version: v5.5.0 Server Version: v1.32.3
11 - Provisioning Pod Network Routes
node-0/1 pod간 통신을 위한 라우팅 수동설정진행
root@jumpbox:~/kubernetes-the-hard-way# SERVER_IP=$(grep server machines.txt | cut -d " " -f 1) NODE_0_IP=$(grep node-0 machines.txt | cut -d " " -f 1) NODE_0_SUBNET=$(grep node-0 machines.txt | cut -d " " -f 4) NODE_1_IP=$(grep node-1 machines.txt | cut -d " " -f 1) NODE_1_SUBNET=$(grep node-1 machines.txt | cut -d " " -f 4) echo $SERVER_IP $NODE_0_IP $NODE_0_SUBNET $NODE_1_IP $NODE_1_SUBNET 192.168.10.100 192.168.10.101 10.200.0.0/24 192.168.10.102 10.200.1.0/24 root@jumpbox:~/kubernetes-the-hard-way# ssh server ip -c route default via 10.0.2.2 dev eth0 10.0.2.0/24 dev eth0 proto kernel scope link src 10.0.2.15 192.168.10.0/24 dev eth1 proto kernel scope link src 192.168.10.100
12 - Smoke Test
Data encryption
root@jumpbox:~/kubernetes-the-hard-way# kubectl create secret generic kubernetes-the-hard-way --from-literal="mykey=mydata" secret/kubernetes-the-hard-way created #정상 적용 확인 root@jumpbox:~/kubernetes-the-hard-way# kubectl get secret kubernetes-the-hard-way -o jsonpath='{.data.mykey}' ; echo bXlkYXRh root@jumpbox:~/kubernetes-the-hard-way# ssh root@server \ 'etcdctl get /registry/secrets/default/kubernetes-the-hard-way | hexdump -C' 00000000 2f 72 65 67 69 73 74 72 79 2f 73 65 63 72 65 74 |/registry/secret| 00000010 73 2f 64 65 66 61 75 6c 74 2f 6b 75 62 65 72 6e |s/default/kubern| 00000020 65 74 65 73 2d 74 68 65 2d 68 61 72 64 2d 77 61 |etes-the-hard-wa| 00000030 79 0a 6b 38 73 3a 65 6e 63 3a 61 65 73 63 62 63 |y.k8s:enc:aescbc| 00000040 3a 76 31 3a 6b 65 79 31 3a 96 7c 14 e2 52 45 50 |:v1:key1:.|..REP| 00000050 f0 6a a5 66 a0 ac 73 62 d2 d4 63 e0 96 7a d5 55 |.j.f..sb..c..z.U| 00000060 ff a5 3d 3f 47 fc 53 c7 f3 90 de c2 bb e4 ae 60 |..=?G.S........`| 00000070 d0 0f 1e 34 a5 a0 59 11 d4 f2 8a 32 21 85 5f f5 |...4..Y....2!._.| 00000080 1c 01 f5 58 96 dc e1 cc e4 1a 47 c7 48 26 f6 53 |...X......G.H&.S| 00000090 b0 12 b4 8e f5 eb 8a 01 c6 a7 7c 67 78 57 9c e0 |..........|gxW..| 000000a0 a1 06 84 67 8c 57 c4 a0 23 1c 6a d0 a2 62 8b 78 |...g.W..#.j..b.x| 000000b0 8c dc fe 68 60 f8 8d 38 14 90 46 97 bc ae 4d d5 |...h`..8..F...M.| 000000c0 37 76 8f a9 fd 74 b8 85 f0 09 8d d7 0c 61 3e e3 |7v...t.......a>.| 000000d0 04 1a a8 99 80 15 45 7d a5 41 b7 75 54 a6 e0 dc |......E}.A.uT...| 000000e0 0e 57 ae e7 3b 8b bd 1b 43 25 39 2e 04 4b 90 be |.W..;...C%9..K..| 000000f0 ab 3d d2 0c e7 9c 97 cf 2d 3d 2f 91 b9 f3 05 f6 |.=......-=/.....| 00000100 3f 47 93 3a a8 dd e3 54 55 15 42 8a 39 45 cb 2b |?G.:...TU.B.9E.+| 00000110 c3 cb 2d bf df 5f 2b c4 12 58 38 11 73 6a c6 f8 |..-.._+..X8.sj..| 00000120 f7 97 1b bd d3 e3 95 e1 f5 ef d1 fb 5e 4b 1b ab |............^K..| 00000130 36 22 7c 3d d0 e8 80 b4 4d 85 20 05 9f d4 c2 10 |6"|=....M. .....| 00000140 96 23 c0 88 e3 a1 22 f7 61 cd 70 00 86 18 5c 24 |.#....".a.p...\$| 00000150 9a a4 14 e3 4b 39 39 57 ee 0a |....K99W..| 0000015aDeployments , Port Forwarding , Log, Exec, Service(NodePort)
root@jumpbox:~/kubernetes-the-hard-way# kubectl get pod kubectl create deployment nginx --image=nginx:latest kubectl scale deployment nginx --replicas=2 kubectl get pod -owide No resources found in default namespace. deployment.apps/nginx created deployment.apps/nginx scaled NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-54c98b4f84-dkn2w 0/1 ContainerCreating 0 0s <none> node-1 <none> <none> nginx-54c98b4f84-kws4j 0/1 ContainerCreating 0 0s <none> node-0 <none> <none> root@jumpbox:~/kubernetes-the-hard-way# kubectl get pod -owide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-54c98b4f84-dkn2w 1/1 Running 0 44s 10.200.1.2 node-1 <none> <none> nginx-54c98b4f84-kws4j 1/1 Running 0 44s 10.200.0.2 node-0 <none> <none> # server 노드에서 파드 IP로 호출 확인 root@jumpbox:~/kubernetes-the-hard-way# ssh server curl -s 10.200.1.2 | grep title <title>Welcome to nginx!</title> root@jumpbox:~/kubernetes-the-hard-way# ssh server curl -s 10.200.0.2 | grep title <title>Welcome to nginx!</title> root@jumpbox:~/kubernetes-the-hard-way# echo $POD_NAME nginx-54c98b4f84-dkn2w root@jumpbox:~/kubernetes-the-hard-way# kubectl port-forward $POD_NAME 8080:80 & [1] 3130 root@jumpbox:~/kubernetes-the-hard-way# Forwarding from 127.0.0.1:8080 -> 80 Forwarding from [::1]:8080 -> 80실습 환경 정리
C:\Users\bom\Desktop\스터디\onpremisk8s>vagrant destroy -f ==> node-1: Forcing shutdown of VM... ==> node-1: Destroying VM and associated drives... ==> node-0: Forcing shutdown of VM... ==> node-0: Destroying VM and associated drives... ==> server: Forcing shutdown of VM... ==> server: Destroying VM and associated drives... ==> jumpbox: Forcing shutdown of VM... ==> jumpbox: Destroying VM and associated drives... C:\Users\bom\Desktop\스터디\onpremisk8s>rmdir /s /q .vagrant
'Study > K8S-Deploy' 카테고리의 다른 글
| K8S)2주차 과제 (0) | 2026.01.15 |
|---|