Node and Cluster
学习参考:Node
查看节点
bash
# 查看节点清单
[root@master30 ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master30.song.cloud Ready control-plane 37h v1.30.2
worker31.song.cloud Ready <none> 36h v1.30.2
worker32.song.cloud Ready <none> 36h v1.30.2
# 查看特定节点详细信息
[root@master30 ~]# kubectl describe node worker31.song.cloud
删除节点
以 worker31 节点为例。
bash
# 设置节点为维护模式
[root@master30 ~]# kubectl drain worker31.song.cloud --ignore-daemonsets
node/worker31.song.cloud cordoned
Warning: ignoring DaemonSet-managed Pods: kube-system/calico-node-v8jdn, kube-system/kube-proxy-27vl2
evicting pod kube-system/calico-kube-controllers-7cb4fd5784-jx2xl
pod/calico-kube-controllers-7cb4fd5784-jx2xl evicted
node/worker31.song.cloud drained
[root@master30 ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master30.song.cloud Ready control-plane 41h v1.30.2
worker31.song.cloud Ready,SchedulingDisabled <none> 41h v1.30.2
worker32.song.cloud Ready <none> 41h v1.30.2
# 删除 worker31 节点
[root@master30 ~]# kubectl delete node worker31.song.cloud
node "worker31.song.cloud" deleted
[root@master30 ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master30.song.cloud Ready control-plane 41h v1.30.2
worker32.song.cloud Ready <none> 41h v1.30.2
# 重置删除的 worker31 节点
[root@worker31 ~]# kubeadm reset -f
[preflight] Running pre-flight checks
W1019 07:37:44.242023 7660 removeetcdmember.go:106] [reset] No kubeadm config, using etcd pod spec to get data directory
[reset] Deleted contents of the etcd data directory: /var/lib/etcd
[reset] Stopping the kubelet service
[reset] Unmounting mounted directories in "/var/lib/kubelet"
[reset] Deleting contents of directories: [/etc/kubernetes/manifests /var/lib/kubelet /etc/kubernetes/pki]
[reset] Deleting files: [/etc/kubernetes/admin.conf /etc/kubernetes/kubelet.conf /etc/kubernetes/bootstrap-kubelet.conf /etc/kubernetes/controller-manager.conf /etc/kubernetes/scheduler.conf]
The reset process does not clean CNI configuration. To do so, you must remove /etc/cni/net.d
The reset process does not reset or clean up iptables rules or IPVS tables.
If you wish to reset iptables, you must do so manually by using the "iptables" command.
If your cluster was setup to utilize IPVS, run ipvsadm --clear (or similar)
to reset your system's IPVS tables.
The reset process does not clean your kubeconfig files and you must remove them manually.
Please, check the contents of the $HOME/.kube/config file.
删除集群
删除集群流程:
- 删除所有 node
- 删除所有 master
具体步骤:
- 删除所有node节点
bash
[root@master30 ~]# kubectl drain worker31.song.cloud --ignore-daemonsets --force
[root@master30 ~]# kubectl drain worker32.song.cloud --ignore-daemonsets --force
[root@master30 ~]# kubectl delete node worker31.song.cloud worker32.song.cloud
# 重置节点,注意执行位置
[root@worker31 ~]# kubeadm reset -f
[root@worker32 ~]# kubeadm reset -f
- 删除master节点
bash
# 删除集群前获取集群配置
[root@master30 ~]# kubectl get cm kubeadm-config -n kube-system -o yaml > kubeadm.yml
# 修改kubeadm.yml内容如下:
[root@master30 ~]# vim kubeadm.yml
# 删除1-3和22-28行,效果如下
apiServer:
timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta3
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controllerManager: {}
dns: {}
etcd:
local:
dataDir: /var/lib/etcd
imageRepository: registry.k8s.io
kind: ClusterConfiguration
kubernetesVersion: v1.30.2
networking:
dnsDomain: cluster.local
podSubnet: 10.224.0.0/16
serviceSubnet: 10.96.0.0/12
scheduler: {}
[root@master30 ~]# kubectl delete node master30.song.cloud
[root@master30 ~]# kubeadm reset -f
[root@master30 ~]# rm -fr .kube/
重建集群
bash
# 初始化集群
[root@master30 ~]# kubeadm init --config kubeadm.yml
# 也可以使用之前的命令
[root@master30 ~]# kubeadm init --kubernetes-version=v1.30.2 --pod-network-cidr=10.224.0.0/16
# 配置凭据
[root@master30 ~]# mkdir -p $HOME/.kube
[root@master30 ~]# sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
[root@master30 ~]# sudo chown $(id -u):$(id -g) $HOME/.kube/config
# 配置网络
[root@master30 ~]# kubectl apply -f calico.yaml
# 加入集群
[root@worker31 ~]# kubeadm join 10.1.8.30:6443 --token ky95b9.sjg0fn21pdi1m0xz --discovery-token-ca-cert-hash sha256xxxxxxx
[root@worker32 ~]# kubeadm join 10.1.8.30:6443 --token ky95b9.sjg0fn21pdi1m0xz --discovery-token-ca-cert-hash sha256xxxxxxx
Namespace and Contexts
学习参考:Namespace
Namespace 介绍
**问题:**多个用户使用同一个Kubernetes Cluster, 如何将他们创建的资源隔离开呢?
答案:Namespace ,简写ns,也称之为 project,代表资源集合,用于分组集群资源。Kubernetes 使用 Namespace 可以将一个物理的 Cluster 逻辑上划分成多个资源集合, 每个集合就是一个Namespace。 不同Namespace 里的资源是完全隔离的。
Kubernetes 默认创建以下Namespace:
- default: 创建资源时如果不指定Namespace, 将被放到这个Namespace中。
- kube-system: Kubernetes 自己创建的系统资源将放到这个Namespace中。
- kube-public:该命名空间中所有对象可以被所有用户(包括未验证身份的用户)读取。
- kube-node-lease:该命名空间含有与每个节点关联的Lease对象。节点租用允许kubelet发送heartbeat(心跳),以便控制平面能检测节点故障。
思考:所有对象都属于 Namespace 吗?
**答:**大多数Kubernetes资源(例如 pod、services、pvc等)都属于某个Namespace,但 Namespace 资源本身并不在 Namespace 中,更低级别资源(如Node和persistentVolumes)也不在任何Namespace中。
Namespace 管理
bash
# 查看Namespace清单
[root@master30 ~]# kubectl get ns
NAME STATUS AGE
default Active 7d4h
kube-node-lease Active 7d4h
kube-public Active 7d4h
kube-system Active 7d4h
# 获取Namespace资源yaml格式定义文件
[root@master30 ~]# kubectl get ns default -o yaml
# 创建Namespace
[root@master30 ~]# kubectl create ns song
# 注意:命名空间名称满足正则表达式[a-z0-9]([-a-z0-9]*[a-z0-9])?,最大长度为63位
# 直接编辑Namespace
[root@master30 ~]# kubectl edit ns song
# 查看Namespace详细信息
[root@master30 ~]# kubectl describe ns song
Name: song
Labels: <none>
Annotations: <none>
Status: Active
No resource quota.
No LimitRange resource.
# 删除Namespace
[root@master30 ~]# kubectl delete ns song
namespace "song" deleted
# 注意:
# 删除一个namespace会自动删除该namespace中所有资源。
# default和kube-system命名空间不可删除。
Namespace 还可以通过 yaml 文件创建。
yaml
# ns-song.yaml
apiVersion: v1
kind: Namespace
metadata:
name: song
bash
[root@master30 ~]# kubectl apply -f ns-song.yaml
namespace/song created
操作特定ns中对象,需要使用选项-n指定ns,例如:
bash
[root@master30 ~]# kubectl run web --image=nginx -n song
pod/web created
[root@master30 ~]# kubectl get pod -n song -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web 1/1 Running 0 39s 10.224.113.129 worker32.song.cloud <none> <none>
[root@master30 ~]# curl -s 10.224.113.129 | grep nginx
<title>Welcome to nginx!</title>
<h1>Welcome to nginx!</h1>
<p>If you see this page, nginx is successfully installed and working.
<a href="https://nginx.org/">nginx.org</a>.<br/>
<a href="https://community.nginx.org/">community.nginx.org</a>.<br/>
<a href="https://f5.com/nginx">f5.com/nginx</a>.</p>
<p><em>Thank you for using nginx.</em></p>
Namespace 切换
kubectl
查看当前所在ns
bash
[root@master30 ~]# kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
* kubernetes-admin@kubernetes kubernetes kubernetes-admin
此时NAMESPACE列对应的属性为空,不属于任何NAMESPACE。
设置默认ns
bash
[root@master30 ~]# kubectl config set-context --current --namespace=song
Context "kubernetes-admin@kubernetes" modified.
[root@master30 ~]# kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
* kubernetes-admin@kubernetes kubernetes kubernetes-admin song
此时,NAMESPACE 列对应的属性为 song。
kubens
kubens 安装
bash
[root@master30 ~]# wget https://codeload.github.com/ahmetb/kubectx/zip/refs/heads/master -O kubectx.zip
[root@master30 ~]# unzip kubectx.zip
[root@master30 ~]# ls kubectx-master/
CONTRIBUTING.md README.md completion go.sum internal kubens
LICENSE cmd go.mod img kubectx test
[root@master30 ~]# cp kubectx-master/kubens /usr/local/bin/
[root@master30 ~]# chmod +x /usr/local/bin/kubens
# 配置补全
[root@master30 ~]# cp kubectx-master/completion/kubens.bash /etc/bash_completion.d/
[root@master30 ~]# source /etc/bash_completion.d/kubens.bash
kubens 命令使用
bash
[root@master30 ~]# kubens -h
USAGE:
kubens : list the namespaces in the current context
kubens <NAME> : change the active namespace of current context
kubens - : switch to the previous namespace in this context
kubens -c, --current : show the current namespace
kubens -h,--help : show this message
[root@master30 ~]# kubens
default
kube-node-lease
kube-public
kube-system
song
[root@master30 ~]# kubens kube-system
[root@master30 ~]# kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
* kubernetes-admin@kubernetes kubernetes kubernetes-admin kube-syste
[root@master30 ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
calico-kube-controllers-7cb4fd5784-dqv6n 1/1 Running 0 19m
calico-node-5k2bp 1/1 Running 0 18m
calico-node-6vpt6 1/1 Running 0 19m
calico-node-7x82d 1/1 Running 0 19m
coredns-66f779496c-h89xx 1/1 Running 0 19m
coredns-66f779496c-zqqxd 1/1 Running 0 19m
etcd-master30.song.cloud 1/1 Running 2 19m
kube-apiserver-master30.song.cloud 1/1 Running 2 19m
kube-controller-manager-master30.song.cloud 1/1 Running 2 19m
kube-proxy-7l9pr 1/1 Running 0 19m
kube-proxy-9djwp 1/1 Running 0 19m
kube-proxy-n2bk9 1/1 Running 0 18m
kube-scheduler-master30.song.cloud 1/1 Running 2 19m
自定义脚本
bash
#!/bin/bash
function usage(){
echo "$0 [namespace]
1. 没有namespace参数时,显示namespace清单
2. namespace必须是集群中存在的namespace"
}
# 获取当前namespace
namespace=$(kubectl config get-contexts | awk '/\*/{print $5}')
if [ -z "$namespace" ];then
namespace=default
fi
# 显示 namespace清单
if [ $# -eq 0 ];then
kubectl get ns | awk '{print " "$1}' | sed "s/^ $namespace/\* $namespace/"
exit 1
fi
# 切换 namespace
if [ $# -eq 1 ];then
if kubectl get ns | awk '$1 !~ "NAME" {print $1}' | grep -qx "$1" &>/dev/null;then
kubectl config set-context --current --namespace $1 > /dev/null
echo "当前namespace设置为:$1"
else
usage
fi
fi
Cluster 切换
~/.kube/config 详解
单集群配置
获取凭据文件内容(不显示敏感信息):
bash
[root@master30 ~]# kubectl config view
yaml
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: DATA+OMITTED
server: https://10.1.8.30:6443
name: kubernetes
contexts:
- context:
cluster: kubernetes
namespace: kube-system
user: kubernetes-admin
name: kubernetes-admin@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-admin
user:
client-certificate-data: DATA+OMITTED
client-key-data: DATA+OMITTED
配置文件示例:
yaml
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMvakNDQWVhZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRJeU1EUXdNakExTURZd05Wb1hEVE15TURNek1EQTFNRFl3TlZvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTHg5ClZnNGUyR3dUTkVUaUowTjBqV09hZ2NvQVRnclFzVXVjWU1Jb281YWFZZGtTZGY2amdJanhTeEtNTmZyL3MrQWQKems5S25CL2UwS0ZxSEJwOEhsQy9VZ0JTK1V2THl6b2VuWVNFM29MWmJzdDhwY1JXL0ZWQVdQckRkS1VhcTdJcApyVXpvQlRTSHRHSEluNitLR1htZ3BwWkdLK3pRT2pjTWYyT2IxOGZ0NDZDbXNFT24rMmhKZk13eHBUd3k0dEgvCktteWhnVStYUys1c0Z5L0N2R1gwbUEzbWpzeHZ4VnFmamQ0T2F0RVVhamN5aERVc3FxRVVBUmNWZGdpbkhUc2IKdWVhc3NieUFZSGRJWGFiMjQvVzg0ZXpDYk8vMGhvcHhZZFhGVDYxQVc3R2RNL0IvNlYyU0hDWUFCd2FKU1dmNApZWHFpajJoMndUNDdYZHZscHNzQ0F3RUFBYU5aTUZjd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0hRWURWUjBPQkJZRUZLWlJpc2FLS1c4YjFFcUlHeHhTcTkrdUdEWFNNQlVHQTFVZEVRUU8KTUF5Q0NtdDFZbVZ5Ym1WMFpYTXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBRjhHSjI1c1RqVEd3RDRoSDVmegp5bXU2WGhSd212ejBzemNKUTVKVVlsSndpUlJ0NUVBZ2lNUHZ0MndIeGt1UExGWDAwRFZ2MWorQkEzaEt5Wk5GClVaQUdrRmVwK0JyOWZYUWxVSE15OHZTZjFZSVhBRk43MFdBT0dFdVZjWEJDeDFNbWlBTndObUQyck1LdmFJK1cKci80Y1hMdXdVZlNUaUZaeFpaVGdaRkFtSFJ0QnVvSmpoaStmQjRPT2xTRFNEMU9PaFZjVVc3bWo3YkhJUjN1cgpzRnFYakp5eEc0T0JadlM5MTBXMUNtYTJWUTFCYnprY1h0YzJZOUdDSS9Cd3h2a0labWFSYy9ETFY1M0YxSmxXCnluNmovZEpvdmd6SGZqaVhheUxoekpaUDhMaG9ULzFacFQ2K214Uml0SHVMM2RVRW9oL2ttSzZqclBjZlFUWlMKTnRrPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
server: https://10.1.8.30:6443
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: kubernetes-admin
name: kubernetes-admin@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-admin
user:
client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURJVENDQWdtZ0F3SUJBZ0lJYm9pOWR1alB4dEF3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB5TWpBME1ESXdOVEEyTURWYUZ3MHlNekEwTURJd05UQTJNRGRhTURReApGekFWQmdOVkJBb1REbk41YzNSbGJUcHRZWE4wWlhKek1Sa3dGd1lEVlFRREV4QnJkV0psY201bGRHVnpMV0ZrCmJXbHVNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXhSbWh6MkpjWG83RmNIb1QKQ0d6dHkyRGplM1FvYVl1djVMMmV2V3NpMk14SmZRLzVnRWg4cDdXZEdTQ0NDL0t5a2Fvbk9ZWFh3MkxEVi9yVQpkbEtNbUtTN2s1eG5WWWV1M0EyZGlCMTU1MVVFK0lTelVPTE54c3J0MjdVajRuMDliUU5kSzhjeEZvclhxVUV0ClppVTdHY0dOZ3hRUVA4MkhGSDdTb09RTXRtTmo0bXdMWHVZbEFWODZ5TXl5RThQYjF5Y0FoQjhVY1BFUmRUeWQKeEtUY3FVbG0xYnQ4cU1CRzlYWUZFNk1IUUpldXk0Rnk3NjlYL2ZJNk9SZCtuUGdVWHVVd0FUYVdYR2JIeWhoUApDS0dKWXdzY09PRUFmWnRWV3RYUkxiM1pEWWpiVmFqTzllT0ZHYnorcjRxVDR2NEpkL1dZZ1RLcmUvTDBzVlhRCkROZWZDd0lEQVFBQm8xWXdWREFPQmdOVkhROEJBZjhFQkFNQ0JhQXdFd1lEVlIwbEJBd3dDZ1lJS3dZQkJRVUgKQXdJd0RBWURWUjBUQVFIL0JBSXdBREFmQmdOVkhTTUVHREFXZ0JTbVVZckdpaWx2RzlSS2lCc2NVcXZmcmhnMQowakFOQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBckt4cjhFbEtYN2FYWUMvdzZhUFg4M3JvRHl0Q0NudTBTMHpWCm5WTVFnMUsvUmhRSGV5TnY2SGtycTJXSFhoUjh1L2M3Ukw3WGwyeDlzcWhPWmR3cGRrUlBXK0RENEs4TFMwYjAKUnhwdGxraW44UFE5QkZEOExuNDlmdmNhRG9LT0lhV2djZFFVMFRKQVZoZ1RNQ3FZZ0ZNTUhQa3I2d2Q2WVFtMgp3KzhsVlNCNytmeERKVlhkeUZWMFdOdk5Jb1JrM0FCcGEyOVVVZlZoY1FnZGI2M1RFamgwUlI0d014bjhhY2E1CnNiaE1wVmZiT2ZUU0pRTUJGRkRkMG5DWnJSN3NxQWluOUE2M3RydWZLTzJMTEF0YUVJeDRMUzJWZ09veG5odWEKQlh6UGp4SHF5TTR1WFRqQVlOMk44K2wxWXRBeSs0VTg2ZzVEMEZZeUpSTE5NMU5VL2c9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0NBUUVBeFJtaHoySmNYbzdGY0hvVENHenR5MkRqZTNRb2FZdXY1TDJldldzaTJNeEpmUS81CmdFaDhwN1dkR1NDQ0MvS3lrYW9uT1lYWHcyTERWL3JVZGxLTW1LUzdrNXhuVllldTNBMmRpQjE1NTFVRStJU3oKVU9MTnhzcnQyN1VqNG4wOWJRTmRLOGN4Rm9yWHFVRXRaaVU3R2NHTmd4UVFQODJIRkg3U29PUU10bU5qNG13TApYdVlsQVY4NnlNeXlFOFBiMXljQWhCOFVjUEVSZFR5ZHhLVGNxVWxtMWJ0OHFNQkc5WFlGRTZNSFFKZXV5NEZ5Cjc2OVgvZkk2T1JkK25QZ1VYdVV3QVRhV1hHYkh5aGhQQ0tHSll3c2NPT0VBZlp0Vld0WFJMYjNaRFlqYlZhak8KOWVPRkdieityNHFUNHY0SmQvV1lnVEtyZS9MMHNWWFFETmVmQ3dJREFRQUJBb0lCQUNkS0hMOUNWRGRsTG1abApielhXd1BBeHVDYjcyTEp4YmZhaTllbThXWTN0NnhoSy91bGJpYjNFcmpROERyQmpDTVdRclpFQjVTakZuenNDCmZTZTQvTjNRdUxPTUVlMHl4dUNHdGtoVDErRU5TWmhnbTM0Y04valFxdW1KQ2tZendQTGlJTWlCUkgvQjNZdVgKdW4wS0h1WGJkMklSdGN1Q0pOTXBGTU9Oc2hzSkMyRTI1cmhXazlZZFdKTVVQV2JjMGZUd0RDdHhVSXpRNWhycApOa0tGenpBekdiVFA2dXA2dWJrYzQ4Zm9BNDVTRUJLNkhhcFZBNEQ1NzNQNFNmZWRodmhMVG9lbmQzM3NmeTJYCjlkS1dFOUg4VUQ3VGFRc3N6MG8xSU1xK0xVVU5UNUVqRkVCOXVtemIxTHB4YW1wUFJqVVpXU2ZEcXJDbGlvMkUKWHFaWkd3RUNnWUVBMm5Tbmd2R0p2NUZhdFVQeGppbWMyNHhOWjZSTWhRRFc3OG9TRUYrUUVoV2RscGlwTk94QQpVNTJNY1NrSmNMR1Jkd3VIaWdjQXVWVW90N09sak9MU1Zzak4yN0xRQTFraTNXbjYxeWVKUSs5MVpZMW9GaUJQCmpBZWJoS1BJanFPT2p3YUsrMEJ5cGFJb2dTb215dzErNklrSE5kNmJkc2FQbG1aMU9wc0hjRHNDZ1lFQTV2bG0KOGNvUUlEWWx5Q0x3YzMzSWRHd0xsWU9KUmFNdCs5QXRNY1VaZGZZN2gvaUlWTE4wSEZkUUFkOWxLUUxyNlpZVApuS0lWcUdzU1BiM2kyMCsyZHNVN3VPUjNOVkZCeHcvZUVVM1FnTjFtVTRnZzBLNnpORUpkKzZaYVo2cUQyVVhRCnY3cTdiOHhzekJoUkNMakdjb1huL2ZnWFBIWmRDUE9VVUVIWTczRUNnWUVBek1RSHVDK2JoSnRFd1IvY3JmckgKY3V1Q0txSFFyK0xubFlCOWlpZHBMZXBnK3FaQ0JMOW1WSG9iQ0g4RXdFTlJMSnI4QXg4cFNJOVFTVkQwM3FoRgpyTjh3UnJ6SFNqd2srQkc4OUN1MCtKN2VGY0NFVGlrZkp3eUNjOFBwMi9ublNKMURiTnN1RzU5eUJCQjBxR1FRCkR2dFNiT1lxSngxYnZnaHYzZTB1L2IwQ2dZRUF4NHc1TURQT2NzWFZKbTlwSlo1S0RLczc1dFJaU0Z5T1lidWQKRUI2a3ZKRWJKWUhHNXNhVFRkanhPbXp5VE5oRlVPMWp6RE1NV3hFR0ZXbDBFTjF4V25OVUFZMEFvSU92UEhlcwo5MjR1OE9aV2ZWeGlYV2hSVXBqejhYSHJNUnpVQkdhWXpzeFpHMkdWclU1azFCQXZBc3BGZjlsUzJkMjR5djhGCjU4QzcxMEVDZ1lBV0p4NmpuV05vbGc1QzhvSGpDT0Jkb0RGdHhGeEpiT2M5QUJ2aHpZbGlTSHp5aTY3RjVQZ28KREdaWXJjWWZxYVY5MVl5R24xaWQybG5GcVZoZ1VGYnpGS2t4U0FaS0FJVDRwbGNucVRWQm9oc1UwMkxqSUdEZwpESU5SQW8xb0dqRTdOM3FWUVFzS0huSDBnUXNwWVZpN3NFRzRDdWtZSDQ2MUNCM0dET0N0b3c9PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=
说明:
- certificate-authority-data 指定CA证书,通过base64编码。
bash
[root@master30 ~]# echo LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURJVENDQWdtZ0F3SUJBZ0lJYm9pOWR1alB4dEF3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB5TWpBME1ESXdOVEEyTURWYUZ3MHlNekEwTURJd05UQTJNRGRhTURReApGekFWQmdOVkJBb1REbk41YzNSbGJUcHRZWE4wWlhKek1Sa3dGd1lEVlFRREV4QnJkV0psY201bGRHVnpMV0ZrCmJXbHVNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXhSbWh6MkpjWG83RmNIb1QKQ0d6dHkyRGplM1FvYVl1djVMMmV2V3NpMk14SmZRLzVnRWg4cDdXZEdTQ0NDL0t5a2Fvbk9ZWFh3MkxEVi9yVQpkbEtNbUtTN2s1eG5WWWV1M0EyZGlCMTU1MVVFK0lTelVPTE54c3J0MjdVajRuMDliUU5kSzhjeEZvclhxVUV0ClppVTdHY0dOZ3hRUVA4MkhGSDdTb09RTXRtTmo0bXdMWHVZbEFWODZ5TXl5RThQYjF5Y0FoQjhVY1BFUmRUeWQKeEtUY3FVbG0xYnQ4cU1CRzlYWUZFNk1IUUpldXk0Rnk3NjlYL2ZJNk9SZCtuUGdVWHVVd0FUYVdYR2JIeWhoUApDS0dKWXdzY09PRUFmWnRWV3RYUkxiM1pEWWpiVmFqTzllT0ZHYnorcjRxVDR2NEpkL1dZZ1RLcmUvTDBzVlhRCkROZWZDd0lEQVFBQm8xWXdWREFPQmdOVkhROEJBZjhFQkFNQ0JhQXdFd1lEVlIwbEJBd3dDZ1lJS3dZQkJRVUgKQXdJd0RBWURWUjBUQVFIL0JBSXdBREFmQmdOVkhTTUVHREFXZ0JTbVVZckdpaWx2RzlSS2lCc2NVcXZmcmhnMQowakFOQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBckt4cjhFbEtYN2FYWUMvdzZhUFg4M3JvRHl0Q0NudTBTMHpWCm5WTVFnMUsvUmhRSGV5TnY2SGtycTJXSFhoUjh1L2M3Ukw3WGwyeDlzcWhPWmR3cGRrUlBXK0RENEs4TFMwYjAKUnhwdGxraW44UFE5QkZEOExuNDlmdmNhRG9LT0lhV2djZFFVMFRKQVZoZ1RNQ3FZZ0ZNTUhQa3I2d2Q2WVFtMgp3KzhsVlNCNytmeERKVlhkeUZWMFdOdk5Jb1JrM0FCcGEyOVVVZlZoY1FnZGI2M1RFamgwUlI0d014bjhhY2E1CnNiaE1wVmZiT2ZUU0pRTUJGRkRkMG5DWnJSN3NxQWluOUE2M3RydWZLTzJMTEF0YUVJeDRMUzJWZ09veG5odWEKQlh6UGp4SHF5TTR1WFRqQVlOMk44K2wxWXRBeSs0VTg2ZzVEMEZZeUpSTE5NMU5VL2c9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== | base64 -d
-----BEGIN CERTIFICATE-----
MIIDITCCAgmgAwIBAgIIboi9dujPxtAwDQYJKoZIhvcNAQELBQAwFTETMBEGA1UE
AxMKa3ViZXJuZXRlczAeFw0yMjA0MDIwNTA2MDVaFw0yMzA0MDIwNTA2MDdaMDQx
FzAVBgNVBAoTDnN5c3RlbTptYXN0ZXJzMRkwFwYDVQQDExBrdWJlcm5ldGVzLWFk
bWluMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxRmhz2JcXo7FcHoT
CGzty2Dje3QoaYuv5L2evWsi2MxJfQ/5gEh8p7WdGSCCC/KykaonOYXXw2LDV/rU
dlKMmKS7k5xnVYeu3A2diB1551UE+ISzUOLNxsrt27Uj4n09bQNdK8cxForXqUEt
ZiU7GcGNgxQQP82HFH7SoOQMtmNj4mwLXuYlAV86yMyyE8Pb1ycAhB8UcPERdTyd
xKTcqUlm1bt8qMBG9XYFE6MHQJeuy4Fy769X/fI6ORd+nPgUXuUwATaWXGbHyhhP
CKGJYwscOOEAfZtVWtXRLb3ZDYjbVajO9eOFGbz+r4qT4v4Jd/WYgTKre/L0sVXQ
DNefCwIDAQABo1YwVDAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUH
AwIwDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBSmUYrGiilvG9RKiBscUqvfrhg1
0jANBgkqhkiG9w0BAQsFAAOCAQEArKxr8ElKX7aXYC/w6aPX83roDytCCnu0S0zV
nVMQg1K/RhQHeyNv6Hkrq2WHXhR8u/c7RL7Xl2x9sqhOZdwpdkRPW+DD4K8LS0b0
Rxptlkin8PQ9BFD8Ln49fvcaDoKOIaWgcdQU0TJAVhgTMCqYgFMMHPkr6wd6YQm2
w+8lVSB7+fxDJVXdyFV0WNvNIoRk3ABpa29UUfVhcQgdb63TEjh0RR4wMxn8aca5
sbhMpVfbOfTSJQMBFFDd0nCZrR7sqAin9A63trufKO2LLAtaEIx4LS2VgOoxnhua
BXzPjxHqyM4uXTjAYN2N8+l1YtAy+4U86g5D0FYyJRLNM1NU/g==
-----END CERTIFICATE-----
- client-certificate-data 指定用户证书,同样是 base64 编码。
- client-key-data 指定用户私钥,同样是 base64 编码。
bash
# 或者使用以下命令获取不显示具体证书和key内容
[root@master30 ~]# kubectl config view
yaml
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: DATA+OMITTED
server: https://10.1.8.30:6443
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: kubernetes-admin
name: kubernetes-admin@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-admin
user:
client-certificate-data: REDACTED
client-key-data: REDACTED
多集群配置
示例:/root/multi-cluster-config
yaml
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: DATA+OMITTED
server: https://10.1.8.30:6443
name: cluster1
- cluster:
certificate-authority-data: DATA+OMITTED
server: https://10.1.8.150:6443
name: cluster2
contexts:
- context:
cluster: cluster1
namespace: default
user: cluster1-admin
name: cluster1-context
- context:
cluster: cluster2
namespace: default
user: cluster2-admin
name: cluster2-context
current-context: cluster1-context
kind: Config
preferences: {}
users:
- name: cluster1-admin
user:
client-certificate-data: DATA+OMITTED
client-key-data: DATA+OMITTED
- name: cluster2-admin
user:
client-certificate-data: DATA+OMITTED
client-key-data: DATA+OMITTED
配置文件定义了以下资源:
- clusters:集群信息,包括集群名、authority、地址和端口。
- users:用户信息,包括用户名、certificate和key。
- contexts:上下文信息,包括上下文名称、集群名、用户名和namespace。
多集群切换
kubernetes 自带工具
环境准备:
bash
[root@master30 ~]# cp .kube/config .kube/config.ori
[root@master30 ~]# cp multi-cluster-config .kube/config
查看集群清单
bash
[root@master30 ~]# kubectl config get-clusters
NAME
cluster1
cluster2
查看上下文清单
bash
[root@master30 ~]# kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
* cluster1-context cluster1 cluster1-admin default
cluster2-context cluster2 cluster2-admin default
* 代表当前使用的上下文
切换上下文
bash
[root@master30 ~]# kubectl config use-context cluster2-context
[root@master30 ~]# kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
cluster1-context cluster1 cluster1-admin default
* cluster2-context cluster2 cluster2-admin default
kubectx-第三方工具
kubectx 安装
bash
[root@master30 ~]# wget https://codeload.github.com/ahmetb/kubectx/zip/refs/heads/master -O kubectx.zip
[root@master30 ~]# unzip kubectx.zip
[root@master30 ~]# ls kubectx-master/
CONTRIBUTING.md README.md completion go.sum internal kubens
LICENSE cmd go.mod img kubectx test
[root@master30 ~]# cp kubectx-master/kubectx /usr/local/bin/
[root@master30 ~]# chmod +x /usr/local/bin/kubectx
# 配置补全
[root@master30 ~]# cp kubectx-master/completion/kubectx.bash /etc/bash_completion.d/
[root@master30 ~]# source /etc/bash_completion.d/kubectx.bash
kubectx 帮助
bash
[root@master30 ~]# kubectx -h
USAGE:
kubectx : list the contexts
kubectx <NAME> : switch to context <NAME>
kubectx - : switch to the previous context
kubectx -c, --current : show the current context name
kubectx <NEW_NAME>=<NAME> : rename context <NAME> to <NEW_NAME>
kubectx <NEW_NAME>=. : rename current-context to <NEW_NAME>
kubectx -d <NAME> [<NAME...>] : delete context <NAME> ('.' for current-context)
(this command won't delete the user/cluster entry
that is used by the context)
kubectx -u, --unset : unset the current context
kubectx -h,--help : show this message
kubectx 命令使用
bash
[root@master30 ~]# kubectx
cluster1-context
cluster2-context
[root@master30 ~]# kubectx -c
cluster2-context
[root@master30 ~]# kubectx cluster1-context
Switched to context "cluster1-context".
[root@master30 ~]# kubectx -c
cluster1-context
[root@master30 ~]# kubectx -u
Unsetting current context.
Property "current-context" unset.
[root@master30 ~]# kubectx -c
error: current-context is not set
Kubernetes Pod
学习参考:Pod
环境准备
bash
[root@master30 ~]# kubectl create ns pods
[root@master30 ~]# kubectl config set-context --current --namespace pods
Pod 介绍
pod 代表一个deployment单元:a single instance of an application in Kubernetes。
k8s通过定义一个Pod的资源,然后在Pod里面运行容器,容器需要指定镜像,用来运行具体的服务。Pod代表集群上正在运行的一个进程,一个Pod封装一个容器(也可以封装多个容器),Pod里的容器共享存储、网络等。也就是说,应该把整个pod看作虚拟机,然后每个容器相当于运行在虚拟机的进程。
-
运行单个容器的 Pod:将Pod看作是单个容器的包装器,kubernetes管理pods而不是直接管理容器。
-
运行多个容器的 Pod :POD可以封装一个由多个共存容器组成的应用程序。pod中的容器会自动在集群中的同一物理机或虚拟机上运行。POD中多个容器共享资源和依赖项,彼此通信,以及协调何时以及如何终止它们。POD将这些容器、网络资源和存储资源作为一个单一的可管理实体包装在一起。pod中多个容器共享网络和存储资源。每个pod分配唯一的ip地址,pod中容器共享netns,包括ip地址和port端口。多个容器之间使用localhost通信。当pod中容器与其他pod通信,需要使用共享的网络资源。pod可以使用多个volume,pod中所有容器都可以访问这些卷。
白话解释: 可以把pod看成是一个"豌豆荚",里面有很多"豆子"(容器)。一个豌豆荚里的豆子,它们吸收着共同的营养成分、肥料、水分等,Pod和容器的关系也是一样,Pod里面的容器共享pod的网络、存储等。
例如:web容器提供文件共享,另外一个容器负责更新文件内容。
pod 基本管理
创建 pod
bash
# 空运行,只生成yaml文件
[root@master30 ~]# kubectl run web --image=hub.laoma.cloud/library/nginx --dry-run=client -o yaml
yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: web
name: web
spec:
containers:
- image: hub.laoma.cloud/library/nginx
name: web
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
bash
# 直接创建pod
[root@master30 ~]# kubectl run web --image=hub.laoma.cloud/library/nginx
pod/web created
[root@master30 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
web 0/1 ContainerCreating 0 36s
[root@master30 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
web 1/1 Running 0 51s
[root@master30 ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web 1/1 Running 0 67s 10.224.51.131 worker31.laoma.cloud <none> <none>
[root@master30 ~]# ssh root@worker31 nerdctl ps --namespace k8s.io |grep web
[root@master30 ~]# ssh root@worker31 nerdctl images --namespace k8s.io |grep nginx
查看 pod
bash
# 以yaml格式查看pod
[root@master30 ~]# kubectl get pod web -o yaml
# 查看pod
[root@master30 ~]# kubectl describe pod web
# 查看pod标准输出,可以是哟个选项-f动态查看pod输出
[root@master30 ~]# kubectl logs -f web
编辑 pod
bash
[root@master30 ~]# kubectl edit pod web
提示:并不是所有属性都可以编辑,例如pod名称。如果非要编辑特定属性,可以先删除pod,然后修改pod对的yaml文件,重新创建。
pod 中执行命令
bash
[root@master30 ~]# kubectl exec web -- hostname
web
[root@master30 ~]# kubectl exec web -- pwd
/
[root@master30 ~]# kubectl exec -it web -- bash -c 'echo Hello World > htdocs/index.html'
[root@master30 ~]# kubectl exec web -- id
uid=0(root) gid=0(root) groups=0(root)
cp 文件给 pod
bash
[root@master30 ~]# kubectl cp /etc/hosts web:/new-hosts
[root@master30 ~]# kubectl exec web -- ls /new-hosts
/new-hosts
删除 pod
bash
[root@master30 ~]# kubectl delete pod web
pod "web" deleted
删除时间
bash[root@master30 ~]# kubectl get pod web -o yaml|grep ' terminationGracePeriodSeconds' terminationGracePeriodSeconds: 30
yaml 文件创建 pod
yaml
# web.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
run: web
name: web
spec:
containers:
- image: hub.laoma.cloud/library/nginx
name: web
bash
[root@master30 ~]# kubectl create -f web.yaml
# 或者
[root@master30 ~]# kubectl apply -f web.yaml
综合实验:构建 wordpreess
- 创建 pod-mysql 数据库
- 创建 pod-wordpress 博客
参考步骤:
bash
# 创建 pod-mysql 数据库
[root@master30 ~]# kubectl run wordpress-db --image=mysql --image-pull-policy IfNotPresent --env MYSQL_ROOT_PASSWORD=123
# 创建 pod-wordpress 博客
[root@master30 ~]# kubectl run wordpress-app --image=wordpress --image-pull-policy IfNotPresent
# 实现集群外访问集群内pod
[root@master30 ~]# kubectl port-forward pod/wordpress-app --address 10.1.8.30 8080:80
# 该命令窗口不要关闭
# 查看 IP
[root@master30 ~]# kubectl get pods -o wide | awk '{print $1" "$6}'
NAME IP
wordpress-app 10.224.113.135
wordpress-db 10.224.19.5
# 创建数据库
[root@master30 ~]# mysql -uroot -p123 -h 10.224.19.5
mysql> create database wordpress;
mysql> create user wordpress identified by '123';
mysql> grant all privileges on wordpress.* to wordpress;
mysql> flush privileges;
mysql> exit
访问web页面 http://10.1.8.30:8080,配置站点。
多容器 pod
示例文件:blog.yaml
bash
[root@master30 ~]# vim pod-blog.yaml
yaml
apiVersion: v1
kind: Pod
metadata:
name: bbs
labels:
run: bbs
spec:
containers:
- image: hub.laoma.cloud/library/mysql:latest
imagePullPolicy: IfNotPresent
name: mysql
env:
- name: MYSQL_ROOT_PASSWORD
value: "123"
- name: MYSQL_USER
value: tom
- name: MYSQL_PASSWORD
value: "123"
- name: MYSQL_DATABASE
value: bbs
ports:
- containerPort: 3306
name: mysql
protocol: TCP
- image: hub.laoma.cloud/library/wordpress:latest
imagePullPolicy: IfNotPresent
name: wordpress
env:
- name: WORDPRESS_DB_USER
value: tom
- name: WORDPRESS_DB_PASSWORD
value: "123"
- name: WORDPRESS_DB_NAME
value: bbs
- name: WORDPRESS_DB_HOST
value: 127.0.0.1
ports:
- containerPort: 80
name: wordpress
protocol: TCP
hostPort: 80
bash
[root@master30 ~]# kubectl apply -f pod-blog.yaml
# 查看 pod 运行节点
[root@master30 ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
bbs 2/2 Running 0 10m 10.224.225.68 worker32.laoma.cloud <none> <none>
# 多容器pod中执行命令,通过-c指定容器
[root@master30 ~]# kubectl exec bbs -c wordpress -- hostname
bbs
[root@master30 ~]# kubectl cp /etc/hosts bbs:/new-hosts -c wordpress
[root@master30 ~]# kubectl exec bbs -c wordpress -- ls /new-hosts
/new-hosts
数据库访问测试
bash
[root@master30 ~]# kubectl exec -it bbs -c mysql -- mysql -utom -p123
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
使用所在宿主机的80端口访问:http://10.1.8.32/
pod 关键属性
bash
[root@master30 ~]# kubectl explain pod | grep '^ [a-zA-Z]'
apiVersion <string>
kind <string>
metadata <ObjectMeta>
spec <PodSpec>
status <PodStatus>
pod.metadata
bash
[root@master30 ~]# kubectl explain pod.metadata | grep '^ [a-zA-Z]'
annotations <map[string]string>
clusterName <string>
creationTimestamp <string>
deletionGracePeriodSeconds <integer>
deletionTimestamp <string>
finalizers <[]string>
generateName <string>
generation <integer>
labels <map[string]string>
managedFields <[]Object>
name <string>
namespace <string>
ownerReferences <[]Object>
resourceVersion <string>
selfLink <string>
uid <string>
需要关注的属性:labels,name,namespace,deletionGracePeriodSeconds。
pod.spec
bash
[root@master30 ~]# kubectl explain pod.spec | grep '^ [a-zA-Z]'
activeDeadlineSeconds <integer>
affinity <Object>
automountServiceAccountToken <boolean>
containers <[]Object> -required-
dnsConfig <Object>
dnsPolicy <string>
enableServiceLinks <boolean>
ephemeralContainers <[]Object>
hostAliases <[]Object>
hostIPC <boolean>
hostNetwork <boolean>
hostPID <boolean>
hostname <string>
imagePullSecrets <[]Object>
initContainers <[]Object>
nodeName <string>
nodeSelector <map[string]string>
overhead <map[string]string>
preemptionPolicy <string>
priority <integer>
priorityClassName <string>
readinessGates <[]Object>
restartPolicy <string>
runtimeClassName <string>
schedulerName <string>
securityContext <Object>
serviceAccount <string>
serviceAccountName <string>
setHostnameAsFQDN <boolean>
shareProcessNamespace <boolean>
subdomain <string>
terminationGracePeriodSeconds <integer>
tolerations <[]Object>
topologySpreadConstraints <[]Object>
volumes <[]Object>
重点关注:containers、nodeName、volumes等。
pod.spec.containers
bash
[root@master30 ~]# kubectl explain pod.spec.containers | grep '^ [a-zA-Z]'
args <[]string>
command <[]string>
env <[]Object>
envFrom <[]Object>
image <string>
imagePullPolicy <string>
lifecycle <Object>
livenessProbe <Object>
name <string> -required-
ports <[]Object>
readinessProbe <Object>
resources <Object>
securityContext <Object>
startupProbe <Object>
stdin <boolean>
stdinOnce <boolean>
terminationMessagePath <string>
terminationMessagePolicy <string>
tty <boolean>
volumeDevices <[]Object>
volumeMounts <[]Object>
workingDir <string>
重点关注:command、env、image、imagePullPolicy、volumeMounts等。
pod.spec.containers.ImagePullPolicy
- Always,总是从仓库下载镜像。
- Never,只使用本地镜像,不下载。
- IfNotPresent,优先使用本地镜像,如果没有才从仓库下载镜像。
pod lifecycle 和 status
pod lifecycle
- pod的生命周期取决于pod中所有容器的生命周期。
- 容器的生命周期取决于容器中进程的生命周期。
Pod status
常见 pod 状态如下:
- ContainerCreating 正在创建
- Running 正在运行
- Completed 运行完成
- Error/RunContainerError 运行错误
- CrashLoopBackOff 重新创建
- ErrImagePull 获取镜像错误
- ImagePullBackOff 重新获取镜像
- Terminating,正在终止(删除)
实验1:pod中包含1个容器,验证pod状态
监控命令: watch -n 1 kubectl get pod
示例1:
yaml
apiVersion: v1
kind: Pod
metadata:
name: busybox
labels:
app: busybox
spec:
restartPolicy: Never
containers:
- name: busybox
image: hub.laoma.cloud/library/busybox
imagePullPolicy: IfNotPresent
command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 10']
command命令可以改写如下:
yaml
command:
- sh
- -c
- echo OK! && sleep 10
或者
yaml
args:
- sh
- -c
- echo OK! && sleep 10
观察pod状态为:ContainerCreating-->Running-->Completed
示例2:
yaml
apiVersion: v1
kind: Pod
metadata:
name: busybox
labels:
app: busybox
spec:
restartPolicy: Never
containers:
- name: busybox
image: hub.laoma.cloud/library/busybox
imagePullPolicy: IfNotPresent
command: ['sh', '-c', 'echoxxx Hello Kubernetes! && sleep 5']
观察pod状态为:ContainerCreating-->Error
实验2:pod中包含2个容器,验证pod状态
yaml
apiVersion: v1
kind: Pod
metadata:
name: busybox
labels:
app: busybox
spec:
restartPolicy: Never
containers:
- name: busybox1
image: hub.laoma.cloud/library/busybox
imagePullPolicy: IfNotPresent
command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 5']
- name: busybox2
image: hub.laoma.cloud/library/busybox
imagePullPolicy: IfNotPresent
command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 10']
观察pod状态为:ContainerCreating-->Running-->NotReady(其中一个先完成)-->Completed(两个都完成)
yaml
apiVersion: v1
kind: Pod
metadata:
name: busybox
labels:
app: busybox
spec:
restartPolicy: Never
containers:
- name: busybox1
image: hub.laoma.cloud/library/busybox
imagePullPolicy: IfNotPresent
command: ['sh', '-c', 'echoxx Hello Kubernetes! && sleep 5']
- name: busybox2
image: hub.laoma.cloud/library/busybox
imagePullPolicy: IfNotPresent
command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 20']
观察pod状态为:ContainerCreating-->Error
pod.spec.restartPolicy
示例:
yaml
restartPolicy: Never
containers:
- name: myapp-container
image: hub.laoma.cloud/library/busybox
command: ['sh', '-c', 'echo The app is running! && sleep 5']
restartPolicy,针对pod中所有容器生效。
- Always,除了 Running 状态,其他状态总是重启,默认值。
- OnFailure,失败了才重启。
- Never,从不重启。
实验1:验证pod中含有单个容器重启策略。
更改pod重启策略,直接apply会报错,需要删除重建。
第一个yaml验证Always/OnFailure/Never重启策略
yaml
apiVersion: v1
kind: Pod
metadata:
name: busybox
labels:
app: busybox
spec:
restartPolicy: Always/OnFailure/Never
containers:
- name: busybox
image: hub.laoma.cloud/library/busybox
imagePullPolicy: IfNotPresent
command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 5']
第二个yaml验证OnFailure
yaml
apiVersion: v1
kind: Pod
metadata:
name: busybox
labels:
app: busybox
spec:
restartPolicy: OnFailure
containers:
- name: busybox
image: hub.laoma.cloud/library/busybox
imagePullPolicy: IfNotPresent
command: ['sh', '-c', 'echoxxx Hello Kubernetes! && sleep 5']
第三个yaml验证 Never 重启策略
yaml
apiVersion: v1
kind: Pod
metadata:
name: busybox
labels:
app: busybox
spec:
restartPolicy: Never
containers:
- name: busybox
image: hub.laoma.cloud/library/busybox
imagePullPolicy: IfNotPresent
command: ['sh', '-c', 'echoxxx Hello Kubernetes! && sleep 5']
实验2:验证pod中含有多个容器重启策略。
验证结果:只要有一个容器满足重启策略条件,就会重启。
示例1:
yaml
apiVersion: v1
kind: Pod
metadata:
name: busybox
labels:
app: busybox
spec:
restartPolicy: Always/OnFailure/Never
containers:
- name: busybox1
image: hub.laoma.cloud/library/busybox
imagePullPolicy: IfNotPresent
command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 5']
- name: busybox2
image: hub.laoma.cloud/library/busybox
imagePullPolicy: IfNotPresent
command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 5']
使用Always重启策略时,当容器busybox1状态为Completed时,容器busybox2还未创建成功,此时会根据重启策略重启pod。当然也可以将容器的生命周期延长,sleep 5改为sleep 50,运行50s之后还会重启pod。
使用OnFailure/Never重启策略就不会出现这种情况。
示例2:第二个command是错误的。
yaml
apiVersion: v1
kind: Pod
metadata:
name: busybox
labels:
app: busybox
spec:
restartPolicy: Always/OnFailure/Never
containers:
- name: busybox1
image: hub.laoma.cloud/library/busybox
imagePullPolicy: IfNotPresent
command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 5']
- name: busybox2
image: hub.laoma.cloud/library/busybox
imagePullPolicy: IfNotPresent
command: ['sh', '-c', 'echoxxx Hello Kubernetes! && sleep 5']
Always和OnFailure重启策略总是会重启pod;Never重启策略就不会重启pod。
Init Containers
一个pod可以有多个容器在其中运行应用程序,也可以有一个或多个initContainers。initContainers中容器状态必须是complete,containers容器才能运行。
如果pod的initContainers fail,kubernetes根据restartpolicy重启pod,直到initContainers状态为complete。
如果pod中initContainers有多个容器,那么会按顺序创建和执行。按顺序执行的initContainers必须成功才能执行下一个initContainers。所有init全部成功执行完成后,才开始执行pod中常规容器。
使用场景:
1、等待某个服务创建成功。
for i in {1..100}; do sleep 1; if dig myservice; then exit 0; fi; done; exit 1
2、等待固定时间后再运行app容器。
sleep 60
3、Clone a git repository into a volume
示例1:
bash
root@master30:~/pods# vim pod-myapp.yaml
yaml
# myservice
---
apiVersion: v1
kind: Service
metadata:
name: myservice
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9376
# mydb
---
apiVersion: v1
kind: Service
metadata:
name: mydb
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9377
# myapp
---
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
initContainers:
- name: init-myservice
image: hub.laoma.cloud/library/busybox
command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done;sleep 3;']
- name: init-mydb
image: hub.laoma.cloud/library/busybox
command: ['sh', '-c', 'until nslookup mydb; do echo waiting for mydb; sleep 2; done;sleep 3;']
containers:
- name: myapp-container
image: hub.laoma.cloud/library/busybox
command: ['sh', '-c', 'echo The app is running! && sleep 3600']
首先创建2个service,然后创建pod,观察pod状态变化。
示例2:
bash
root@master30:~/pods# vim pod-myapp.yaml
yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
volumes:
- name: workdir
emptyDir: {}
containers:
- name: myapp-container
image: hub.laoma.cloud/library/busybox
command: ['sh', '-c', 'echo The app is running! && sleep 3600']
volumeMounts:
- name: workdir
mountPath: "/work-dir"
initContainers:
- name: init-poda
image: hub.laoma.cloud/library/busybox
command: ['sh', '-c', 'touch /work-dir/aa.txt && sleep 10']
volumeMounts:
- name: workdir
mountPath: "/work-dir"
在app容器中查看文件
bash
[root@master30 ~]# kubectl exec myapp-pod -c myapp-container -- ls /xx
pod的状态变化:Init:0/1->PodInitializing->Running
将初始化容器command变更为以下内容再测试:
command: ['sh', '-c', 'touchxx /work-dir/aa.txt']
pod的状态变化:
Init:0/1->Init:Error->Init:CrashLoopBackOff,然后Init:Error->Init:CrashLoopBackOff循环。
静态 pod
**问题:**正常情况下,pod 由 master 节点统一管理。那么 master 上的kube-apiserver、kube-scheduler、kube-controller-manager等pod又是由谁来管理的呢?
答案 :kubelet 服务。master节点上组件以静态Pod方式运行,由本地kubelet进行管理。它们不能通过API Server进行管理,无法与ReplicationController、Deployment或DaemonSet进行关联,并且kubelet也无法对其健康检查。
我们来分析下 kubelet.service 配置。
bash
[root@master30 ~]# systemctl status kubelet.service |cat
● kubelet.service - kubelet: The Kubernetes Node Agent
Loaded: loaded (/usr/lib/systemd/system/kubelet.service; enabled; preset: enabled)
Drop-In: /usr/lib/systemd/system/kubelet.service.d
└─10-kubeadm.conf
Active: active (running) since Sun 2024-07-14 09:52:08 UTC; 1h 7min ago
Docs: https://kubernetes.io/docs/
Main PID: 7489 (kubelet)
Tasks: 11 (limit: 4557)
Memory: 39.0M (peak: 39.9M)
CPU: 1min 45.913s
CGroup: /system.slice/kubelet.service
└─7489 /usr/bin/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf --config=/var/lib/kubelet/config.yaml --container-runtime-endpoint=unix:///var/run/containerd/containerd.sock --pod-infra-container-image=registry.k8s.io/pause:3.9
......
[root@master30 ~]# cat /usr/lib/systemd/system/kubelet.service
[Unit]
Description=kubelet: The Kubernetes Node Agent
Documentation=https://kubernetes.io/docs/
Wants=network-online.target
After=network-online.target
[Service]
ExecStart=/usr/bin/kubelet
Restart=always
StartLimitInterval=0
RestartSec=10
[Install]
WantedBy=multi-user.target
# kubelet.service服务启动参数通过 Drop-In 文件 10-kubeadm.conf 配置
[root@master30 ~]# cat /usr/lib/systemd/system/kubelet.service.d/10-kubeadm.conf
# Note: This dropin only works with kubeadm and kubelet v1.11+
[Service]
Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf"
Environment="KUBELET_CONFIG_ARGS=--config=/var/lib/kubelet/config.yaml"
# This is a file that "kubeadm init" and "kubeadm join" generates at runtime, populating the KUBELET_KUBEADM_ARGS variable dynamically
EnvironmentFile=-/var/lib/kubelet/kubeadm-flags.env
# This is a file that the user can use for overrides of the kubelet args as a last resort. Preferably, the user should use
# the .NodeRegistration.KubeletExtraArgs object in the configuration files instead. KUBELET_EXTRA_ARGS should be sourced from this file.
EnvironmentFile=-/etc/default/kubelet
ExecStart=
ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_KUBEADM_ARGS $KUBELET_EXTRA_ARGS
# 以下参数定义了kubelet配置文件位置
# KUBELET_CONFIG_ARGS=--config=/var/lib/kubelet/config.yaml
# 该文件中的 staticPodPath 参数定义了一个目录
# kubelet会定期扫描该目录中pod文件,并根据目标中文件变动创建和删除pod
[root@master30 ~]# grep staticPodPath /var/lib/kubelet/config.yaml
staticPodPath: /etc/kubernetes/manifests
[root@master30 ~]# ls -1 /etc/kubernetes/manifests
etcd.yaml
kube-apiserver.yaml
kube-controller-manager.yaml
kube-scheduler.yaml
**注意:**不要修改 staticPodPath 参数配置,否则需要将集群组件4个yaml文件也要复制过去。
我们还可以通过参数 --pod-manifest-path设置,该目录下所有 pod 也是静态 pod。
bash
[root@master30 ~]# kubelet --help|grep pod-manifest-path
--pod-manifest-path string Path to the directory containing static pod files to run, or the path to a single static pod file. Files starting with dots will be ignored. (DEPRECATED: This parameter should be set via the config file specified by the Kubelet's --config flag. See https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/ for more information.)
思考
1. kubernetes 中 pod 和 container 区别?
答:
容器是运行时概念 ,真正跑应用的进程环境。
kubernetes 中 Pod:是 K8s 独有的概念 ,是 K8s 中最小调度、管理、自愈单元,是容器的"外壳 + 运行环境"。
- **一个 Pod 里可以有 1 个或多个容器,**pod中所有容器:
- 同住一个房间 ,共用网络、存储。
- 一起被调度到同一台机器,一起销毁。

| 特性 | 容器 | Pod |
|---|---|---|
| K8s 最小调度单位 | ❌ 不是 | ✅ 是 |
| 独立 IP | ✅ 有 | ✅ 有 |
| 独立 存储 | ✅ 有 | ✅ 有 |
| 多容器支持 | ❌ 不支持 | ✅ 天然支持 |
| 网络/存储共享 | ❌ 不能 | ✅ 内部容器可共享 |
| 生命周期管理 | ❌ 弱 | ✅ 完整(重启、自愈) |
| 属于谁 | 运行时(Docker/containerd) | Kubernetes |
2. kubernetes 为什么直接管理 pod 而不是容器?
- 容器太"原子",不适合直接调度。K8s 需要一个能直接被调度、能独立运行、有完整身份 的对象--Pod。
-
容器:只是一个进程/运行环境(Docker/containerd)。
-
Pod:是容器的封装 + 网络/存储/配置/生命周期的统一抽象 。K8s 调度、扩缩容、自愈、服务发现、监控......全都以 Pod 为单位。
-
Pod 支持"多容器协同"(最关键设计)。
很多场景必须多个容器一起跑、共享资源:
- 业务容器 + Sidecar(日志、监控、代理)
- 业务容器 + InitContainer(初始化)
- 业务容器 + 网络/安全代理容器
它们需要:
- 共享 Network Namespace(同一个 IP、端口空间)
- 共享 Volume
- 一起调度到同一台机器
-
Pod 提供统一的生命周期与自愈。
K8s 要做:
- 重启失败容器
- 替换崩溃节点上的实例
- 滚动更新、回滚
- 扩缩容
这些行为必须作用在一个稳定、标准、独立的单元上:
- 如果直接管容器,多容器应用会乱
- 以 Pod 为单位,管理语义清晰、一致
-
解耦底层容器运行时。
Pod 屏蔽了底层实现:
- Docker
- containerd
- cri-o
- 其他 CRI 运行时
K8s 只跟 Pod/CRI 打交道,不绑定某一种容器技术。
3. 解释 pod 中 pause 容器作用
在 Kubernetes 里,每个 Pod 都会自动创建一个 pause 容器(也叫 infra 容器) ,它是 Pod 里第一个启动、最后退出的容器,作用非常关键。
-
pause 容器是干嘛的?
pause 容器就是为了"占坑",把 Pod 的网络和命名空间先 hold 住。
-
它的 3 个核心作用
① 创建并持有 Pod 的 Linux Namespace
Pod 里所有容器要共享:
- Network namespace(同一个 IP、端口)
- PID namespace(可选)
- IPC namespace
这些共享空间必须由一个"永远不死"的容器来持有 ,否则共享空间会消失。这个容器就是 pause。
② 让 Pod 生命周期独立于业务容器
- 业务容器挂了 → 重启
- pause 容器不挂 → Pod 就不会消失
- 网络、IP、存储挂载都能保持不变
如果没有 pause:业务容器一退出,整个 Pod 的网络就没了,重启也没用。
③ 实现多容器共享网络
nginx、业务容器、sidecar 都加入 pause 的 network namespace:
- 共享同一个 IP
- 可以用
127.0.0.1互相访问 - 端口不能冲突
-
超形象比喻
- pause = 房东
- Pod = 房子
- 业务容器 = 租客
房东(pause)先占好房子(网络/命名空间),租客(业务容器)才能住进来。租客换了一波又一波,房子一直都在。
-
一个 Pod 内部结构(最标准)
bashPod ├── pause 容器(infra)------ 永远第一个启动 │ 持有:网络命名空间、IP、IPC └── 业务容器 1、2、3... 都加入 pause 的命名空间 -
最精炼总结
pause 容器 = Pod 的基石
- 只负责 holding namespace
- 保证 Pod 网络、IP、生命周期稳定
环境清理
bash
[root@master30 ~]# kubectl delete ns pods