k8s作为分布式集群部署方案,是一个主流的部署方案。
1. 服务器配置
至少准备3台服务器,首先修改服务器名称
hostnamectl set-hostname k8s-master
hostnamectl set-hostname k8s-node1
hostnamectl set-hostname k8s-node2
将集群ip与名称写入hosts文件
echo '''
10.30.239.157 k8s-master
10.30.239.158 k8s-node1
10.30.239.159 k8s-node2
''' >> /etc/hosts
然后关闭防火墙和selinux
systemctl stop firewalld
setenforce 0
禁用swap分区,swap为0即禁用成功
swapoff -a
free -mh
添加网桥过滤和地址转发功能
cat > /etc/sysctl.d/kubernetes.conf << EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
EOF
sysctl --system
配置集群节点的免密登录
ssh-keygen -t rsa
scp -p ~/.ssh/id_rsa.pub root@k8s-node1:/root/.ssh/authorized_keys
scp -p ~/.ssh/id_rsa.pub root@k8s-node2:/root/.ssh/authorized_keys
2. yum源配置
由于本次部署的服务器为中标麒麟7.6版,首先进行yum源的配置。
配置kubernetes的yum源
vi /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
配置docker-ce的yum源。
wget -O /etc/yum.repos.d/docker-ce.repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
下载centos7的repo文件。
curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo
需要注意的是将docker-ce、centos的repo文件中的所有$releasever修改为7,否则会报错。
baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos/7/os/$basearch/
yum源配置完成后,重新生成缓存
yum clean all
yum makecache
3. 安装kubernetes集群
3.1 安装kubeadm
执行如下命令,进行kubeadm等环境的安装。
yum install -y kubelet kubeadm kubectl
若报错:“Couldn’t open file /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7”
处理方法:
cd /etc/pki/rpm-gpg
wget https://www.centos.org/keys/RPM-GPG-KEY-CentOS-7 --no-check-certificate
安装完毕后,启动kubelet,此时会显示启动失败,不用处理。
systemctl start kubelet
systemctl enable kubelet
systemctl status kubelet
3.2 安装docker-ce
容器运行时环境通常是Docker,k8s版本 ≥ v1.24需要额外安装cri-dockerd。
yum install docker-ce docker-ce-cli containerd.io -y
配置镜像加速
cat<< EOF > /etc/docker/daemon.json
{
"registry-mirrors": ["https://gpkhi0nk.mirror.aliyuncs.com"],
"data-root": "/data/docker",
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file": "4"
}
}
EOF
启动docker
systemctl daemon-reload
systemctl start docker
systemctl enable docker
3.3. cri-dockerd安装
下载cri-dockerd安装包,并设置自启动。
wget https://github.com/Mirantis/cri-dockerd/releases/download/v0.3.4/cri-dockerd-0.3.4-3.el7.x86_64.rpm
rpm -ivh cri-dockerd-0.3.4-3.el7.x86_64.rpm
注意k8s的1.28版本拉取镜像时会报错:detected that the sandbox image “registry.k8s.io/pause:3.6” of the container runtime is inconsistent with that used by kubeadm
在所有节点上进行处理:
systemctl stop cri-docker
vi /usr/lib/systemd/system/cri-docker.service
修改ExecStart配置,重启 cri-dockerd
ExecStart=/usr/bin/cri-dockerd --container-runtime-endpoint fd:// --pod-infra-container-image=registry.aliyuncs.com/google_containers/pause:3.9
systemctl daemon-reload
systemctl enable cri-docker.socket cri-docker
systemctl start cri-docker.socket cri-docker
systemctl status cri-docker.socket
3.4 kubeadm master节点初始化
–cri-socket:处理docker和cri的兼容问题
–image-repository:添加k8s镜像国内仓库地址
kubeadm init --cri-socket unix:///var/run/cri-dockerd.sock --image-repository=registry.aliyuncs.com/google_containers
重启之后reset,在执行init
kubeadm reset --cri-socket unix:///var/run/cri-dockerd.sock
日志内容如下表明初始化成功。
执行如下命令,将刚刚部署生成的 Kubernetes 集群的安全配置文件,保存到当前用户的.kube 目录。
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
查看k8s集群状态,此时集群处于NotReady的状态,需要通过calico进行网络支撑
kubectl get nodes
3.5 calico安装
wget https://docs.projectcalico.org/manifests/calico.yaml --no-check-certificate
kubectl apply -f calico.yaml
# kube-system 是 Kubernetes 项目预留的系统 Pod 的工作空间,Namepsace
kubectl get pod -n kube-system
确认所有pod都处于runing状态
3.6 加入worker节点
在worker节点服务器上,将worker节点加进master节点
kubeadm join 10.30.239.157:6443 --token l4qooc.gcxyc46dkpo8ehqk --discovery-token-ca-cert-hash sha256:f359197c8932beb29f85b04f26e4bfe7ed3e1f1cbe94c4afddb855c619325844 --cri-socket unix:///var/run/cri-dockerd.sock
node节点打标签,显示为work
kubectl label nodes k8s-node1 node-role.kubernetes.io/work=work
kubectl label nodes k8s-node2 node-role.kubernetes.io/work=work
查看集群状态,所有节点都处于ready状态
3.7 部署 Dashboard
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-rc6/aio/deploy/recommended.yaml
# 查看是否创建成功
kubectl get pods --all-namespaces
配置浏览器访问
kubectl get svc --all-namespaces
kubectl delete service kubernetes-dashboard --namespace=kubernetes-dashboard
vi dashboard-svc.yaml
kind: Service
apiVersion: v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kubernetes-dashboard
spec:
type: NodePort
ports:
- port: 443
targetPort: 8443
selector:
k8s-app: kubernetes-dashboard
创建Pod
kubectl apply -f dashboard-svc.yaml
创建kubernetes-dashboard管理员
vi dashboard-svc-account.yaml
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: dashboard-admin
subjects:
- kind: ServiceAccount
name: dashboard-admin
namespace: kube-system
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
kubectl apply -f dashboard-svc-account.yaml
查看浏览器访问端口,https://master_ip:port/#/login,采用token访问
kubectl get svc --all-namespaces
# 获取token
kubectl -n kubernetes-dashboard create token kubernetes-dashboard
浏览器页面报错:secrets is forbidden: User “system:serviceaccount:kubernetes-dashboard:kubernetes-dashboard” cannot list resource “secrets” in API group “” in the namespace “default”。
安装yaml时,已创建了一个用户kubernetes-dashboard,可通过如下命令查看其详情
kubectl describe serviceaccount/kubernetes-dashboard -n kubernetes-dashboard
kubernetes 集群安装好后,会自动生成一些 clusterroles 集群权限对象,可以用下面的命令查看。
kubectl get clusterroles
查看集群管理员详情,*号表示对所有资源有所有权限
kubectl describe clusterroles cluster-admin
将服务账户 kubernetes-dashboard 跟 cluster-admin 集群管理员权限对象绑定
vi kubernetes-dashboard-ClusterRoleBinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: kubernetes-dashboard
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: kubernetes-dashboard
namespace: kubernetes-dashboard
kubectl apply -f kubernetes-dashboard-ClusterRoleBinding.yaml
若报错:cannot change roleRef,则执行如下命令,删除后再重新创建
kubectl delete -f kubernetes-dashboard-ClusterRoleBinding.yaml
查看是否创建成功
kubectl get clusterrolebindings kubernetes-dashboard
重新登录后,dashbord页面即可正常显示
3.8 搭建docker 私有仓库
由于经常需要再离线环境中使用预先准备的image,因此学习下如何搭建私有仓库
docker pull docker.io/registry
启动registry容器
docker run -d -p 5000:5000 --restart always --name registry -v /home/images:/var/lib/registry -e REGISTRY_STORAGE_DELETE_ENABLED="true" registry:latest
在浏览器上访问:http://ip:5000/v2/_catalog,此时提示仓库为空。
配置信任源,让docker使用http协议,重启docker
vi /etc/docker/daemon.json
{
"insecure-registries" : [ "ip:5000" ]
}
systemctl restart docker
将预先准备的镜像加载至docker
docker load --input /opt/web.tar
打tag,并推送至仓库
docker tag web:20231130 <ip>:5000/web:20231130
docker push <ip>:5000/web:20231130
出现该提示即推送成功
curl -XGET -s http://ip:5000/v2/_catalog | python -m json.tool
3.9 nfs挂载
k8s通过pv与pvc进行持久化存储,创建pv.yaml, pvc.yaml,需要注意的是pvc中storageClassName参数需要与绑定的pv值一致,且storage不得超过pv的storage值
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs
spec:
storageClassName: manual
capacity:
storage: 1Gi
accessModes:
- ReadWriteMany
nfs:
server: 10.30.239.159
path: "/opt/data"
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nfs
spec:
accessModes:
- ReadWriteMany
storageClassName: manual
resources:
requests:
storage: 1Gi
在所有需要挂载nfs服务的集群节点上执行如下命令:
yum install nfs-utils -y
systemctl start nfs
在远程共享存储服务器上安装nfs,并将挂载目录授权给集群节点使用
vim /etc/exports
/opt/data 10.30.239.159(rw,sync,no_subtree_check,no_root_squash,insecure)
创建pv与pvc的pod
kubectl apply -f k8s/pv.yaml
kubectl apply -f k8s/pvc.yaml
4. 测试部署nginx
kubectl create deployment nginx --image=nginx
kubectl expose deployment nginx --port=80 --type=NodePort
kubectl get service
通过浏览器访问,http://<集群任一ip>:/
5. 常用命令与处理
#查看pod状态
# -owide:查看更多信息,如ip等
# -n:指定命名空间
kubectl get pod -n kube-system
删除pod
kubectl delete pod <pod_name>
删除pod时,由于replicas机制,可能导致pod会被自动重新创建,此时,必须删除Pod控制器
# 查看Pod控制器
kubectl get deploy
# 删除控制器
# pod会被自动删除
kubectl delete deploy <deploy_name>
非master节点执行上述命令时报错:The connection to the server localhost:8080 was refused
处理方法:
# 将master上的admin.conf复制到worker节点
scp /etc/kubernetes/admin.conf root@k8s-node2:/etc/kubernetes/admin.conf
# 在非master节点上执行
echo "export KUBECONFIG=/etc/kubernetes/admin.conf" >> ~/.bash_profile
source ~/.bash_profile
6. sealos部署k8s
安装sealos
wget https://github.com/labring/sealos/releases/download/v4.1.3/sealos_4.1.3_linux_amd64.tar.gz
tar zxvf sealos_4.1.3_linux_amd64.tar.gz sealos
chmod +x sealos
cp sealos /usr/bin
sealos version
部署命令:
sealos init \
--master 192.168.0.2 \
--master 192.168.0.3 \
--master 192.168.0.4 \ # master地址列表
--node 192.168.0.5 \ # node地址列表
--user root \ # 服务用户名
--passwd your-server-password \ # 服务器密码,用于远程执行命令
--pkg kube1.14.1.tar.gz \ # 离线安装包名称
--version v1.14.1 # kubernetes 离线安装包版本,这渲染kubeadm配置时需要使用
7. 使用k8s启动django服务
编写yaml文件
apiVersion: apps/v1
kind: Deployment
metadata:
name: django-example
labels:
app: django-example
spec:
replicas: 1
selector:
matchLabels:
app: django-example
template:
metadata:
labels:
app: django-example
spec:
containers:
- name: web-app
image: django-example:v1.0
ports:
- containerPort: 80
创建pod
kubectl apply -f django.yaml
查看pod
kubectl get pod
若pod创建失败,采用如下命令查看失败详情
kubectl describe po <pod_name>
进入pod
kubectl exec -it <pod_name> -- /bin/sh
空命令,避免报错:Back-off restarting failed container web-app in pod
command: [ "/bin/bash", "-c", "--" ]
args: [ "while true; do sleep 30; done;" ]
8. 定时任务调度
编写job.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
name: hello
spec:
schedule: "*/1 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: hello
image: busybox
args:
- /bin/sh
- -c
- date; echo Hello from the Kubernetes cluster
restartPolicy: OnFailure
查看与删除cronjob
kubectl get cronjob
kubectl delete cronjob hello
查看cronjob的执行记录
kubectl get jobs --watch
查看某次执行的日志
pods=$(kubectl get pods --selector=job-name=hello-28394362 --output=jsonpath={.items..metadata.name})
kubectl logs $pods
附录
yaml格式的pod定义文件完整内容说明
apiVersion: v1 #必选,版本号,例如v1
kind: Pod #必选,Pod
metadata: #必选,元数据
name: string #必选,Pod名称
namespace: string #必选,Pod所属的命名空间
labels: #自定义标签
- name: string #自定义标签名字
annotations: #自定义注释列表
- name: string
spec: #必选,Pod中容器的详细定义
containers: #必选,Pod中容器列表
- name: string #必选,容器名称
image: string #必选,容器的镜像名称
imagePullPolicy: [Always | Never | IfNotPresent] #获取镜像的策略 Alawys表示下载镜像 IfnotPresent表示优先使用本地镜像,否则下载镜像,Nerver表示仅使用本地镜像
command: [string] #容器的启动命令列表,如不指定,使用打包时使用的启动命令
args: [string] #容器的启动命令参数列表
workingDir: string #容器的工作目录
volumeMounts: #挂载到容器内部的存储卷配置
- name: string #引用pod定义的共享存储卷的名称,需用volumes[]部分定义的的卷名
mountPath: string #存储卷在容器内mount的绝对路径,应少于512字符
readOnly: boolean #是否为只读模式
ports: #需要暴露的端口库号列表
- name: string #端口号名称
containerPort: int #容器需要监听的端口号
hostPort: int #容器所在主机需要监听的端口号,默认与Container相同
protocol: string #端口协议,支持TCP和UDP,默认TCP
env: #容器运行前需设置的环境变量列表
- name: string #环境变量名称
value: string #环境变量的值
resources: #资源限制和请求的设置
limits: #资源限制的设置
cpu: string #Cpu的限制,单位为core数,将用于docker run --cpu-shares参数
memory: string #内存限制,单位可以为Mib/Gib,将用于docker run --memory参数
requests: #资源请求的设置
cpu: string #Cpu请求,容器启动的初始可用数量
memory: string #内存请求,容器启动的初始可用数量
livenessProbe: #对Pod内个容器健康检查的设置,当探测无响应几次后将自动重启该容器,检查方法有exec、httpGet和tcpSocket,对一个容器只需设置其中一种方法即可
exec: #对Pod容器内检查方式设置为exec方式
command: [string] #exec方式需要制定的命令或脚本
httpGet: #对Pod内个容器健康检查方法设置为HttpGet,需要制定Path、port
path: string
port: number
host: string
scheme: string
HttpHeaders:
- name: string
value: string
tcpSocket: #对Pod内个容器健康检查方式设置为tcpSocket方式
port: number
initialDelaySeconds: 0 #容器启动完成后首次探测的时间,单位为秒
timeoutSeconds: 0 #对容器健康检查探测等待响应的超时时间,单位秒,默认1秒
periodSeconds: 0 #对容器监控检查的定期探测时间设置,单位秒,默认10秒一次
successThreshold: 0
failureThreshold: 0
securityContext:
privileged:false
restartPolicy: [Always | Never | OnFailure]#Pod的重启策略,Always表示一旦不管以何种方式终止运行,kubelet都将重启,OnFailure表示只有Pod以非0退出码退出才重启,Nerver表示不再重启该Pod
nodeSelector: obeject #设置NodeSelector表示将该Pod调度到包含这个label的node上,以key:value的格式指定
imagePullSecrets: #Pull镜像时使用的secret名称,以key:secretkey格式指定
- name: string
hostNetwork:false #是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主机网络
volumes: #在该pod上定义共享存储卷列表
- name: string #共享存储卷名称 (volumes类型有很多种)
emptyDir: {} #类型为emtyDir的存储卷,与Pod同生命周期的一个临时目录。为空值
hostPath: string #类型为hostPath的存储卷,表示挂载Pod所在宿主机的目录
path: string #Pod所在宿主机的目录,将被用于同期中mount的目录
secret: #类型为secret的存储卷,挂载集群与定义的secre对象到容器内部
scretname: string
items:
- key: string
path: string
configMap: #类型为configMap的存储卷,挂载预定义的configMap对象到容器内部
name: string
items:
- key: string
path: string
items:
- key: string
path: string
configMap: #类型为configMap的存储卷,挂载预定义的configMap对象到容器内部
name: string
items:
- key: string
path: string