Kubernetes 实践:集群安装与应用部署

这篇记录整理一次 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ sudo apt-get update
$ sudo apt-get install ca-certificates curl
$ sudo install -m 0755 -d /etc/apt/keyrings
$ sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
$ sudo chmod a+r /etc/apt/keyrings/docker.asc
Add the repository to Apt sources:
$ echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
$ sudo apt-get update
# step 1: 安装必要的一些系统工具
sudo apt-get update
sudo apt-get -y install apt-transport-https ca-certificates curl software-properties-common
# step 2: 安装GPG证书
curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
# Step 3: 写入软件源信息
sudo add-apt-repository "deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"
# Step 4: 更新并安装Docker-CE
sudo apt-get -y update
sudo apt-get -y install docker-ce

或者安装制定版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
$ apt-cache madison docker-ce | awk '{ print $3 }'
$ VERSION_STRING=5:20.10.24~3-0~ubuntu-jammy
$ sudo apt-get install docker-ce=$VERSION_STRING docker-ce-cli=$VERSION_STRING
# apt list --installed | grep docker
Set version lock
# apt-mark hold docker-* containerd.io
List version locked software
# apt-mark showhold
Unlock the software
# apt-mark unhold docker-*
# vi /etc/docker/daemon.json
{
"oom-score-adjust": -1000,
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file": "5"
},
"exec-opts": ["native.cgroupdriver=systemd"],
"max-concurrent-downloads": 10,
"max-concurrent-uploads": 10,
"bip": "169.254.123.1/24",
"dns": ["202.201.0.133"],
"storage-driver": "overlay2",
"storage-opts": ["overlay2.override_kernel_check=true"]
}
}
# systemctl daemon-reload
# systemctl restart docker
# mkdir /etc/systemd/system/docker.service.d
# cd /etc/systemd/system/docker.service.d/
# vi http_proxy.conf
[Service]
Environment="HTTP_PROXY=http://noc:8912027@cg.lzu.edu.cn:8080"
Environment="HTTPS_PROXY=http://noc:8912027@cg.lzu.edu.cn:8080"
Environment="NO_PROXY=localhost,127.0.0.1,harbor.lzu.edu.cn"
# systemctl daemon-reload
# systemctl restart docker

这部分和 Docker 单独安装流程基本一致,下面保留最终安装效果,然后继续 Kubernetes 相关配置。

操作截图 3

操作截图 4

Linux全局代理添加

1
2
3
4
5
6
export HTTP_PROXY=http://noc:8912027@cg.lzu.edu.cn:8080
export HTTPS_PROXY=http://noc:8912027@cg.lzu.edu.cn:8080
export NO_PROXY=localhost,127.0.0.1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,*.lzu.edu.cn
export http_proxy=http://noc:8912027@cg.lzu.edu.cn:8080
export https_proxy=http://noc:8912027@cg.lzu.edu.cn:8080
export no_proxy=localhost,127.0.0.1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,*.lzu.edu.cn

安装cri-dockered

1
2
3
4
# wget http://bigdata.cg.lzu.edu.cn/kubernetes/cri-dockerd_0.3.13.3-0.ubuntu-jammy_amd64.deb
# dpkg -i cri-dockerd_0.3.13.3-0.ubuntu-jammy_amd64.deb
# systemctl daemon-reload
# systemctl start cri-docker

关闭swap

命令行swapoff –a直接关闭

1
# vi /etc/fstab  注释掉swap引导项

查看br_netfilter模块和overlay是否被内核加载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# lsmod | grep br_netfilter
# lsmod | grep overlay
# modprobe br_netfilter
# modprobe overlay
# cat <<EOF | tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
# cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
# sysctl --system

操作截图 5

set apt source of aliyun for kubernetes

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# curl -s https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | apt-key add
# echo "deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main" > /etc/apt/sources.list.d/k8s.list
# apt-get update
# apt-cache madison kubelet
# apt install kubeadm=1.26.8-00 kubelet=1.26.8-00 kubectl=1.26.8-00 -y
# systemctl enable kubelet
# apt-mark hold kubelet kubeadm kubectl
# source <(kubectl completion bash)
# echo 'source <(kubectl completion bash)' >>~/.bashrc
# vi /etc/docker/daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"],
}
# vi /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
[Service]
Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf --cgroup-driver=systemd"
# vi /usr/lib/systemd/system/cri-docker.service
[Service]
ExecStart=/usr/bin/cri-dockerd --pod-infra-container-image=registry.aliyuncs.com/google_containers/pause:3.9 --container-runtime-endpoint fd://
# containerd config default > /etc/containerd/config.toml
Reboot the service:
systemctl daemon-reload
systemctl restart containerd.service
systemctl restart docker.service
systemctl restart cri-docker

操作截图 6

三、安装kubernetes

control node:

1
# kubeadm version

操作截图 7

1
2
3
4
5
6
# kubeadm init --apiserver-advertise-address=192.168.111.135 --control-plane-endpoint=192.168.111.135 \
--pod-network-cidr=10.244.0.0/16 --service-cidr=10.245.0.0/16 \
--image-repository registry.aliyuncs.com/google_containers \
--ignore-preflight-errors=Swap \
--kubernetes-version=v1.26.8 \
--cri-socket unix:///var/run/cri-dockerd.sock

操作截图 8

1
2
3
4
# mkdir -p $HOME/.kube
# cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
# chown $(id -u):$(id -g) $HOME/.kube/config
# kubectl get node

这里显示了一个控制节点docker,因为我使用的是docker主机名

操作截图 9

worker node 加入集群(需要将ip地址改为对应的worker节点虚拟机):

1
2
3
4
# kubeadm join 192.168.101.100:6443 --token 7k09zz.6ogjsk85qsqbc8wx \
--discovery-token-ca-cert-hash sha256:391c3cb957ec1a9e2f67b1516768d69029e712f4ca98e5b49d9cd8b651dde93d \
--control-plane \
--cri-socket unix:///var/run/cri-dockerd.sock

由于当前设备只能启动一台虚拟机,这里没有继续展示 worker 节点加入过程,后续操作在单节点控制平面上完成。

1
# kubectl describe nodes docker

操作截图 10

Delete the tain for control node in single node environment:

1
2
# kubectl taint node docker node-role.kubernetes.io/control-plane-
# kubectl taint node docker node.kubernetes.io/not-ready-

操作截图 11

安装calico

1
2
3
4
5
6
7
8
9
10
# wget https://raw.githubusercontent.com/projectcalico/calico/v3.27.2/manifests/tigera-operator.yaml
# wget https://raw.githubusercontent.com/projectcalico/calico/v3.27.2/manifests/custom-resources.yaml
# vi custom-resources.yaml
ipPools:
- blockSize: 24
cidr: 10.244.0.0/16
# kubectl create -f tigera-operator.yaml
# kubectl create -f custom-resources.yaml
# kubectl get ns
# kubectl get node -o wide

操作截图 12

安装metric-server

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# wget http://bigdata.cg.lzu.edu.cn/kubernetes/metrics-server-v0.7.1.tar
# docker image load -i metrics-server-v0.7.1.tar
# vi ./metrics-server/manifests/base/deployment.yaml
containers:
- name: metrics-server
image: gcr.io/k8s-staging-metrics-server/metrics-server:v0.7.1
imagePullPolicy: IfNotPresent
command:
- /metrics-server
- --kubelet-insecure-tls
- --kubelet-preferred-address-types=InternalIP
# kubectl apply -k ./metrics-server/manifests/base/
# kubectl get pod -n kube-system | grep metric
# kubectl get service -A

操作截图 13

1
2
# kubectl get pod -A
# kubectl get pods -n kube-system -o wide

操作截图 14

1
2
# kubectl top nodes
# kubectl top pod -n kube-system

可以看到所有namespace都成功运行,配置成功。

操作截图 15

四、练习kubectl基本命令

4.1 pod 基本操作

查看kubernetes集群信息

1
# kubectl cluster-info

查看kubernetes版本

1
2
# kubectl version
# kubectl version --short

查看kubernetes所支持的api-version

1
# kubectl api-versions

操作截图 16

删除节点及重新加入

步骤1、通过kubeadm drain命令把节点设置为维护模式,会把已经在该节点上运行的业务pod驱逐到其他节点运行

1
2
# kubectl drain node03 --delete-emptydir-data --force --ignore-daemonsets
# kubectl get node

步骤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
2
3
4
5
# kubectl get namespaces
# kubectl get ns
# kubectl create namespace ns1
# kubectl delete namespaces ns1
# kubectl config set-context --current --namespace=default

操作截图 17

查看节点以及服务

1
2
3
# kubectl get service -A
# kubectl get node
# kubectl get service -A

操作截图 18

五、使用命令行和yaml文件创建pod

5.1 Pod创建

查看pod

1
2
3
4
# kubectl get pod
# kubectl get pod -n kube-system
# kubectl get pod --all-namespaces
# kubectl get pod –A

创建pod,创建pod时可带诸多参数,运行kubectl run –h查看更多即可

1
2
kubectl run NAME --image=image  [--env="key=value"]  [--port=port]  [--labels=label=value]  [--dry-run=server|client] [--overrides=inline-json] [--command] -- [COMMAND] [args...] [options]
# kubectl run pod1 --image=nginx

删除pod,增加参–force可加快删除速度

1
# kubectl delete pod pod1

操作截图 19

1
2
# kubectl run pod1 --image=nginx --port=80
# 或kubectl run pod1 --image=nginx --image-pull-policy=IfNotPresent

集群内每一个pod都会获得一个地址(pod地址是相对临时的,service地址才是相对稳定的)

1
# kubectl get pod -o wide

通过IP访问pod

1
# curl http://10.244.239.9

操作截图 20

操作截图 21

在pod里执行命令

1
# kubectl exec  pod1 -- ls /usr/share/nginx/html

物理机和pod互拷文件

1
2
3
# kubectl cp /etc/hosts pod1:/usr/share/nginx/html/
# kubectl cp pod1:/usr/share/nginx/html/hosts /root/hosts
# kubectl cp pod1:/usr/share/nginx/html/ /opt/

进入pod里并获取bash

1
2
3
# kubectl exec -it pod1 -- bash
root@pod1:/#
root@pod1:/# exit

操作截图 22

如果一个pod有多个容器默认进入的是第一个容器,想进入指定容器用-c指定容器名。

查看pod里的输出,如果一个pod有多个容器,需要使用-c指定查看哪个容器的输出。

1
# kubectl logs pod1

操作截图 23

使用yaml的方式来创建pod可以在文件里指定更多的属性。

1
2
3
# mkdir pod ; cd pod
# kubectl run pod2 --image=nginx --dry-run=client -o yaml > pod2.yaml
# cat pod2.yaml

操作截图 24

*YAML文件写法是分级的,子级和父级之间要缩进2个空格(不能按Tab键),子级的第一个位置可以以“-”开头,这个“-”和父级对齐。

YAML文件里第一级常见参数主要有以下四个:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
apiVersion: 指定pod的apiVersion,固定值v1
kind: 指定当前yaml要创建的类型是pod,与apiVersion值是对应的
metadata:用于指定pod的元数据信息,包括pod名、pod标签和所在命名空间等信息
spec:定义容器及各种策略
# vi pod3.yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: pod3
name: pod3
spec:
containers:
- command: ["sh","-c","echo aa;sleep 1000"]
image: nginx
imagePullPolicy: IfNotPresent
name: c1
resources: {}
- image: nginx
imagePullPolicy: IfNotPresent
name: c2
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}

使用YAML文件创建pod:

1
2
3
4
# kubectl apply -f pod3.yaml
# kubectl get pod
# kubectl logs pod3 -c c1
# kubectl logs pod3 -c c2

操作截图 25

操作截图 26

查看pod属性

1
# kubectl describe pod pod3

进入pod并获取bash

1
2
# kubectl exec -it pod3 -- bash
# kubectl exec -it pod3 -c c2 -- bash

删除pod

1
# kubectl delete -f pod3.yaml

操作截图 27

操作截图 28

创建deployment

1
# kubectl create deployment nginx --image=nginx --replicas=2

查看deployment

1
# kubectl get deployments.apps

操作截图 29

修改镜像下载策略以提高速度

1
2
# kubectl edit deployments.apps nginx
imagePullPolicy: Always

修改副本数

1
# kubectl scale deployment nginx --replicas=4

删除deployment

1
# kubectl delete deployments.apps nginx

操作截图 30

通过yaml方式创建depoyment

1
2
# kubectl create deployment nginx --image=nginx --dry-run=client -o yaml > d1.yaml
# vi d1.yaml

操作截图 31

1
# kubectl apply -f d1.yaml

操作截图 32

1
2
3
4
# kubectl get deployments.apps
# kubectl get deployments.apps -o wide
# kubectl get pod
# kubectl get pod -o wide

操作截图 33

删除一个pod后,会自动创建出一个新的pod,以满足replicas数。

1
2
# kubectl delete pod nginx-57cc89bc77-2g66z
# kubectl get pod

删除deployment

1
# kubectl delete -f d1.yaml

操作截图 34

当deployment的pod负载较大,需要更多的pod来分摊负载,就需要管理员手动去调整副本数。

可以设置让k8s根据pod负载情况自动去调整deployment里pod的副本数,这可以通过水平自动更新HPA(Horizontal Pod Autoscalers)来实现,通过检查pod的cpu负载通知deployment让其自动更新pod数量。

1
2
kubectl autoscale (-f FILENAME | TYPE NAME | TYPE/NAME) [--min=MINPODS] --max=MAXPODS [--cpu-percent=CPU]
--cpu-percent如果不写默认是80.

查看当前是否有hpa配置

1
# kubectl get hpa

创建hpa

1
2
# kubectl get deployments.apps
# kubectl autoscale deployment nginx --min=2 --max=10

查看

1
2
# kubectl get horizontalpodautoscalers.autoscaling
# kubectl scale deployment nginx --replicas=1

操作截图 35

删除hpa

1
# kubectl delete horizontalpodautoscalers.autoscaling nginx

操作截图 36

修改deployment的配置,设置每个容器的资源限制

1
2
3
4
5
6
7
# kubectl edit deployments.apps nginx
- image: nginx
imagePullPolicy: IfNotPresent
name: nginx
resources:
requests:
cpu: 100m

创建deployment副本数为1个

1
# kubectl scale deployment nginx --replicas=1

操作截图 37

创建新的HPA,使得每个pod的cpu数最大使用率不超过70%

1
# kubectl autoscale deployment nginx --min=1 --max=5 --cpu-percent=70

为deployment创建一个服务,类型为NodePort

1
2
# kubectl expose deployment nginx --port=80 --target-port=80 --type=NodePort
# kubectl get service

操作截图 38

在任一客户端安装ab测试对其进行压测:

1
2
# yum install httpd-tools –y   (# apt install apache2-utils)
# ab -t 600 -n 1000000 -c 1000 http://192.168.111.135:30267/index.html

随着请求CPU负载增加pod自动扩展。

负载降低后pod数不是立刻减少,要等到一段时间,默认是5m,目的是防止pod数的抖动。

升级镜像可以通过以下三种方法:

1、kubectl edit deploy

2、修改yaml文件,然后执行kubectl apply -f yaml文件

3、命令行方式修改。命令行方式可以记录镜像变更信息,回滚方便。

命令行升级deployment里镜像的语法:

1
2
3
4
5
6
kubectl set image deploy/名字  容器名=镜像  <--record>
# kubectl set image deploy/nginx nginx=nginx:latest
# kubectl set image deploy/nginx nginx=nginx:1.21
# kubectl get deployments.apps -o wide
# kubectl set image deploy/nginx nginx=nginx:1.20
# kubectl get deployments.apps -o wide

查看镜像变化过程,由于没有记录无法查看,

1
# kubectl rollout history deployment nginx

操作截图 39

更新镜像时增加–record选项记录更新以方便镜像回滚。

1
2
3
4
# kubectl set image deploy/nginx nginx=nginx:1.20  --record
# kubectl set image deploy/nginx nginx=nginx:1.21 --record
# kubectl rollout history deployment nginx
# kubectl get deployments.apps nginx -o wide

如果变更后的镜像有问题,我们可以把镜像回滚到变更之前的版本,回滚的语法是:

1
2
3
kubectl rollout undo deployment 名字 --to-revision=版本
# kubectl rollout undo deployment nginx --to-revision=5
# kubectl get deployments.apps nginx -o wide

操作截图 40

对deployment可能会有多个pod,使用滚动更新不是一次性全部更新,而是先更新几个pod镜像,更新完成后再更新几个,直至将所有pod全部更新完毕。

rollingUpgrade主要涉及两个参数:

1、maxSurge:指定一次创建几个pod,可以是百分比,也可以是具体数字

2、maxUnavailable:用来指定最多删除几个pod,可以是百分比,也可以是具体数字

1
2
3
4
5
6
# kubectl edit deployments.apps nginx
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate

默认为25%。可修改为1进行查看,即变更镜像时删除一个创建一个。

1
2
3
4
# kubectl scale deployment nginx --replicas=5
# kubectl set image deploy/nginx nginx=nginx:1.21
# kubectl set image deploy/nginx nginx=nginx:1.20
# kubectl get pod

因为docker现在被墙了,其他版本镜像无法拉取

操作截图 41

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

操作截图 42

job练习:计算圆周率小数点后2000位

1
2
3
# kubectl create job job2 --image=perl -- perl -Mbignum=bpi -wle 'print bpi(2000)'
# kubectl get pod
# kubectl get jobs.batch

操作截图 43

操作截图 44

查看计算结果

1
# kubectl logs job2-le3gv

操作截图 45

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
2
3
# kubectl apply -f cjob1.yaml
# kubectl get cronjobs.batch
# kubectl get pod

每隔1分钟生成一个pod,该pod完成任务sleep 30后就结束。

Completed pod数由选项successfulJobsHistoryLimit决定,默认为3。

删除cronjob

1
# kubectl delete cronjobs.batch cjob1

操作截图 46

5.4 StatefulSets

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# vi headless-nginx.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: nginx
# kubectl apply -f headless-nginx.yaml
# vi stateful-nginx.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: nginx
spec:
selector:
matchLabels:
app: nginx
serviceName: "nginx"
replicas: 3
minReadySeconds: 10
template:
metadata:
labels:
app: nginx
spec:
terminationGracePeriodSeconds: 10
containers:
- name: nginx
image: nginx:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
name: web
# kubectl apply -f stateful-nginx.yaml

六、使用命令行和yaml文件创建deployment and job

6.1 deployment

1
2
3
4
5
# kubectl create deployment web1 --image=nginx --dry-run=client -o yaml > web1.yaml
# vi web1.yaml
# kubectl apply -f web1.yaml
# kubectl get deployments.apps -o wide
# kubectl get pod -o wide

操作截图 47

1
# kubectl expose deployment nginx --name=web1 --port=80 --target-port=80

不使用–name指定服务名,则保持和deployment名字一致。

1
--port指服务端口, --target-port是后端pod运行服务的端口。

查看服务

1
2
# kubectl get svc
# kubectl get service -o wide

查看详细信息

1
# kubectl describe service web1

操作截图 48

使用命令生成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

操作截图 49

6.2 服务发布

外部主机访问集群服务主要有三种方式:

1、NodePort

将服务映射到物理机(集群中所有节点)的某个端口提供外界访问

2、LoadBalancer

使用LoadBalancer给svc分配一个地址(外界可访问地址),svc直接对外提供服务。

需要安装部署第三方工具metallb。

3、ingress

使用nginx-ingress实现反向代理,通过域名对外提供服务。

需要安装部署nginx-ingress控制器。

1
2
3
# kubectl expose deployment web1 --name=web1 --port 80 --type=NodePort
# kubectl get svc
# kubectl edit svc web1

Yaml文件为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apiVersion: v1
kind: Service
metadata:
creationTimestamp: null
labels:
app: web1
name: web1
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: web1
type: NodePort
status:
loadBalancer: {}

操作截图 50

七、安装loadblancer

使用LoadBalancer需要安装部署第三方工具metalllb。

1
# kubectl edit configmap -n kube-system kube-proxy

修改 strictARP: true

下载部署metallb所需yaml文件

1
2
3
# mkdir ~/metallb
# cd ~/metallb/
# wget https://raw.githubusercontent.com/metallb/metallb/v0.14.5/config/manifests/metallb-native.yaml

操作截图 51

部署metallb

可以修改配置文件添加imagePullPolicy: IfNotPresent然后进行部署

1
# kubectl apply -f metallb-native.yaml

查看

1
2
3
# kubectl get deployments.apps -n metallb-system
# kubectl get daemonsets.apps -n metallb-system
# kubectl get pod -n metallb-system

操作截图 52

创建一个外部地址池

1
2
3
4
5
6
7
8
9
10
11
12
13
# vi ipaddresspool.yaml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
namespace: metallb-system
name: doc-l2-label
labels:
zone: east
spec:
addresses:
- 192.168.111.135/24
# kubectl apply -f ipaddresspool.yaml
# kubectl get ipaddresspools.metallb.io -n metallb-system

修改地址池范围,指定可用地址

1
2
3
4
# kubectl edit ipaddresspools.metallb.io  -n metallb-system
spec:
addresses:
- 192.168.100.210 - 192.168.100.219

操作截图 53

发布地址池:

1
# vi l2advertisement.yaml

操作截图 54

1
2
# kubectl apply -f l2advertisement.yaml
# kubectl get l2advertisements.metallb.io -n metallb-system

创建一个pod

1
# kubectl run pod1 --image=nginx --image-pull-policy=IfNotPresent

为pod1创建一个名为svc1类型为LoadBalancer的服务

1
2
# kubectl expose pod pod1 --name=svc1 --port=80 --type=LoadBalancer
# kubectl get svc

操作截图 55

访问EXTERNAL-IP即可。

删除svc1和pod1

1
2
# kubectl delete svc svc1
# kubectl delete pod pod1

操作截图 56

八、安装ingress-nginx

官网:https://kubernetes.github.io/ingress-nginx/

1
2
3
4
# mkdir ~/ingress-nginx
# cd ~/ingress-nginx/
# wget http://bigdata.cg.lzu.edu.cn/kubernetes/ingress-nginx/deploy.yaml
# cat deploy.yaml | grep image

所需镜像国内网络无法下载,从国外下载打包回来。并修改yaml文件中镜像名称和实际镜像名称一致。

校内镜像下载: wget http://bigdata.cg.lzu.edu.cn/kubernetes/ingress-nginx-v1.7.0.tar

下载镜像文件并在所有节点加载镜像。并根据实际镜像tag修改deploy.yaml文件。

1
2
# kubectl apply -f deploy.yaml
# kubectl get ns

操作截图 57

1
2
3
# kubectl get pod -n ingress-nginx
# kubectl get svc -n ingress-nginx
# kubectl get configmaps -n ingress-nginx

修改pod副本数为worker数

1
# kubectl scale deployment ingress-nginx-controller -n ingress-nginx --replicas=2

操作截图 58

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
2
# kubectl create ingress pod1.lzu.edu.cn --class=nginx --rule=pod1.lzu.edu.cn/*=pod1:80
# kubectl get ingress

操作截图 59

手动添加解析后访问

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# curl http://pod1.lzu.edu.cn
# kubectl create ingress pod1.lzu.edu.cn --class=nginx --rule=pod1.lzu.edu.cn/*=pod1:80 --dry-run=client -o yaml > pod1.lzu.edu.cn.ymal
# cat pod1.lzu.edu.cn.ymal
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
creationTimestamp: null
name: pod1.lzu.edu.cn
spec:
ingressClassName: nginx
rules:
- host: pod1.lzu.edu.cn
http:
paths:
- backend:
service:
name: pod1
port:
number: 80
path: /
pathType: Prefix
status:
loadBalancer: {}

九、准备NFS server并安装其他服务

nfs-server configure:

1
2
3
4
5
# apt -y install nfs-kernel-server
# mkdir /nfs_data
# vi /etc/exports
/nfs_data 192.168.111.135/24(rw,insecure,no_subtree_check,no_root_squash,crossmnt)
# systemctl restart nfs-server

操作截图 60

1
2
3
# git clone https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner.git
# cd ~/nfs-subdir-external-provisioner/deploy
# vi deployment.yaml

增加镜像下载策略和修改NFS_SERVER和NFS_PATH和nfs server path

操作截图 61

1
2
3
# kubectl apply -f rbac.yaml
# kubectl apply -f deployment.yaml
# kubectl get deployments.apps

操作截图 62

镜像需要从境外下载,下载镜像导入到各工作节点

1
2
# wget http://bigdata.cg.lzu.edu.cn/kubernetes/nfs-subdir-provisioner-v4.0.2.tar
# docker image load -i nfs-subdir-provisioner-v4.0.2.tar (所有节点均需导入)

操作截图 63

1
2
3
4
# kubectl apply -f class.yaml
# kubectl get sc
# kubectl apply -f test-claim.yaml
# kubectl get pvc

操作截图 64

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# cat test-claim.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: test-claim
spec:
storageClassName: nfs-client
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Mi
# cat test-pod.yaml
kind: Pod
apiVersion: v1
metadata:
name: test-pod
spec:
containers:
- name: test-pod
image: busybox:stable
command:
- "/bin/sh"
args:
- "-c"
- "touch /mnt/SUCCESS && exit 0 || exit 1"
volumeMounts:
- name: nfs-pvc
mountPath: "/mnt"
restartPolicy: "Never"
volumes:
- name: nfs-pvc
persistentVolumeClaim:
claimName: test-claim

十、安装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

操作截图 65

添加仓库语法:

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

操作截图 66

操作截图 67

通过helm安装cert-manager

1
2
3
# helm repo add jetstack https://charts.jetstack.io
# kubectl create namespace cert-manager
# kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.7.1/cert-manager.crds.yaml

操作截图 68

1
2
# proxy_host=username:password@proxyserver:port
# helm upgrade --install cert-manager jetstack/cert-manager --namespace cert-manager --version v1.7.1

操作截图 69

查看

1
2
3
# kubectl rollout status deployment -n cert-manager cert-manager
# kubectl get deployments.apps -n cert-manager
# kubectl get pods -n cert-manager

操作截图 70

1
2
# helm repo add rancher-stable https://releases.rancher.com/server-charts/stable
# kubectl create namespace cattle-system

通过文件创建secret

1
# vi mypasswd

操作截图 71

1
# kubectl create secret generic mysecret2 --from-file=mypasswd

查看

1
2
# kubectl get secrets
# kubectl get secrets mysecret2

操作截图 72

看到其类型为Opaque,即使用base64编码格式的secret

1
# kubectl get secrets mysecret2 -o yaml

看到只有一个data,名为mypasswd,内容被base64编码过了

查看

1
2
# kubectl get secrets mysecret2 -o jsonpath='{.data.mypasswd} '
# kubectl get secrets mysecret2 -o jsonpath='{.data.mypasswd}' | base64 -d

操作截图 73

操作截图 74

1
2
3
4
# kubectl apply -f pod1_secret.yaml
# kubectl get pod
# kubectl exec pod1 -- ls /root/mypasswd
# kubectl exec pod1 -- cat /root/mypasswd/mypasswd

通过helm安装cert-manager

1
2
3
4
5
6
7
8
9
# helm repo add jetstack https://charts.jetstack.io
# kubectl create namespace cert-manager
# kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.7.1/cert-manager.crds.yaml
# proxy_host=username:password@proxyserver:port
# helm upgrade --install cert-manager jetstack/cert-manager \
--namespace cert-manager --version v1.7.1 \
--set http_proxy=http://${proxy_host} \
--set https_proxy=http://${proxy_host} \
--set no_proxy=127.0.0.0/8\\,10.0.0.0/8\\,cattle-system.svc\\,172.16.0.0/12\\,192.168.0.0/16\\,.svc\\,.cluster.local

操作截图 75

查看

1
2
3
# kubectl rollout status deployment -n cert-manager cert-manager
# kubectl get deployments.apps -n cert-manager
# kubectl get pods -n cert-manager

操作截图 76

1
2
3
4
5
6
7
8
9
# helm repo add rancher-stable https://releases.rancher.com/server-charts/stable
# kubectl create namespace cattle-system
# kubectl create secret tls lzu-key --cert=lzu2023.crt --key=lzu2023.key -n cattle-system
# helm upgrade -install rancher rancher-stable/rancher \
--namespace cattle-system \
--set hostname=student0.lzu.edu.cn \
--set ingress.tls.source=lzu-key \
--set https_proxy=http://${proxy_host} \
--set no_proxy=127.0.0.0/8\\,10.0.0.0/8\\,cattle-system.svc\\,172.16.0.0/12\\,192.168.0.0/16\\,.svc\\,.cluster.local

操作截图 77

1
# helm upgrade --install rancher rancher-stable/rancher --namespace cattle-system

查看

1
2
3
4
# kubectl rollout status deployment -n cattle-system rancher
# kubectl get deployments.apps -n cattle-system
# kubectl get service -n cattle-system
# kubectl get ingress -n cattle-system

操作截图 78

默认创建的ingress类型不是nginx,没有注册到ingress-nginx-controller,删除重建(rke创建的kubernetes无需此步骤)

1
2
# kubectl delete ingress rancher -n cattle-system
# kubectl create ingress rancher --class=nginx --rule=student0.lzu.edu.cn/*=rancher:80,tsl=lzu-key -n cattle-system

操作截图 79

rancher使用

客户端自行添加域名解析

访问https://student0.lzu.edu.cn

修改设置管理员密码时需满足复杂度要求,默认最小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端口)

操作截图 80

操作截图 81

操作截图 82

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

操作截图 83

此外,还可以在 K8S 上搭建 WordPress,流程和之前单独部署 WordPress 基本一致:

1
2
3
4
# cd /var/www/html/
# wget https://cn.wordpress.org/latest-zh_CN.zip
# dnf install -y unzip
# unzip latest-zh_CN.zip

修改权限

1
# chown -R apache. wordpress/

删除下载文件

1
# rm latest-zh_CN.zip

将wordpress文件放置到apache根目录

1
2
# mv /var/www/html/wordpress/* /var/www/html/
# rmdir /var/www/html/wordpress/

修改wordpress配置文件,配置数据库信息

1
2
# cp /var/www/html/wp-config-sample.php /var/www/html/wp-config.php
# vi /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

操作截图 84

至此,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技能。