k8s环境搭建及使用
环境准备
准备三台节点:一台master,两台node (都为Centos 8 Stream)
规划好IP地址,配置本地yum源
主机名 | IP地址 | 子网掩码 | 网关/DNS |
---|---|---|---|
kmaster | 192.168.146.200 | 255.255.255.0 | 192.168.146.2 |
knode1 | 192.168.146.201 | 255.255.255.0 | 192.168.146.2 |
knode2 | 192.168.146.202 | 255.255.255.0 | 192.168.146.2 |
上传脚本运行
1.上传 Stream8-k8s-v1.30.0.sh 脚本,3台节点都要执行
2. 确定系统的网卡名称,到底是ens160还是ens33,在脚本里面第29行做对应的修改:
hostip=$(ifconfig ens33 |grep -w “inet” |awk ‘{print $2}’)
:set number 按回车键就可以显示行号了,行号显示只是暂时的,退出后就不再显示行号了
确认完网卡名称之后执行:sh Stream8-k8s-v1.30.0.sh
等待脚本执行完之后我们进行初始化集群操作
初始化集群
集群初始化这个操作(命令),只在kmaster节点上执行,其他节点不用管。
我们在kmaster节点 查看一下刚刚的脚本,发现在最后一行有命令被注释掉了,这就是初始化命令
仅在master主机上做集群初始化
执行 kubeadm init --image-repository registry.aliyuncs.com/google_containers --kubernetes-version=v1.30.0 --pod-network-cidr=10.244.0.0/16
添加环境变量(只在kmaster里添加)
直接复制下面的命令粘贴到kmaster里面
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
echo 'export KUBECONFIG=/etc/kubernetes/admin.conf' >> /etc/profile
source /etc/profile
之后执行 kubectl get node
我们看到现在是没有node节点的
在我们做集群初始化的时候最后一条是用来添加 node节点的 将这条命令复制到两个node节点中(knode1和knode2)
kubeadm join 192.168.146.200:6443 --token 1dtkxe.83yfs832s3iqlcj2 \
--discovery-token-ca-cert-hash sha256:7696f8abca7d75f199152ffc5d347bbc61c2b343e4878df44a6cbdd622dedde1
复制过去我们在执行 kubectl get node 会发现两个节点已经添加过来了
目前集群已经搞好了,但是网络插件没有安装。
安装网络插件calico
导入插件,官方提供了两个脚本 operator、custom,按照顺序执行,就会自动的联网拉取dockerhub的calico镜像,启动calico对应的容器。
但是现在无法在线拉取镜像。怎么办,只能选择手工导入这些镜像。
上传并导入calico镜像(3个节点)
上传calico镜像
将这9个tar包上传到三个节点当中
#在kmaster上传之后可以使用这个命令将tar传过去。
scp -r calico 192.168.146.201:/
scp -r calico 192.168.146.202:/
导入calico镜像
ctr -n k8s.io image import apiserver-v3.28.0.tar
ctr -n k8s.io image import cni-v3.28.0.tar csi-v3.28.0.tar
ctr -n k8s.io image import csi-v3.28.0.tar
ctr -n k8s.io image import kube-controllers-v3.28.0.tar
ctr -n k8s.io image import node-driver-registrar-v3.28.0.tar
ctr -n k8s.io image import node-v3.28.0.tar
ctr -n k8s.io image import operator-v1.34.0.tar
ctr -n k8s.io image import pod2daemon-flexvol-v3.28.0.tar
ctr -n k8s.io image import typha-v3.28.0.tar
三个节点同样的操作,安装完了验证一下。crictl images
执行calico脚本(只在kmaster)
将两个yaml文件脚本上传到kmaster上,其他节点不管
上传到kmaster之后执行下面两条命令
kubectl create -f tigera-operator-v3.28.0.yaml
kubectl create -f custom-resources-v3.28.0.yaml
watch -n 1 kubectl get pod -n calico-system
动态观察容器状态,全部变为running,说明网络插件完全安装好了。退出ctrl+c
全部关机打个快照
命令补全
在kmaster节点中,在/etc/profile
里添加source <(kubectl completion bash)
然后source一下,这样我们在输入命令的时候能用Tab键补全
[root@kmaster ~]# vim /etc/profile
source <(kubectl completion bash)#添加这段
[root@kmaster ~]# source /etc/profile
命名空间 namespace
k8s里面的大部分对象资源,都是通过ns做隔离的。容器可以分布在不同的节点,但是这些容器有可能属于同一个ns。
我们通常更换ns需要的命令较为繁琐,我们上传一个脚本,对它加上一定的权限,这就使得我们在更换命名空间的时候更为简便。
[root@kmaster ~]# ls
anaconda-ks.cfg calico kubens Stream8-k8s-v1.30.0.sh
[root@kmaster ~]# mv kubens /bin/
[root@kmaster ~]# chmod +x /bin/kubens
[root@kmaster ~]# kubens
calico-apiserver
calico-system
default
kube-node-lease
kube-public
kube-system
tigera-operator
- 上传kubens
- 将kubens移动到/bin
- 对/bin/kubens添加权限
pod
pod是k8s集群中管理的最小单元,它相当于是一个穿了衣服的容器,但是通常我们所说一个pod就是一个容器,当然一个pod里也允许有多个容器,默认一个pod里有一个容器。
创建pod
创建pod的方式:1.命令行方式 2.yaml文件方式创建
命令行:
kubectl run pod1 --image registry.cn-hangzhou.aliyuncs.com/haoxiansheng/nginx
[root@kmaster ~]# kubectl run pod1 --image registry.cn-hangzhou.aliyuncs.com/haoxiansheng/nginx
pod/pod1 created
#查看当下pod
[root@kmaster ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
pod1 0/1 ContainerCreating 0 11s
#查看pod具体信息
[root@kmaster ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod1 1/1 Running 0 24s 10.244.195.133 knode1 <none> <none>
现在创建好了,怎么删除pod,删除pod方式有很多这里就说一个,剩下的可以自己研究一下
kubectl delete pod pod1
执行玩这条命令我们发现创建的pod1 已经被删除了。
我们看到下面这条命令–image 这个是拉取镜像,后面是镜像地址,只有这样我们才能创建pod。
kubectl run pod1 --image registry.cn-hangzhou.aliyuncs.com/haoxiansheng/nginx
但是在拉取镜像的时候,有三种镜像拉取策略:1.Always 2.IfNotPresent 3.Never。
Always:不管本地有没有镜像,都会联网去检查有没有更新(触发联网动作)。
IfNotPresent:如果本地有,直接使用本地;如果没有,则自动联网下载。
Never:不会联网下载,前提必须本地有镜像,直接用本地,本地没有,直接报错。
我们默认使用的是IfNotPresent,如果要指定kubectl run pod1 --image registry.cn-hangzhou.aliyuncs.com/haoxiansheng/nginx --image-pull-policy Never
。
yaml文件方式创建
我们首先要知道yaml文件格式非常严格,他需要所有的命令以空格来对齐,不能使用Tab来对齐。
我们要生成yaml文件需要用到--dry-run
这个参数,这个参数一共有三个参数值:1.none 2.client 3. server
--dry-run
主要用于测试当前命令语句,不会真正的在集群里面去执行操作。
--dry-run=server
:如果server,当前语句要发送给kube-api组件,这个语句需要拿到后端去模拟运行,后端服务端会生成很多很多参数的。这些参数很多我们用不到。
--dry-run=client
:语句就不会发送到后端kube-api,而是直接在客户端本地运行,生成的参数就会少很多,也方便我们去编辑。
不管是server还是client选项,只要带了--dry-run
它就不会真正的执行语句。
现在我们通过这个--dry-run
来创建我们的yaml文件
[root@kmaster ~]# kubectl run pod1 --image registry.cn-hangzhou.aliyuncs.com/haoxiansheng/nginx --image-pull-policy IfNotPresent --dry-run=client -o yaml >pod1.yaml
[root@kmaster ~]# ls
anaconda-ks.cfg calico pod1.yaml Stream8-k8s-v1.30.0.sh
下面就是pod1.yaml
文件,现在我们用yaml文件来执行 看看容器是否能创建出来
这里看到倒数第二行有个restartpolicy
这是重启策略
restartpolicy
一共有3种
Always
:总是,一直,不管正常退出,还是非正常退出,都会重启
Never
:不管正常还是不正常退出,都不重启
OnFailure
:正常退出不重启,非正常退出重启
我们先查看有没有pod1,有的话删除,然后通过pod1.yaml
进行创建,可以通过apply
和create
来创建
create用于该资源是首次创建的时候,一旦资源存在,再次使用create直接报错。
apply不管资源是不是首次创建,都可以使用,可以使用apply重复执行。
[root@kmaster ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
pod1 1/1 Running 0 22m
[root@kmaster ~]# kubectl delete pod pod1
pod "pod1" deleted
[root@kmaster ~]# kubectl apply -f pod1.yaml
pod/pod1 created
[root@kmaster ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
pod1 1/1 Running 0 11s
[root@kmaster ~]#
进入pod
[root@kmaster ~]# kubectl exec -ti pod1 -- bash
root@pod1:/#
标签
主机标签
[root@kmaster ~]# kubectl get nodes --show-labels
NAME STATUS ROLES AGE VERSION LABELS
kmaster Ready control-plane 25h v1.30.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=kmaster,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node.kubernetes.io/exclude-from-external-load-balancers=
knode1 Ready <none> 25h v1.30.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=knode1,kubernetes.io/os=linux
knode2 Ready <none> 25h v1.30.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=knode2,kubernetes.io/os=linux
[root@kmaster ~]#
通过kubectl get nodes --show-labels
查看主机标签,这个标签可以添加、删除,也可以通过这个标签来发放到指定的节点。
例如:给knode2添加标签disk=ssd
[root@kmaster ~]# kubectl label nodes knode2 disk=ssd
node/knode2 labeled
[root@kmaster ~]# kubectl get nodes --show-labels
NAME STATUS ROLES AGE VERSION LABELS
kmaster Ready control-plane 25h v1.30.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=kmaster,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node.kubernetes.io/exclude-from-external-load-balancers=
knode1 Ready <none> 25h v1.30.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=knode1,kubernetes.io/os=linux
knode2 Ready <none> 25h v1.30.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disk=ssd,kubernetes.io/arch=amd64,kubernetes.io/hostname=knode2,kubernetes.io/os=linux
通过和上面的对比,我们发现knode2上多了一个disk=ssd
的标签
如果要删除这个标签:kubectl label nodes knode2 disk-
这样就可以删除了,标签的排序是按照字母顺序排序的。
那么我们怎么通过标签来发放pod到knode2上呢?
我们需要用到 nodeSelector
,指定发布到带有disk=ssd
标签的主机节点上
这样我们在创建pod的时候就会发布到knode2
上
pod标签
查询pod标签:kubectl get pod --show-labels
[root@kmaster ~]# kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
pod1 1/1 Running 0 3m2s run=pod1
我们看到pod1
的标签是run=pod1
在这个基础上,给他添加几个标签aaa=bbb、xxx=yyy、abc=123。
这样再次创建pod,就会添加标签到pod标签中。
特殊的标签 ROLES
这个标签没有什么意义,只是给我们看,我们可以设置他的标签,这样在调node的时候一目了然
[root@kmaster ~]# kubectl get node
NAME STATUS ROLES AGE VERSION
kmaster Ready control-plane 26h v1.30.0
knode1 Ready <none> 25h v1.30.0
knode2 Ready <none> 25h v1.30.0
[root@kmaster ~]# kubectl label nodes kmaster node-role.kubernetes.io/control-plane-
node/kmaster unlabeled
[root@kmaster ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
kmaster Ready <none> 26h v1.30.0
knode1 Ready <none> 25h v1.30.0
knode2 Ready <none> 25h v1.30.0
现在看到这个 control-plane
已经被删除了
添加master、node1、node2到这三个节点
[root@kmaster ~]# kubectl label nodes kmaster node-role.kubernetes.io/master=
node/kmaster labeled
[root@kmaster ~]# kubectl label nodes knode1 node-role.kubernetes.io/node1=
node/knode1 labeled
[root@kmaster ~]# kubectl label nodes knode2 node-role.kubernetes.io/node2=
node/knode2 labeled
[root@kmaster ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
kmaster Ready master 26h v1.30.0
knode1 Ready node1 26h v1.30.0
knode2 Ready node2 26h v1.30.0
存储管理
本地存储(两种类型)
emptyDir
临时的,删除pod的时候,也会随之删除
对于emptyDir来说,会在pod所在的物理机上生成一个随机目录。pod的容器会挂载到这个随机目录上。当pod容器删除后,随机目录也会随之删除。适用于多个容器临时共享数据。
为什么说它是临时的,我们在删除pod的时候这个目录也会被删除,abc也就看不到了(可以自行实验一下)。
我们通过yaml文件来设置
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: pod1
aaa: bbb
xxx: yyy
abc: '123'
name: pod1
spec:
volumes:
- name: v1
emptyDir: {}
containers:
- image: registry.cn-hangzhou.aliyuncs.com/haoxiansheng/nginx
imagePullPolicy: IfNotPresent
name: pod1
resources: {}
volumeMounts:
- name: v1
mountPath: /abc
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
[root@kmaster ~]# kubectl create -f pod1.yaml
pod/pod1 created
[root@kmaster ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
pod1 1/1 Running 0 8s
[root@kmaster ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod1 1/1 Running 0 21s 10.244.195.135 knode1 <none> <none>
[root@kmaster ~]# kubectl exec -ti pod1 -- bash
root@pod1:/# cd /abc
root@pod1:/abc# touch abc.txt
root@pod1:/abc# ls
abc.txt
root@pod1:/abc# exit
exit
我们在abc目录下创建一个abc.txt,这时候我们再去knode1查找会发现我们的abc目录下面有abc.txt,但是这个效果和上面的一样,当我们删除pod时,这个abc.txt也会被删除
hotpath
永久保留的 删除之后pod,数据依然存在
yaml文件:
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: pod1
aaa: bbb
xxx: yyy
abc: '123'
name: pod1
spec:
volumes:
- name: v1
emptyDir: {}
- name: v2
hostPath:
path: /web
containers:
- image: registry.cn-hangzhou.aliyuncs.com/haoxiansheng/nginx
imagePullPolicy: IfNotPresent
name: pod1
resources: {}
volumeMounts:
- name: v2
mountPath: /abc
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
当我们删除pod1时 在看一下/web还是会有
网络存储(NFS为例)
对接网络存储,
-
创建一个linux,加一块50GB的硬盘。
-
关闭防火墙和selinux
关闭防火墙
systemctl stop firewalld
systemctl disable firewalld
永久关闭SELinux:要永久关闭SELinux,需要编辑vi /etc/sysconfig/selinux
文件,并将SELINUX的值改为disabled
,然后重启系统。
- 安装软件包(配置yum源之后)
配置本地yum源
挂载ios到/mnt/下
mount /dev/cdrom /mnt/
到yum源下面,把失效的yum源移到自己创建的bak下
cd /etc/yum.repos.d/
mkdir bak
mv *.repo bak/
创建abc.repo
vi abc.repo
将下面的配置写道abc.repo里面
[abc]
name = abc
baseurl = file:///mnt/AppStream/
gpgcheck = 0
[os]
name = os
baseurl = file:///mnt/BaseOS/
gpgcheck = 0
yum install -y yum-utils vim bash-completion net-tools wget nfs-utils
- 启动服务
[root@nfs ~]# systemctl start nfs-server.service
[root@nfs ~]# systemctl enable nfs-server.service
- 创建linux时,多给他分配一块50G的硬盘,将新的硬盘分区格式化并挂载
[root@nfs yum.repos.d]# fdisk -l
Disk /dev/sda: 100 GiB, 107374182400 bytes, 209715200 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xa133529c
Device Boot Start End Sectors Size Id Type
/dev/sda1 * 2048 2099199 2097152 1G 83 Linux
/dev/sda2 2099200 209715199 207616000 99G 8e Linux LVM
********这里能看到我们新建的硬盘50G**************
Disk /dev/sdb: 50 GiB, 53687091200 bytes, 104857600 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
我这块硬盘叫sdb注意查看你们的。
fdisk /dev/sdb
输入一个n,之后回车回车回车,输入一个q。
mkfs.xfs /dev/sdb
之后我们创建一个目录,将新盘挂载到这个目录上
mkdir /share_data
查询这块硬盘的UUID,用这个UUID来挂载。
[root@nfs yum.repos.d]# blkid
/dev/sdb: UUID="e46293af-5747-41a0-9576-09ff4540e3cc" BLOCK_SIZE="512" TYPE="xfs"
vim /etc/fstab
这样就挂载好了,现在对这个硬盘进行共享。
- 编辑共享目录
/etc/exports
这个目录是Linux当中专门用于共享的。
[root@nfs ~]# vim /etc/exports
[root@nfs ~]# cat /etc/exports
/share_data *(rw,async,no_root_squash)
解析:1. /share_data 共享这个目录
2. *代表所有网段都可访问这个目录,若要指定,可以将*替换为指定网段192.168.100.0/24
3. rw读写方式访问
4. async异步读写访问,多节点,不需要返回结果,只需要写入
5. no_rot_squash:登入 NFS 主机使用分享目录的使用者,如果是root 的话,那么对于这个分享的目录来说,他就具有 root 的权限!这个项目「极不安全」,不建议使用。以root身份写。
[root@nfs ~]# exportfs -arv 直接使用这条命令刷新,不用重启服务就能生效。
exporting *:/share_data
- node安装nfs-utils
虽然未来的pod要连接nfs,但是真正连接nfs的是pod所在的物理主机。所以作为物理主机(客户端)也要安装nfs客户端。
yum install -y nfs-utils
- 测试挂载
[root@knode1 yum.repos.d]# umount /mnt
[root@knode1 yum.repos.d]# mount -t nfs 192.168.146.132:/share_data /mnt
[root@knode1 yum.repos.d]# df -TH
192.168.146.132:/share_data nfs4 54G 408M 54G 1% /mnt
- 创建pod
修改pod1.yaml文件
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: pod1
aaa: bbb
xxx: yyy
abc: '123'
name: pod1
spec:
volumes:
- name: v1
emptyDir: {}
- name: v2
hostPath:
path: /web
- name: v3
nfs:
server: 192.168.146.132
path: /share_data
containers:
- image: registry.cn-hangzhou.aliyuncs.com/haoxiansheng/nginx
imagePullPolicy: IfNotPresent
name: pod1
resources: {}
volumeMounts:
- name: v3
mountPath: /abc
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
创建pod,并在pod1里的 /abc 下创建了aaabbb.txt
[root@kmaster ~]# kubectl apply -f pod1.yaml
pod/pod1 created
[root@kmaster ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod1 1/1 Running 0 11s 10.244.195.141 knode1 <none> <none>
[root@kmaster ~]# kubectl exec -ti pod1 -- bash
root@pod1:/# cd /abc
root@pod1:/abc# ls
root@pod1:/abc# touch aaabbb.txt
root@pod1:/abc#
我们在nfs端也看到了aaabbb.txt
[root@nfs ~]# cd /share_data
[root@nfs share_data]# ls
aaabbb.txt