这篇记录整理一次 Kubernetes 环境搭建和应用部署流程,内容覆盖 Docker、cri-dockerd、kubeadm、Calico、Metrics Server、Pod、Deployment、Service、LoadBalancer、Ingress、NFS、Helm、Rancher 和 WordPress。
一、目标
Kubernetes(简称K8S) 是容器和集群管理的标准。Kubernetes 集群是由多个计算机(可以是物理机、云主机或虚拟机)组成的一个独立系统,通过 Kubernetes 容器管理系统,实现部署、运维和伸缩 Docker 容器等功能。本次搭建主要覆盖以下内容:
建立一个 Kubernetes 集群,包含一个主节点和两个工作节点,在集群上练习 kubectl 命令的基本操作。
练习通过命令行和 YAML 创建 Pod、Deployment 和 Job,并掌握 HPA。
练习为 Deployment 创建 Service,并通过 NodePort 暴露服务,再从客户端访问该服务。
为集群安装 LoadBalancer 软件,准备可用子网,并通过 LoadBalancer 方式暴露服务。
为集群安装 ingress-nginx 并验证。
为集群准备 NFS Server,安装 NFS Subdir External Provisioner,然后创建 PersistentVolumeClaim 并验证。
下载安装 Helm,用它安装 Rancher Dashboard,然后在 Dashboard 中管理集群并创建 WordPress 应用。
说明:部分镜像如 busybox、perl 等通过其他服务器提前拉取并打包到本地,再导入本地虚拟机使用。
二、安装并配置Docker
先配置 Docker 的 apt repository。
添加 Docker 官方 GPG key:
1 | $ sudo apt-get update |
或者安装制定版本:
1 | $ apt-cache madison docker-ce | awk '{ print $3 }' |
这部分和 Docker 单独安装流程基本一致,下面保留最终安装效果,然后继续 Kubernetes 相关配置。


Linux全局代理添加
1 | export HTTP_PROXY=http://noc:8912027@cg.lzu.edu.cn:8080 |
安装cri-dockered
1 | # wget http://bigdata.cg.lzu.edu.cn/kubernetes/cri-dockerd_0.3.13.3-0.ubuntu-jammy_amd64.deb |
关闭swap
命令行swapoff –a直接关闭
1 | # vi /etc/fstab 注释掉swap引导项 |
查看br_netfilter模块和overlay是否被内核加载
1 | # lsmod | grep br_netfilter |

set apt source of aliyun for kubernetes
1 | # curl -s https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | apt-key add |

三、安装kubernetes
control node:
1 | # kubeadm version |

1 | # kubeadm init --apiserver-advertise-address=192.168.111.135 --control-plane-endpoint=192.168.111.135 \ |

1 | # mkdir -p $HOME/.kube |
这里显示了一个控制节点docker,因为我使用的是docker主机名

worker node 加入集群(需要将ip地址改为对应的worker节点虚拟机):
1 | # kubeadm join 192.168.101.100:6443 --token 7k09zz.6ogjsk85qsqbc8wx \ |
由于当前设备只能启动一台虚拟机,这里没有继续展示 worker 节点加入过程,后续操作在单节点控制平面上完成。
1 | # kubectl describe nodes docker |

Delete the tain for control node in single node environment:
1 | # kubectl taint node docker node-role.kubernetes.io/control-plane- |

安装calico
1 | # wget https://raw.githubusercontent.com/projectcalico/calico/v3.27.2/manifests/tigera-operator.yaml |

安装metric-server
1 | # wget http://bigdata.cg.lzu.edu.cn/kubernetes/metrics-server-v0.7.1.tar |

1 | # kubectl get pod -A |

1 | # kubectl top nodes |
可以看到所有namespace都成功运行,配置成功。

四、练习kubectl基本命令
4.1 pod 基本操作
查看kubernetes集群信息
1 | # kubectl cluster-info |
查看kubernetes版本
1 | # kubectl version |
查看kubernetes所支持的api-version
1 | # kubectl api-versions |

删除节点及重新加入
步骤1、通过kubeadm drain命令把节点设置为维护模式,会把已经在该节点上运行的业务pod驱逐到其他节点运行
1 | # kubectl drain node03 --delete-emptydir-data --force --ignore-daemonsets |
步骤2、删除这个节点
1 | # kubectl delete nodes node03 |
步骤3、清空节点上的配置
1 | # kubeadm reset(不管是master还是worker节点清空kubernetes配置都使用该命令) |
v1.24以后使用docker-ce时需添加–cri-socket unix:///var/run/cri-dockerd.sock
1 | # kubeadm reset --cri-socket unix:///var/run/cri-dockerd.sock |
步骤4、重新加入集群
配置namespace练习
1 | # kubectl get namespaces |

查看节点以及服务
1 | # kubectl get service -A |

五、使用命令行和yaml文件创建pod
5.1 Pod创建
查看pod
1 | # kubectl get pod |
创建pod,创建pod时可带诸多参数,运行kubectl run –h查看更多即可
1 | kubectl run NAME --image=image [--env="key=value"] [--port=port] [--labels=label=value] [--dry-run=server|client] [--overrides=inline-json] [--command] -- [COMMAND] [args...] [options] |
删除pod,增加参–force可加快删除速度
1 | # kubectl delete pod pod1 |

1 | # kubectl run pod1 --image=nginx --port=80 |
集群内每一个pod都会获得一个地址(pod地址是相对临时的,service地址才是相对稳定的)
1 | # kubectl get pod -o wide |
通过IP访问pod
1 | # curl http://10.244.239.9 |


在pod里执行命令
1 | # kubectl exec pod1 -- ls /usr/share/nginx/html |
物理机和pod互拷文件
1 | # kubectl cp /etc/hosts pod1:/usr/share/nginx/html/ |
进入pod里并获取bash
1 | # kubectl exec -it pod1 -- bash |

如果一个pod有多个容器默认进入的是第一个容器,想进入指定容器用-c指定容器名。
查看pod里的输出,如果一个pod有多个容器,需要使用-c指定查看哪个容器的输出。
1 | # kubectl logs pod1 |

使用yaml的方式来创建pod可以在文件里指定更多的属性。
1 | # mkdir pod ; cd pod |

*YAML文件写法是分级的,子级和父级之间要缩进2个空格(不能按Tab键),子级的第一个位置可以以“-”开头,这个“-”和父级对齐。
YAML文件里第一级常见参数主要有以下四个:
1 | apiVersion: 指定pod的apiVersion,固定值v1 |
使用YAML文件创建pod:
1 | # kubectl apply -f pod3.yaml |


查看pod属性
1 | # kubectl describe pod pod3 |
进入pod并获取bash
1 | # kubectl exec -it pod3 -- bash |
删除pod
1 | # kubectl delete -f pod3.yaml |


创建deployment
1 | # kubectl create deployment nginx --image=nginx --replicas=2 |
查看deployment
1 | # kubectl get deployments.apps |

修改镜像下载策略以提高速度
1 | # kubectl edit deployments.apps nginx |
修改副本数
1 | # kubectl scale deployment nginx --replicas=4 |
删除deployment
1 | # kubectl delete deployments.apps nginx |

通过yaml方式创建depoyment
1 | # kubectl create deployment nginx --image=nginx --dry-run=client -o yaml > d1.yaml |

1 | # kubectl apply -f d1.yaml |

1 | # kubectl get deployments.apps |

删除一个pod后,会自动创建出一个新的pod,以满足replicas数。
1 | # kubectl delete pod nginx-57cc89bc77-2g66z |
删除deployment
1 | # kubectl delete -f d1.yaml |

当deployment的pod负载较大,需要更多的pod来分摊负载,就需要管理员手动去调整副本数。
可以设置让k8s根据pod负载情况自动去调整deployment里pod的副本数,这可以通过水平自动更新HPA(Horizontal Pod Autoscalers)来实现,通过检查pod的cpu负载通知deployment让其自动更新pod数量。
1 | kubectl autoscale (-f FILENAME | TYPE NAME | TYPE/NAME) [--min=MINPODS] --max=MAXPODS [--cpu-percent=CPU] |
查看当前是否有hpa配置
1 | # kubectl get hpa |
创建hpa
1 | # kubectl get deployments.apps |
查看
1 | # kubectl get horizontalpodautoscalers.autoscaling |

删除hpa
1 | # kubectl delete horizontalpodautoscalers.autoscaling nginx |

修改deployment的配置,设置每个容器的资源限制
1 | # kubectl edit deployments.apps nginx |
创建deployment副本数为1个
1 | # kubectl scale deployment nginx --replicas=1 |

创建新的HPA,使得每个pod的cpu数最大使用率不超过70%
1 | # kubectl autoscale deployment nginx --min=1 --max=5 --cpu-percent=70 |
为deployment创建一个服务,类型为NodePort
1 | # kubectl expose deployment nginx --port=80 --target-port=80 --type=NodePort |

在任一客户端安装ab测试对其进行压测:
1 | # yum install httpd-tools –y (# apt install apache2-utils) |
随着请求CPU负载增加pod自动扩展。
负载降低后pod数不是立刻减少,要等到一段时间,默认是5m,目的是防止pod数的抖动。
升级镜像可以通过以下三种方法:
1、kubectl edit deploy
2、修改yaml文件,然后执行kubectl apply -f yaml文件
3、命令行方式修改。命令行方式可以记录镜像变更信息,回滚方便。
命令行升级deployment里镜像的语法:
1 | kubectl set image deploy/名字 容器名=镜像 <--record> |
查看镜像变化过程,由于没有记录无法查看,
1 | # kubectl rollout history deployment nginx |

更新镜像时增加–record选项记录更新以方便镜像回滚。
1 | # kubectl set image deploy/nginx nginx=nginx:1.20 --record |
如果变更后的镜像有问题,我们可以把镜像回滚到变更之前的版本,回滚的语法是:
1 | kubectl rollout undo deployment 名字 --to-revision=版本 |

对deployment可能会有多个pod,使用滚动更新不是一次性全部更新,而是先更新几个pod镜像,更新完成后再更新几个,直至将所有pod全部更新完毕。
rollingUpgrade主要涉及两个参数:
1、maxSurge:指定一次创建几个pod,可以是百分比,也可以是具体数字
2、maxUnavailable:用来指定最多删除几个pod,可以是百分比,也可以是具体数字
1 | # kubectl edit deployments.apps nginx |
默认为25%。可修改为1进行查看,即变更镜像时删除一个创建一个。
1 | # kubectl scale deployment nginx --replicas=5 |
因为docker现在被墙了,其他版本镜像无法拉取

5.2 job 练习: 计算圆周率小数点后 2000 位
job:执行一次性任务,如数据处理分析测试运算等。
创建一个yaml文件
1 | # kubectl create job job3 --image=busybox --dry-run=client -o yaml -- sh -c "echo hello && sleep 30" > job3.yaml |
对生成的yaml进行修改添加imagePullPolicy:IfNotPresent后创建job
1 | # kubectl apply -f job3.yaml |
当任务完成时job完成,pod状态变为Completed。
删除job
1 | # kubectl delete jobs.batch job3 |

job练习:计算圆周率小数点后2000位
1 | # kubectl create job job2 --image=perl -- perl -Mbignum=bpi -wle 'print bpi(2000)' |


查看计算结果
1 | # kubectl logs job2-le3gv |

5.3 cronjob
cronjob是周期性的、循环的。(linux上使用cron周期性执行任务)
1 | # kubectl get cronjobs.batch |
创建cronjobs
1 | kubectl create cronjob NAME --image=image --schedule=‘cron表达式' -- [COMMAND] [args...] [flags] [options] |
创建一个每一分钟执行一次的cronjob
1 | # kubectl create cronjob cjob1 --image=busybox --schedule="*/1 * * * *" --dry-run=client -o yaml -- /bin/sh -c "echo hello && sleep 30" > cjob1.yaml |
修改添加镜像下载策略imagePullPolicy: IfNotPresent
创建cronjob
1 | # kubectl apply -f cjob1.yaml |
每隔1分钟生成一个pod,该pod完成任务sleep 30后就结束。
Completed pod数由选项successfulJobsHistoryLimit决定,默认为3。
删除cronjob
1 | # kubectl delete cronjobs.batch cjob1 |

5.4 StatefulSets
1 | # vi headless-nginx.yaml |
六、使用命令行和yaml文件创建deployment and job
6.1 deployment
1 | # kubectl create deployment web1 --image=nginx --dry-run=client -o yaml > web1.yaml |

1 | # kubectl expose deployment nginx --name=web1 --port=80 --target-port=80 |
不使用–name指定服务名,则保持和deployment名字一致。
1 | --port指服务端口, --target-port是后端pod运行服务的端口。 |
查看服务
1 | # kubectl get svc |
查看详细信息
1 | # kubectl describe service web1 |

使用命令生成yaml文件
1 | # kubectl expose deployment web1 --name=web1 --port=80 --target-port=80 --dry-run=client -o yaml > svc1.yaml |
查看yaml文件
1 | # vi svc1.yaml |
使用yaml文件创建service
1 | # kubectl apply -f svc1.yaml |
查看
1 | # kubectl get svc |
删除服务
1 | # kubectl delete -f svc1.yaml |

6.2 服务发布
外部主机访问集群服务主要有三种方式:
1、NodePort
将服务映射到物理机(集群中所有节点)的某个端口提供外界访问
2、LoadBalancer
使用LoadBalancer给svc分配一个地址(外界可访问地址),svc直接对外提供服务。
需要安装部署第三方工具metallb。
3、ingress
使用nginx-ingress实现反向代理,通过域名对外提供服务。
需要安装部署nginx-ingress控制器。
1 | # kubectl expose deployment web1 --name=web1 --port 80 --type=NodePort |
Yaml文件为:
1 | apiVersion: v1 |

七、安装loadblancer
使用LoadBalancer需要安装部署第三方工具metalllb。
1 | # kubectl edit configmap -n kube-system kube-proxy |
修改 strictARP: true
下载部署metallb所需yaml文件
1 | # mkdir ~/metallb |

部署metallb
可以修改配置文件添加imagePullPolicy: IfNotPresent然后进行部署
1 | # kubectl apply -f metallb-native.yaml |
查看
1 | # kubectl get deployments.apps -n metallb-system |

创建一个外部地址池
1 | # vi ipaddresspool.yaml |
修改地址池范围,指定可用地址
1 | # kubectl edit ipaddresspools.metallb.io -n metallb-system |

发布地址池:
1 | # vi l2advertisement.yaml |

1 | # kubectl apply -f l2advertisement.yaml |
创建一个pod
1 | # kubectl run pod1 --image=nginx --image-pull-policy=IfNotPresent |
为pod1创建一个名为svc1类型为LoadBalancer的服务
1 | # kubectl expose pod pod1 --name=svc1 --port=80 --type=LoadBalancer |

访问EXTERNAL-IP即可。
删除svc1和pod1
1 | # kubectl delete svc svc1 |

八、安装ingress-nginx
官网:https://kubernetes.github.io/ingress-nginx/
1 | # mkdir ~/ingress-nginx |
所需镜像国内网络无法下载,从国外下载打包回来。并修改yaml文件中镜像名称和实际镜像名称一致。
校内镜像下载: wget http://bigdata.cg.lzu.edu.cn/kubernetes/ingress-nginx-v1.7.0.tar
下载镜像文件并在所有节点加载镜像。并根据实际镜像tag修改deploy.yaml文件。
1 | # kubectl apply -f deploy.yaml |

1 | # kubectl get pod -n ingress-nginx |
修改pod副本数为worker数
1 | # kubectl scale deployment ingress-nginx-controller -n ingress-nginx --replicas=2 |

1 | # kubectl get svc -n ingress-nginx |
创建一个名为pod1的pod
1 | # kubectl run pod1 --image=nginx --image-pull-policy=IfNotPresent |
为这个pod1创建名为pod1的svc
1 | # kubectl expose pod pod1 --name=pod1 --port 80 |
创建ingress策略
1 | # kubectl create ingress pod1.lzu.edu.cn --class=nginx --rule=pod1.lzu.edu.cn/*=pod1:80 |

手动添加解析后访问
1 | # curl http://pod1.lzu.edu.cn |
九、准备NFS server并安装其他服务
nfs-server configure:
1 | # apt -y install nfs-kernel-server |

1 | # git clone https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner.git |
增加镜像下载策略和修改NFS_SERVER和NFS_PATH和nfs server path

1 | # kubectl apply -f rbac.yaml |

镜像需要从境外下载,下载镜像导入到各工作节点
1 | # wget http://bigdata.cg.lzu.edu.cn/kubernetes/nfs-subdir-provisioner-v4.0.2.tar |

1 | # kubectl apply -f class.yaml |

1 | # cat test-claim.yaml |
十、安装heml tool、rancher danshbord、wordpress
下载helm:https://github.com/helm/helm/releases
1、下载 需要的版本
2、解压
3、在解压目中找到helm程序,移动到需要的目录中(mv ~/linux-amd64/helm /usr/local/bin/helm)
然后就可以执行客户端程序并 添加稳定仓库: helm help.
helm仓库语法帮助
1 | # helm repo -h |

添加仓库语法:
1 | helm repo add 名字 地址 |
添加仓库
1 | # helm repo add github https://burdenbear.github.io/kube-charts-mirror/ |
查看当前的仓库
1 | # helm repo list |
仓库更新
1 | # helm repo update |
删除仓库
1 | # helm repo remove github |


通过helm安装cert-manager
1 | # helm repo add jetstack https://charts.jetstack.io |

1 | # proxy_host=username:password@proxyserver:port |

查看
1 | # kubectl rollout status deployment -n cert-manager cert-manager |

1 | # helm repo add rancher-stable https://releases.rancher.com/server-charts/stable |
通过文件创建secret
1 | # vi mypasswd |

1 | # kubectl create secret generic mysecret2 --from-file=mypasswd |
查看
1 | # kubectl get secrets |

看到其类型为Opaque,即使用base64编码格式的secret
1 | # kubectl get secrets mysecret2 -o yaml |
看到只有一个data,名为mypasswd,内容被base64编码过了
查看
1 | # kubectl get secrets mysecret2 -o jsonpath='{.data.mypasswd} ' |


1 | # kubectl apply -f pod1_secret.yaml |
通过helm安装cert-manager
1 | # helm repo add jetstack https://charts.jetstack.io |

查看
1 | # kubectl rollout status deployment -n cert-manager cert-manager |

1 | # helm repo add rancher-stable https://releases.rancher.com/server-charts/stable |

1 | # helm upgrade --install rancher rancher-stable/rancher --namespace cattle-system |
查看
1 | # kubectl rollout status deployment -n cattle-system rancher |

默认创建的ingress类型不是nginx,没有注册到ingress-nginx-controller,删除重建(rke创建的kubernetes无需此步骤)
1 | # kubectl delete ingress rancher -n cattle-system |

rancher使用
客户端自行添加域名解析
修改设置管理员密码时需满足复杂度要求,默认最小12位。
自建kubernetes在rancher创建ingress默认class不是nginx,需手工创建。
(ingress-nginx-controller使用了LoadBalancer分配的外部地址。)
rke创建的kubernetes在集群前端添加负载均衡即可。负载均衡将80/443负载到kubernetes集群所有worker节点,DNS将域名解析到负载均衡对外端口。
(rancher将nginx-ingress-controller采用了daemonset部署,直接使用了worker节点80/443端口)



Rancher 还可以通过 RKE 方式自动搭建 Kubernetes 集群:

此外,还可以在 K8S 上搭建 WordPress,流程和之前单独部署 WordPress 基本一致:
1 | # cd /var/www/html/ |
修改权限
1 | # chown -R apache. wordpress/ |
删除下载文件
1 | # rm latest-zh_CN.zip |
将wordpress文件放置到apache根目录
1 | # mv /var/www/html/wordpress/* /var/www/html/ |
修改wordpress配置文件,配置数据库信息
1 | # cp /var/www/html/wp-config-sample.php /var/www/html/wp-config.php |
/** WordPress 数据库名称 */
define( ‘DB_NAME’, ‘wordpress’ );
/** 数据库用户名 */
define( ‘DB_USER’, ‘wordpress’ );
/** 数据库密码 */
define( ‘DB_PASSWORD’, ‘Wordpress!2024’ );
/** 数据库主机 */
define( ‘DB_HOST’, ‘172.16.249.229:33061’ );
数据库信息配置正确就可以进行初始化了。
日志文件目录/var/log/httpd/
php配置文件/etc/httpd/conf.d/php.conf
php-fpm配置文件/etc/php-fpm.d/www.conf
apache配置文件/etc/httpd/conf/httpd.conf
apache的php配置文件 /etc/httpd/conf.d/php.conf
supervisor配置文件/etc/supervisord.conf
supervisor增加的启动服务配置文件/etc/supervisord.d/startup.ini
下面访问虚拟机ip地址:http://192.168.111.135

至此,K8S 集群安装、基础对象操作、服务暴露、Ingress、NFS、Rancher 和 WordPress 部署都已经完成。
十一、一些记录
这次搭建覆盖了 Kubernetes 的几个核心操作面:
基本kubectl命令:我练习了使用基本的kubectl命令来与Kubernetes集群进行交互。
Pod操作:我学习了如何对Pod执行基本操作,包括创建、扩展和删除。
Deployment和Service创建:我使用YAML文件创建了 Deployment和Service,展示了我对Kubernetes声明性配置方法的理解。
负载均衡器和 ingress 控制器:我安装并配置了负载均衡器和ingress控制器,启用了对Kubernetes应用程序的外部访问。
NFS服务器和其他服务:我设置了NFS服务器并安装了其他服务,扩展了Kubernetes集群的功能。
工具和Dashboard:我安装并探索了工具,例如Helm、Rancher Dashboard和WordPress,扩展了我的Kubernetes技能。