markdown文档笔记下载地址:https://install-data.oss-cn-hongkong.aliyuncs.com/%E7%AC%94%E8%AE%B0/kubernetes%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0.md
1.搭建kubernetes集群
Kubernetes 组件介绍
- 一个 kubernetes 集群主要由控制节点(master)、工作节点(node)构成,每个节点上都会安装不同的组件。
- 控制节点(master):集群的控制平面,负责集群的决策。
-
- API Server:集群操作的唯一入口,接收用户输入的命令,提供认证、授权、API注册和发现等机制,同时协调各组件的工作。
-
- Scheduler:负责集群资源调度,按照预定的调度策略将 Pod 调度到相应的 node 节点上。
-
- ControllerManager:负责维护集群的状态,比如程序部署安排、故障检测、自动扩展和滚动更新等。
-
- Etcd:负责存储集群中各种资源对象的信息。
- 工作节点(node):集群的数据平面,负责为容器提供运行环境。
-
- Kubelet:负责维护容器的生命周期,即通过控制 Docker ,来创建、更新、销毁容器。
-
- KubeProxy:负责提供集群内部的服务发现和负载均衡。
-
- Docker:负责节点上容器的各种操作。
- 部署网络组件的作用?
实现容器跨主机网络通信 - 容器接口
CNI 容器网络接口
CRI 容器运行时接口 (对接容器接口)
CSI 容器存储接口
- k8s弃用docker前,与弃用后
k8s -> docker-shim/cri -> docker (有dockershim,默认能兼容docker)
k8s -> cri -> docker(支持cri) (后期需要docker去兼容对接 CRI)
1.1.环境准备
master 192.168.3.124 node1 192.168.3.125 node2 192.168.3.126 关闭防火墙 systemctl stop firewalld systemctl disable firewalld #关闭selinux sed -i 's/enforcing/disabled/' /etc/selinux/config # 永久 setenforce 0 # 临时 #关闭swap swapoff -a # 临时 sed -ri 's/.*swap.*/#&/' /etc/fstab # 永久,sed中&,经常用来在原文本下增加字符串,其中&就相当于要被替换".*swap.* swapoff -a && swapon -a #刷新swp (在初始化得时候如果常出现swp报错请重启服务器,然后再执行一遍关闭swp得命令) #修改主机名,修改hosts vim /etc/hosts 192.168.3.124 master 192.168.3.125 node01 192.168.3.126 node02 #将桥接ipv4流量传递到iptables的链上 cat > /etc/sysctl.d/k8s.conf << EOF net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 net.ipv4.ip_nonlocal_bind = 1 net.ipv4.ip_forward = 1 EOF sysctl --system # 生效 #时间同步 yum install -y ntpdate timedatectl set-timezone Asia/Shanghai 在kubernetes中service有两种代理模型,一种是基于iptables,另一种是基于ipvs的。ipvs的性能要高于iptables的,但是如果要使用它,需要手动载入ipvs模块。 修改内核参数: cat <<EOF > /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 net.ipv4.ip_nonlocal_bind = 1 net.ipv4.ip_forward = 1 EOF sysctl -p /etc/sysctl.d/k8s.conf 1)加载ipvs: [root@k8s-master ~] mkdir /opt/ipvs && cd /opt/ipvs [root@master ipvs] yum -y install ipset ipvsadm sysstat conntrack libseccomp [root@master ipvs] vim ipvs.sh #!/bin/bash modprobe -- ip_vs modprobe -- ip_vs_sh modprobe -- ip_vs_rr modprobe -- ip_vs_wrr modprobe -- nf_conntrack_ipv4 #执行脚本 [root@master ipvs] chmod +x ipvs.sh [root@master ipvs] bash ipvs.sh 2)让脚本开机自启: [root@master ipvs]# lsmod |grep ip_vs ip_vs_wrr 12697 0 ip_vs_rr 12600 0 ip_vs_sh 12688 0 ip_vs 6 ip_vs_rr,ip_vs_sh,ip_vs_wrr nf_conntrack 9 ip_vs,nf_nat,nf_nat_ipv4,nf_nat_ipv6,xt_conntrack,nf_nat_masquerade_ipv4,nf_conntrack_netlink,nf_conntrack_ipv4,nf_conntrack_ipv6 libcrc32c 12644 4 xfs,ip_vs,nf_nat,nf_conntrack [root@master ipvs]# echo "bash /opt/ipvs/ipvs.sh" >>/etc/rc.local [root@master ipvs]# chmod +x /etc/rc.local
讯享网
1.2.安装docker(每台都执行)
讯享网yum -y install yum-utils device-mapper-persistent-data lvm2 yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo yum-config-manager --enable docker-ce-edge yum install -y docker-ce-19.03.9-3.el7 docker-ce-cli-19.03.9-3.el7 containerd.io docker-compose systemctl enable docker systemctl start docker #配置镜像加速(阿里云镜像站) cat > /etc/docker/daemon.json << EOF { "registry-mirrors": ["https://b9pmyelo.mirror.aliyuncs.com"], "exec-opts": ["native.cgroupdriver=systemd"] } EOF
1.3.安装kubeadm和kubelet(每台都执行)
cat > /etc/yum.repos.d/kubernetes.repo << EOF [kubernetes] name=Kubernetes baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64 enabled=1 gpgcheck=0 repo_gpgcheck=0 gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg EOF yum -y install kubelet-1.19.0-0.x86_64 kubeadm-1.19.0-0.x86_64 kubectl-1.19.0-0.x86_64 systemctl enable kubelet
1.4.使用kubeadm部署master
讯享网kubeadm init --kubernetes-version=1.19.0 --apiserver-advertise-address=172.16.8.124 --service-cidr=10.64.0.0/24 --pod-network-cidr=10.244.0.0/16 (master上执行,--image-repository registry.aliyuncs.com/google_containers,指定从阿里云下载) #注:主机名中不能带有_(下划线),不然初始化会报错 mkdir -p $HOME/.kube cp -i /etc/kubernetes/admin.conf $HOME/.kube/config chown $(id -u):$(id -g) $HOME/.kube/config 查看node信息 kubectl get nodes
1.5.让node加入集群
#当主节点启动完k8s之后会生成加入节点的命令,视自己服务器而定 kubeadm join 172.16.8.124:6443 --token xxxxx \ --discovery-token-ca-cert-hash xxxxxx #默认token有效期为24小时,当过期之后,该token就不可用了。这时就需要重新创建token,操作如下: kubeadm token create --print-join-command #查看节点是否已加入 kubectl get nodes
1.6.集群报错
1.6.1.所有节点显示 NotReady
讯享网#查看组件健康情况 kubectl get cs

- 解决方法
vim /etc/kubernetes/manifests/kube-controller-manager.yaml (注释掉 - --port=0) vim /etc/kubernetes/manifests/kube-scheduler.yaml (注释掉 - --port=0) systemctl start kubelet #再次查看

- 过会儿节点也都正常了

1.7.安装pod网络插件
讯享网#主节点执行 kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml #安装calico # wget https://docs.projectcalico.org/v3.8/getting-started/kubernetes/installation/hosted/kubernetes-datastore/calico-networking/1.7/calico.yaml # wget https://docs.projectcalico.org/manifests/calico.yaml #kubectl apply -f calico.yaml #修改部分 (#取消注释) - name: CALICO_IPV4POOL_CIDR value: "10.244.0.0/16" #地址为初始化集群时的“--pod-network-cidr”的设置IP 查看pods信息 kubectl get pods -n kube-system
1.8.安装私有镜像仓库harbor
#安装docker-compose #可以通过修改URL中的版本,可以自定义您的需要的版本 curl -L https://get.daocloud.io/docker/compose/releases/download/1.21.2/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose 为安装脚本添加执行权限 chmod +x /usr/local/bin/docker-compose # 安装Compose命令补全工具 curl -L https://raw.githubusercontent.com/docker/compose/$(docker-compose version --short)/contrib/completion/bash/docker-compose -o /etc/bash_completion.d/docker-compose #重启docker systemctl daemon-reload systemctl restart docker #安装harbor wget https://storage.googleapis.com/harbor-releases/release-1.8.0/harbor-offline-installer-v1.8.0.tgz tar xvf harbor-offline-installer-v1.8.0.tgz cd harbor/ vim harbor.yml (修改默认端口) ./prepare ./install.sh #登录harbor (1)docker login http://192.168.3.124:8080 (docker登录harbor) (docker无法连接harbor时,请在/etc/docker/daemon.json 中添加{
"registry-mirrors": ["https://b9pmyelo.mirror.aliyuncs.com"], "exec-opts": ["native.cgroupdriver=systemd"], "insecure-registries": ["harbor的主机ip"] } (如果还不行请./install.sh)
1.9.安装coredns
讯享网#官方模板:https://github.com/coredns/deployment/blob/master/kubernetes/coredns.yaml.sed #复制内容模板内容 [root@k8s_master yaml]# vim coredns.yaml #要修改的内容 CLUSTER_DNS_IP: 10.0.0.2 #对应kubelet的DNS CLUSTER_DOMAIN: cluster.local REVERSE_CIDRS: in-addr.arpa ip6.arpa STUBDOMAINS: 无 UPSTREAMNAMESERVER: /etc/resolv.conf # 修改镜像为1.7.1 coredns/coredns:1.7.1 #修改后的coredns.yaml wget http://oss.linuxtxc.com/deploy/yaml/coredns.yaml kubectl apply -f coredns.yaml
1.10.重置kubernetes集群
(master,node都执行) kubeadm reset rm -rf /etc/cni/net.d (master上执行 ) kubeadm init --kubernetes-version=1.19.0 --apiserver-advertise-address=192.168.3.124 --service-cidr=10.64.0.0/24 --pod-network-cidr=10.244.0.0/16 mkdir -p $HOME/.kube cp -i /etc/kubernetes/admin.conf $HOME/.kube/config chown $(id -u):$(id -g) $HOME/.kube/config vim /etc/kubernetes/manifests/kube-controller-manager.yaml (注释掉 - --port=0) vim /etc/kubernetes/manifests/kube-scheduler.yaml (注释掉 - --port=0) systemctl start kubelet (node 上执行) kubeadm reset kubeadm join 192.168.3.124:6443 --token f62e1g.exfdrr8bg2fxpdmu \ --discovery-token-ca-cert-hash sha256:7e4762cccce2e8306b6635cbc2091eae34bbf521a343c49fc026a
1.11.切换容器引擎为Containerd
讯享网#启动模块(默认已经启用) modprobe overlay modprobe br_netfilter #设置必需的 sysctl 参数 cat > /etc/sysctl.d/cri-containerd.conf << EOF net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 net.ipv4.ip_forward = 1 EOF sysctl --system #安装containerd (已经安装docker后,默认会有containerd) #yum install -y yum-utils device-mapper-persistent-data lvm2 yum-config-manager \ --add-repo \ https://download.docker.com/linux/centos/docker-ce.repo #yum install -y containerd.io #mkdir -p /etc/containerd #生成默认的配置文件 containerd config default > /etc/containerd/config.toml
- 修改配置文件
• pause镜像设置过阿里云镜像仓库地址
• cgroups驱动设置为systemd
• 拉取Docker Hub镜像配置加速地址设置为阿里云镜像仓库地址
vi /etc/containerd/config.toml [plugins."io.containerd.grpc.v1.cri"] sandbox_image = "registry.aliyuncs.com/google_containers/pause:3.2" ... [plugins."io.containerd.grpc.v1.cri".containerd.default_runtime.options] SystemdCgroup = true ... [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"] endpoint = ["https://b9pmyelo.mirror.aliyuncs.com"] #重启containerd systemctl restart containerd
- 配置kubelet使用containerd
讯享网vi /etc/sysconfig/kubelet KUBELET_EXTRA_ARGS=--container-runtime=remote --container-runtime-endpoint=unix:///run/containerd/containerd.sock --cgroup-driver=systemd systemctl restart kubelet #验证 kubectl get node -o wide
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mLgnwFu3-11)(C:\Users\linux\AppData\Roaming\Typora\typora-user-images\image-.png)]
- 管理容器工具
containerd提供了ctr命令行工具管理容器,但功能比较简单,所以一般会用crictl工具检查和调试容器。
项目地址:https://github.com/kubernetes-sigs/cri-tools/
设置crictl连接containerd:
vi /etc/crictl.yaml runtime-endpoint: unix:///run/containerd/containerd.sock image-endpoint: unix:///run/containerd/containerd.sock timeout: 10 debug: false
- docker与crictl命令对照表:
| *镜像相关功能* | *Docker* | *Containerd* |
|---|---|---|
| 显示本地镜像列表 | docker images | crictl images |
| 下载镜像 | docker pull | crictl pull |
| 上传镜像 | docker push | 无,例如buildk |
| 删除本地镜像 | docker rmi | crictl rmi |
| 查看镜像详情 | docker inspect IMAGE-ID | crictl inspecti IMAGE-ID |
| *容器相关功能* | *Docker* | *Containerd* |
|---|---|---|
| 显示容器列表 | docker ps | crictl ps |
| 创建容器 | docker create | crictl create |
| 启动容器 | docker start | crictl start |
| 停止容器 | docker stop | crictl stop |
| 删除容器 | docker rm | crictl rm |
| 查看容器详情 | docker inspect | crictl inspect |
| 附加容器 | docker attach | crictl attach |
| 执行命令 | docker exec | crictl exec |
| 查看日志 | docker logs | crictl logs |
| 查看容器资源 | docker status | crictl status |
| *POD* *相关功能* | *Docker* | *Containerd* |
|---|---|---|
| 显示 POD 列表 | 无 | crictl pods |
| 查看 POD 详情 | 无 | crictl inspectp |
| 运行 POD | 无 | crictl run |
| 停止 POD | 无 | crictl stop |
2.kubernetes 资源管理
2.1.kubectl create
讯享网kubectl create namespace dev #创建一个namespace kubectl create service clusterip ngx-dep --tcp=80:80 #命令行创建service kubectl create -f ns-dev.yaml #根据yaml文件创建资源 kubectl create deployment deploy-nginx --image=nginx:1.17.2 --replicas=3 -n dev #暴露端口 kubectl expose deployment deploy-nginx --port=80 --target-port=80 --type=NodePort --name=nginx-service -n dev #命令行创建yaml模板 kubectl create deployment deploy-nginx --image=nginx:1.17.2 --replicas=3 -n dev --dry-run=client -o yaml > deploy-nginx.yaml
2.2.kubectl api-resources
kubectl api-resources #查看k8s所有的资源以及对应的apiversion kubectl api-versions #查看k8s所有 版本号
2.3.kubectl explain
讯享网kubectl explain 资源类型(pod,deployment) # 查看某种资源可以配置的一级配置 kubectl explain 资源类型.属性 #查看资源的子属性
2.4.kubectl label
版本类标签(release):stable(稳定版)、canary(金丝雀版本,可以将其称之为测试版中的测试版)、beta(测试版);
环境类标签(environment):dev(开发)、qa(测试)、production(生产)、op(运维);
应用类(app):ui、as、pc、sc;
架构类(tier):frontend(前端)、backend(后端)、cache(缓存);
分区标签(partition):customerA(客户A)、customerB(客户B);
品控级别(Track):daily(每天)、weekly(每周)。
kucectl label pod nginx-pod version=1.0 -n web #为pod打上标签 kubectl label pod --show-labels -n web #显示pod的标签 kucectl label pod nginx-pod version=1.0 --overwrite -n web #覆盖原来的标签
2.5.kubectl describe
讯享网kubectl describe pod nginx-pod -n web #查看pod 的详细信息 kubectl describe service nginx-svc -n web #查看service的 详细信息 kubectl describe node 192.168.3.125 #查看node的详细信息
2.6.kubectl exec
#进入pod容器中 kubectl exec -it nginx-deployment-d598-87hlk -n web /bin/sh
2.7.kubectl get
讯享网kubectl get cs #获取集群健康状态 kubectl get csr #查看申请加入kubernetes集群的token信息 kubectl get endpoints #获取service对应的所有pod的访问地址 kubectl get pod -n web -o wide -w #查看namespace web下的pod,--all-namespaces:查看所有namespace下的pod;-w:动态查看;-o wide:查看更多信息 kubectl get pod --show-labels (显示资源标签) kubectl get pod -l app=nginx (-l,根据标签过滤资源)
2.8.kubectl edit
kubectl edit cm kubeadm-config -n kube-system #cm,configMap;编辑configMap中的配置
2.9.kubectl logs
讯享网kubectl logs nginx-deployment-d598-87hlk -n web #查看pod日志 kubectl logs -f nginx-deployment-d598-87hlk -n web #实时查看日志 kubectl log nginx-deployment-d598-87hlk -c <container_name> -n web #查看pod中单个容器的日志 kubectl logs -l app=frontend -n web #返回全部标记为 app=frontend 的 pod 的合并日志
2.10.kubectl delete
kubectl delete -f deployment-nginx.yaml #删除该yaml中创建的资源 kubectl delete pod nginx-deployment-d598-87hlk -n web #删除pod资源 #有部分 Terminating状态的pod无法删除,可以使用 --grace-period=0 --force强制删除 kubectl delete pod calico-kube-controllers-6b77fff45-m6w4n -n kube-system --grace-period=0 --force
2.11.kubectl autoscale
讯享网kubectl autoscale deployment deployment-nginx --cpu-percent=60 --min=2 --max=10 #使用 Deployment “deployment-nginx”设定,使用默认的自动伸缩策略,指定目标CPU使用率,使其Pod数量在2到10之间。
2.12.kubectl patch
#使用(patch)补丁修改、更新资源的字段。 kubectl patch pod rc-nginx-2-kpiqt -p '{"metadata":{"labels":{"app":"nginx-3"}}}' #修改资源配置
2.13.kubectl replace
讯享网kubectl replace -f rc-nginx.yaml #根据yaml文件更新修改后配置资源,会停掉原来的资源,重新创建
2.14.kubectl scale
kubectl scale rc redis --replicas=3 -n web #操作pod 的扩容和缩容 kubectl scale --replicas=2 -f redis-slave-deployment.yaml
2.15.kubectl rollout
讯享网status:显示当前升级状态 history:显示升级历史记录 pause:暂停版本升级过程 resume:继续已经暂停的版本升级过程 restart:重启版本升级过程 undo:回滚到上一级版本 (可以使用--to-revision,指定版本) kubectl apply -f pc-deployment.yml --record (--record,记录操作记录,便于回滚) #查看历史版本 kubectl rollout history deployment -n app 更新镜像: (1)通过kubectl set 命令去更改 kubectl set image deploy nginx-deployment nginx=nginx:1.15.2 -n app && kubectl rollout pause deployment nginx-deployment -n app #相当于灰度发布 (2)通过修改deployment文件去更改 kubectl apply -f nginx-deployment.yml --record && kubectl rollout pause deployment nginx-deployment -n app #继续更新过程 kubectl rollout resume deployment nginx-deployment -n app #版本回滚到v1 kubectl rollout undo deploy nginx-deployment --to-revision=1 -n app
2.16.kubectl taint
kubectl taint node k8s-node1 tag=webapps:PreferNoSchedule #设置污点 kubectl taint node k8s-node1 tag:PreferNoSchedule- #去除污点 kubectl taint node k8s-node1 tag- #去除所有污点 kubectl describe nodes k8s-node1 | grep Taints #查看节点上的污点 #将node标记为不可调度的状态,这样就不会让新创建的pod在此node上运行。 kubectl cordon 192.168.1.48 #恢复node为可调度的状态。 kubectl uncordon 192.168.1.48 #可以让node在维护期间排除节点。drain本意排水,意思是将出问题的node下的pod转移到其它node下运行,并且不接收新的pod。 kubectl drain 192.168.1.48 --ignore-daemonsets --delete-local-data #drain的参数 --force 当一些pod不是经 ReplicationController, ReplicaSet, Job, DaemonSet 或者 StatefulSet 管理的时候 就需要用--force来强制执行 (例如:kube-proxy) --ignore-daemonsets 无视DaemonSet管理下的Pod --delete-local-data 如果有mount local volumn的pod,会强制杀掉该pod并把料清除掉
2.17.kubectl run
讯享网kubectl run nginx --image=nginx:1.17.1 -n web #命令使用镜像创建容器
2.18.kubectl apply
#如果资源不存在,就创建,相当于kubectl create。 #如果资源存在,就更新,相当于kubectl patch。 kubectl apply -f nginx-pod.yaml -n web --record (--record,记录操作记录,便于回滚)
2.19.kubectl top
讯享网kubectl top pod/node -n dev #查看资源使用情况(需要安装metrics-server)
2.20.kubectl expose
#将tomcat-deployment 服务的8080 端口 暴露给 tomcat-service 的service (也相当于创建service) kubectl expose deployment tomcat-deployment --port=8080 --target-port=8080 --type=ClusterIP --name=tomcat-service -n app
2.21.kubectl cp
讯享网#将pod里的文件拷贝到主机 #kubectl cp -c 容器名 pod名:文件绝对路径 文件目标位置 -n namespace名 kubectl cp nginx-deployment-84b859f76c-crdrl:tmp/helm-v3.5.4-linux-amd64.tar.gz /tmp/helm-v3.5.4-linux-amd64.tar.gz -n app #将主机文件拷贝到pod #kubectl cp 主机文件路径 -c 容器 pod名:容器内绝对路径 -n namespace名 kubectl cp tomcat-java-demo-master.zip nginx-deployment-84b859f76c-crdrl:tmp -n app (如果pod中有多个容器,需要指定进入的容器名) 注:pod后的目录绝对路径不用写"/"
2.22.kubectl certificate
#kubectl certificate用来修改证书资源,可选approve/deny同意与拒绝审批。
2.23.kubectl config
讯享网#config命令,生成集群信息,集群用户和用户权限并把这些内容写入kubectl读取的配置文件 # 设置集群参数 [root@k8s-master admin]# kubectl config set-cluster kubernetes --certificate-authority=/etc/kubernetes/cert/ca.pem --embed-certs=true --server=${KUBE_APISERVER} --kubeconfig=kubectl.kubeconfig #设置客户端认证参数 [root@k8s-master admin]# kubectl config set-credentials admin --client-certificate=admin.pem --client-key=admin-key.pem --embed-certs=true --kubeconfig=kubectl.kubeconfig #设置上下文参数,包含集群名称和访问集群的用户名字 [root@k8s-master admin]# kubectl config set-context kubernetes --cluster=kubernetes --user=admin --kubeconfig=kubectl.kubeconfig #使用默认上下文 [root@k8s-master admin]# kubectl config use-context kubernetes --kubeconfig=kubectl.kubeconfig
3.kubernetes 的Pod 详解
3.1.Pod 所有参数配置
apiVersion: v1 kind: Namespace metadata: name: dev --- #所有常用配置参数 apiVersion: v1 #必选,版本号,例如v1 kind: Pod #必选,资源类型,例如 Pod metadata: #必选,元数据 name: string #必选,Pod名称 namespace: string #Pod所属的命名空间,默认为"default" labels: #自定义标签列表 - name: string spec: #必选,Pod中容器的详细定义 containers: #必选,Pod中容器列表 - name: string #必选,容器名称 image: string #必选,容器的镜像名称 imagePullPolicy: [ Always|Never|IfNotPresent ] #获取镜像的策略 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数 memory: string #内存限制,单位可以为Mib/Gib requests: #资源请求的设置 cpu: string #Cpu请求,容器启动的初始可用数量 memory: string #内存请求,容器启动的初始可用数量 lifecycle: #生命周期钩子 postStart: #容器启动后立即执行此钩子,如果执行失败,会根据重启策略进行重启 preStop: #容器终止前执行此钩子,无论结果如何,容器都会终止 livenessProbe: #对Pod内各容器健康检查的设置,当探测无响应几次后将自动重启该容器 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的重启策略 nodeName: <string> #设置NodeName表示将该Pod调度到指定到名称的node节点上 nodeSelector: obeject #设置NodeSelector表示将该Pod调度到包含这个label的node上 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的存储卷,挂载集群与定义的secret对象到容器内部 scretname: string items: - key: string path: string configMap: #类型为configMap的存储卷,挂载预定义的configMap对象到容器内部 name: string items: - key: string path: string
3.2.Pod资源限制
讯享网apiVersion: v1 kind: Pod metadata: name: test-pod namespace: app labels: app: nginx spec: containers: - name: nginx01 # 容器名称 image: nginx:1.17.1 # 容器需要的镜像地址 imagePullPolicy: IfNotPresent # 设置镜像拉取策略,Alawys;IfNotPresent;Never ports: # 端口设置 - containerPort: 80 # 容器要监听的端口 (0~65536) protocol: TCP # 端口协议 resources: # 资源配额 limits: # 限制资源的上限 cpu: "1" # CPU限制,单位是core数,0.1=100m memory: "10Gi" # 内存限制 requests: # 限制资源的下限 cpu: "0.5" # CPU限制,单位是core数, 0.5=500m memory: "1Gi" # 内存限制
- imagePullPolicy:用于设置镜像拉取的策略,kubernetes支持配置三种拉取策略:
-
- Always:总是从远程仓库拉取镜像(一直远程下载)。
-
- IfNotPresent:本地有则使用本地镜像,本地没有则从远程仓库拉取镜像(本地有就用本地,本地没有就使用远程下载)。
-
- Never:只使用本地镜像,从不去远程仓库拉取,本地没有就报错(一直使用本地,没有就报错)。
3.3.Pod 生命周期
我们一般将Pod对象从创建到终止的这段时间范围称为Pod的生命周期,它主要包含下面的过程:
-
- Pod创建过程。
-
- 运行初始化容器(init container)过程。
-
- 运行主容器(main container):
-
-
- 容器启动后钩子(post start)。
-
-
-
- 容器的存活性探测(liveness probe)、就绪性探测(readiness probe)。
- 容器终止前钩子(pre stop)。
-
-
- Pod终止过程。
3.3.1.钩子函数
- 钩子函数能够感知自身生命周期中的事件,并在相应的时刻到来时运行用户指定的程序代码。
- kubernetes在主容器启动之后和停止之前提供了两个钩子函数:
-
- post start:容器创建之后执行,如果失败会重启容器。
-
- pre stop:容器终止之前执行,执行完成之后容器将成功终止,在其完成之前会阻塞删除容器的操作。
- 钩子处理器支持使用下面的三种方式定义动作:
-
- ① exec命令:在容器内执行一次命令。
…… lifecycle: postStart: exec: command: - cat - /tmp/healthy ……
② tcpSocket:在当前容器尝试访问指定的socket。
讯享网…… lifecycle: postStart: tcpSocket: port: 8080 ……
③ httpGet:在当前容器中向某url发起HTTP请求。
…… lifecycle: postStart: httpGet: path: / #URI地址 port: 80 #端口号 host: 192.168.109.100 #主机地址 scheme: HTTP #支持的协议,http或者https ……
以exec方式为例,演示下钩子函数的使用,创建pod-hook-exec.yaml文件,内容如下:
讯享网apiVersion: v1 kind: Pod metadata: name: pod-hook-exec namespace: app labels: app: nginx spec: containers: # 容器配置 - name: nginx image: nginx:1.17.1 imagePullPolicy: IfNotPresent ports: - name: nginx-port containerPort: 80 protocol: TCP resources: limits: cpu: "2" memory: "10Gi" requests: cpu: "1" memory: "10Mi" lifecycle: # 生命周期配置 postStart: # 容器创建之后执行,如果失败会重启容器 exec: # 在容器启动的时候,执行一条命令,修改掉Nginx的首页内容 command: ["/bin/sh","-c","echo postStart ... > /usr/share/nginx/html/index.html"] preStop: # 容器终止之前执行,执行完成之后容器将成功终止,在其完成之前会阻塞删除容器的操作 exec: # 在容器停止之前停止Nginx的服务 command: ["/usr/sbin/nginx","-s","quit"]
3.3.2.容器探测
容器探测用于检测容器中的应用实例是否正常工作,是保障业务可用性的一种传统机制。
-
- liveness probes:存活性探测,用于检测应用实例当前是否处于正常运行状态,如果不是,k8s会重启容器。
-
- readiness probes:就绪性探测,用于检测应用实例是否可以接受请求,如果不能,k8s不会转发流量。
- 上面两种探针目前均支持三种探测方式:
-
- ① exec命令:在容器内执行一次命令,如果命令执行的退出码为0,则认为程序正常,否则不正常。
---------------------------- readinessProbe: exec: command: - cat - /etc/hosts initialDelaySeconds: 5 timeoutSeconds: 2 successThreshold: 3 failureThreshold: 2 periodSeconds: 5 -----------------------------
-
- ② tcpSocket:将会尝试访问一个用户容器的端口,如果能够建立这条连接,则认为程序正常,否则不正常。
讯享网…… livenessProbe: tcpSocket: port: 8080 failureThreshold: 5 #检测失败5次表示未就绪 initialDelaySeconds: 60 #初始化时间 periodSeconds: 10 #检测间隔 successThreshold: 1 #检查成功为2次表示就绪 timeoutSeconds: 5 #检测失败1次表示未就绪 ……
-
- ③ httpGet:调用容器内web应用的URL,如果返回的状态码在200和399之前,则认为程序正常,否则不正常。
------------------------ livenessProbe: #健康检查方式:[readinessProbe,livenessProbe,StartupProbe] httpGet: #请求方式 path: /health #请求路径 port: 8080 #请求端口 scheme: HTTP 请求协议 failureThreshold: 5 #检测失败5次表示未就绪 initialDelaySeconds: 60 #初始化时间 periodSeconds: 10 #检测间隔 successThreshold: 1 #检查成功为2次表示就绪 timeoutSeconds: 5 #检测失败1次表示未就绪 ----------------------------
- startupProbe : 启动探测,k8s1.16版本后新加的探测方式,用于判断容器内应用程序是否已经启动,如果配置了startuprobe,就会先禁用其他的探测,直到它成功为止。
讯享网---------------------------------- startupProbe: #健康检查方式:[readinessProbe,livenessProbe,StartupProbe] httpGet: #请求方式 path: / #请求路径 port: 8080 #请求端口 scheme: HTTP #请求协议 failureThreshold: 3 #检测失败3次表示未就绪 periodSeconds: 10 #检测间隔 successThreshold: 1 #检查成功为2次表示就绪 timeoutSeconds: 1 #检测失败1次表示未就绪 ----------------------------------
initialDelaySeconds # 容器启动后等待多少秒执行第一次探测。
timeoutSeconds # 探测超时时间。默认1秒,最小1秒。
periodSeconds # 执行探测的频率。默认是10秒,最小1秒。
failureThreshold # 连续探测失败多少次才被认定为失败。默认是3。最小值是1。
successThreshold # 连续探测成功多少次才被认定为成功。默认是1。
重启策略:
-
- Always:容器失效时,自动重启该容器,默认值。
-
- OnFailure:容器终止运行且退出码不为0时重启。
-
- Never:不论状态如何,都不重启该容器。
- startupprobe+readinessProbe+ livenessProbe混合案例
apiVersion: v1 # 必选,API的版本号 kind: Pod # 必选,类型Pod metadata: # 必选,元数据 name: read-startup # 必选,符合RFC 1035规范的Pod名称 labels: # 可选,标签选择器,一般用于过滤和区分Pod app: nginx role: frontend # 可以写多个 annotations: # 可选,注释列表,可以写多个 app: nginx spec: # 必选,用于定义容器的详细信息 containers: # 必选,容器列表 - name: read-startup # 必选,符合规范的容器名称 image: nginx:latest # 必选,容器所用的镜像 imagePullPolicy: Always # 可选,镜像拉取策略 command: # 可选,容器启动执行的命令 - nginx - -g - "daemon off;" workingDir: /usr/share/nginx/html # 可选,容器的工作目录 ports: # 可选,容器需要暴露的端口号列表 - name: http # 端口名称 containerPort: 80 # 端口号 protocol: TCP # 端口协议,默认TCP env: # 可选,环境变量配置列表 - name: TZ # 变量名 value: Asia/Shanghai # 变量的值 - name: LANG value: en_US.utf8 readinessProbe: exec: command: - cat - /etc/hosts initialDelaySeconds: 5 timeoutSeconds: 2 successThreshold: 3 failureThreshold: 2 periodSeconds: 5 startupProbe: httpGet: path: / port: 80 failureThreshold: 30 periodSeconds: 10 livenessProbe: httpGet: path: /healthz port: 80 failureThreshold: 1 periodSeconds: 10 restartPolicy: Never #重启策略
4.kubernetes 中Pod调度
- kubernetes提供了四大类调度方式。
-
- 自动调度:运行在哪个Node节点上完全由Scheduler经过一系列的算法计算得出。
-
- 定向调度:NodeName、NodeSelector。
-
- 亲和性调度:NodeAffinity、PodAffinity、PodAntiAffinity。
-
- 污点(容忍)调度:Taints、Toleration。
4.1.定向调度
- 定向调度,指的是利用在Pod上声明的nodeName或nodeSelector,以此将Pod调度到期望的Node节点上。注意,这里的调度是强制的,这就意味着即使要调度的目标Node不存在,也会向上面进行调度,只不过Pod运行失败而已。
nodeName:用于强制约束将Pod调度到指定的name的Node节点上。这种方式,其实是直接跳过Scheduler的调度逻辑,直接将Pod调度到指定名称的节点。
- 创建一个pod-nodename.yaml文件,内容如下:
讯享网apiVersion: v1 kind: Pod metadata: name: pod-nodename namespace: web labels: app: nginx spec: containers: # 容器配置 - name: nginx image: nginx:1.17.1 imagePullPolicy: IfNotPresent ports: - name: nginx-port containerPort: 80 protocol: TCP nodeName: k8s-node1 #指定调度到k8s-node1节点上
nodeSelector:用于将Pod调度到添加了指定标签的Node节点上,它是通过kubernetes的label-selector机制实现的,换言之,在Pod创建之前,会由Scheduler使用MatchNodeSelector调度策略进行label匹配,找出目标node,然后将Pod调度到目标节点,该匹配规则是强制约束。
#给node节点添加标签 kubectl label node k8s-node1 node=web kubectl label node k8s-node2 node=app
- 创建pod-nodeselector.yaml文件,内容如下:
讯享网apiVersion: v1 kind: Pod metadata: name: pod-nodeselector namespace: app spec: containers: # 容器配置 - name: nginx image: nginx:1.17.1 imagePullPolicy: IfNotPresent ports: - name: nginx-port containerPort: 80 protocol: TCP nodeSelector: node: app #指定调度到具有node=app的Node节点上
4.2.亲和性调度
- 虽然定向调度的两种方式,使用起来非常方便,但是也有一定的问题,那就是如果没有满足条件的Node,那么Pod将不会被运行,即使在集群中还有可用的Node列表也不行,这就限制了它的使用场景。
- 基于上面的问题,kubernetes还提供了一种亲和性调度(Affinity)。它在nodeSelector的基础之上进行了扩展,可以通过配置的形式,实现优先选择满足条件的Node进行调度,如果没有,也可以调度到不满足条件的节点上,使得调度更加灵活。
- Affinity主要分为三类:
-
- nodeAffinity(node亲和性):以Node为目标,解决Pod可以调度到哪些Node的问题。
-
- podAffinity(pod亲和性):以Pod为目标,解决Pod可以和那些已存在的Pod部署在同一个拓扑域中的问题。
-
- podAntiAffinity(pod反亲和性):以Pod为目标,解决Pod不能和那些已经存在的Pod部署在同一拓扑域中的问题。
4.2.1.node亲和性(nodeAffinity)
- 查看nodeAffinity的可选配置项:
pod.spec.affinity.nodeAffinity requiredDuringSchedulingIgnoredDuringExecution #Node节点必须满足指定的所有规则才可以,相当于硬限制 nodeSelectorTerms #节点选择列表 matchFields #按节点字段列出的节点选择器要求列表 matchExpressions #按节点标签列出的节点选择器要求列表(推荐) key #键 values #值 operator # 关系符 支持Exists, DoesNotExist, In, NotIn, Gt, Lt --- preferredDuringSchedulingIgnoredDuringExecution #优先调度到满足指定的规则的Node,相当于软限制 (倾向) preference #一个节点选择器项,与相应的权重相关联 matchFields #按节点字段列出的节点选择器要求列表 matchExpressions #按节点标签列出的节点选择器要求列表(推荐) key #键 values #值 operator #关系符 支持In, NotIn, Exists, DoesNotExist, Gt, Lt weight #倾向权重,在范围1-100。 --- - matchExpressions: - key: nodeenv # 匹配存在标签的key为nodeenv的节点 operator: Exists - key: nodeenv # 匹配标签的key为nodeenv,且value是"xxx"或"yyy"的节点 operator: In values: ["xxx","yyy"] - key: nodeenv # 匹配标签的key为nodeenv,且value大于"xxx"的节点 operator: Gt values: "xxx"
- 下面演示preferredDuringSchedulingIgnoredDuringExecution(软限制):
-
- 创建pod-nodeaffinity-preferred.yaml文件,内容如下:
讯享网apiVersion: v1 kind: Pod metadata: name: pod-nodeaffinity-preferred namespace: app spec: containers: # 容器配置 - name: nginx image: nginx:1.17.1 imagePullPolicy: IfNotPresent ports: - name: nginx-port containerPort: 80 protocol: TCP affinity: # 亲和性配置 nodeAffinity: # node亲和性配置 preferredDuringSchedulingIgnoredDuringExecution: # 先匹配node标签中有nodeenv=app或者nodeenv=xyy的node,优先调度到满足指定的规则的Node,相当于软限制 (倾向) - preference: # 一个节点选择器项,与相应的权重相关联 matchExpressions: - key: nodeenv operator: In values: - "app" - "xyy" weight: 50
- 下面演示preferredDuringSchedulingIgnoredDuringExecution(硬限制):
-
- 创建pod-nodeaffinity-preferred.yaml文件,内容如下:
apiVersion: v1 kind: Pod metadata: name: pod-nodeaffinity-required namespace: dev spec: containers: # 容器配置 - name: nginx image: nginx:1.17.1 imagePullPolicy: IfNotPresent ports: - name: nginx-port containerPort: 80 protocol: TCP affinity: # 亲和性配置 nodeAffinity: # node亲和性配置 requiredDuringSchedulingIgnoredDuringExecution: #先匹配node标签中有nodeenv=app或者nodeenv=xyy的node,如果没有,则会调度失败,相当于硬规则,类似于定向调度 nodeSelectorTerms: # 节点选择列表 - matchExpressions: - key: nodeenv # 匹配存在标签的key为nodeenv的节点,并且value是"xxx"或"yyy"的节点 operator: In values: - "app" - "yyy"
nodeAffinity的注意事项:
- 如果同时定义了nodeSelector和nodeAffinity,那么必须两个条件都满足,Pod才能运行在指定的Node上。
- 如果nodeAffinity指定了多个nodeSelectorTerms,那么只需要其中一个能够匹配成功即可。
- 如果一个nodeSelectorTerms中有多个matchExpressions,则一个节点必须满足所有的才能匹配成功。
- 如果一个Pod所在的Node在Pod运行期间其标签发生了改变,不再符合该Pod的nodeAffinity的要求,则系统将忽略此变化。
4.2.2.Pod亲和性(PodAffinity)
- PodAffinity的可选配置项:
讯享网pod.spec.affinity.podAffinity requiredDuringSchedulingIgnoredDuringExecution #硬限制 namespaces #指定参照pod的namespace topologyKey #指定调度作用域 labelSelector # 标签选择器 matchExpressions #按节点标签列出的节点选择器要求列表(推荐) key #键 values #值 operator #关系符 支持In, NotIn, Exists, DoesNotExist. matchLabels #指多个matchExpressions映射的内容 preferredDuringSchedulingIgnoredDuringExecution #软限制 podAffinityTerm #选项 namespaces #指定参照pod的namespace topologyKey #指定调度作用域 labelSelector # 标签选择器 matchExpressions key # 键 values # 值 operator matchLabels weight # 倾向权重,在范围1-100 #topologyKey用于指定调度的作用域,例如: #如果指定为kubernetes.io/hostname,那就是以Node节点为区分范围。 #如果指定为beta.kubernetes.io/os,则以Node节点的操作系统类型来区分。
- 创建Pod过程:
-
- 创建pod-podaffinity-requred.yaml文件,内容如下:
apiVersion: v1 kind: Pod metadata: name: pod-podaffinity-requred namespace: app spec: containers: # 容器配置 - name: nginx image: nginx:1.17.1 imagePullPolicy: IfNotPresent ports: - name: nginx-web containerPort: 80 protocol: TCP affinity: # 亲和性配置 podAffinity: # Pod亲和性 requiredDuringSchedulingIgnoredDuringExecution: # 硬限制 - labelSelector: matchExpressions: # 该Pod必须和拥有标签app=nginx或者app=test的Pod在同一个Node上。 - key: app operator: In values: - "nginx" - "test" topologyKey: kubernetes.io/hostname
- 创建Pod过程:
-
- 创建pod-podaffinity- prefer.yaml文件,内容如下:
讯享网apiVersion: v1 kind: Pod metadata: name: pod-podaffinity-prefer namespace: app spec: containers: # 容器配置 - name: nginx01 image: nginx:1.17.1 imagePullPolicy: IfNotPresent ports: - name: nginx-app containerPort: 80 protocol: TCP affinity: # 亲和性配置 podAffinity: # Pod亲和性 preferredDuringSchedulingIgnoredDuringExecution: #软限制 - weight: 50 podAffinityTerm: labelSelector: matchExpressions: #先匹配拥有标签app=yyy或者app=test的Pod,如果有,则将pod放在匹配pod同一个Node上,如果没有则让Scheduler根据算法自动调度 - key: app operator: In values: - "yyy" - "test" topologyKey: kubernetes.io/hostname
4.2.3.Pod反亲和性(podAntiAffinity)
- 主要实现以运行的Pod为参照,让新创建的Pod和参照的Pod不在一个区域的功能。
apiVersion: v1 kind: Pod metadata: name: pod-podantiaffinity-requred namespace: app spec: containers: # 容器配置 - name: nginx image: nginx:1.17.1 imagePullPolicy: IfNotPresent ports: - name: nginx-port containerPort: 80 protocol: TCP affinity: # 亲和性配置 podAntiAffinity: # Pod反亲和性 requiredDuringSchedulingIgnoredDuringExecution: # 硬限制 - labelSelector: matchExpressions: - key: app operator: In values: - "nginx" topologyKey: kubernetes.io/hostname
4.3.污点和容忍
4.3.1.污点(Taints)
- Node被设置了污点之后就和Pod之间存在了一种相斥的关系,进而拒绝Pod调度进来,甚至可以将已经存在的Pod驱逐出去。
- 污点的格式为:
key=value:effect,key和value是污点的标签,effect描述污点的作用,支持如下三个选项: -
- PreferNoSchedule:kubernetes将尽量避免把Pod调度到具有该污点的Node上,除非没有其他节点可以调度。
-
- NoSchedule:kubernetes将不会把Pod调度到具有该污点的Node上,但是不会影响当前Node上已经存在的Pod。
-
- NoExecute:kubernetes将不会把Pod调度到具有该污点的Node上,同时也会将Node上已经存在的Pod驱逐。
讯享网#设置污点 kubectl taint node xxx key=value:effect #去除污点 kubectl taint node xxx key:effect- #去除所有污点 kubectl taint node xxx key- #查询所有节点的污点 wget -O jq https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64 chmod +x ./jq cp jq /usr/bin kubectl get nodes -o json | jq '.items[].spec' #查看指定节点上的污点 kubectl describe node 节点名称 #给k8s-node1节点设置污点(PreferNoSchedule) kubectl taint node k8s-node1 tag=test:PreferNoSchedule #为k8s-node1取消污点(PreferNoSchedule),并设置污点(NoSchedule) kubectl taint node k8s-node1 tag:PreferNoSchedule- kubectl taint node k8s-node1 tag=test:NoSchedule
4.3.2.容忍
污点是拒绝,容忍就是忽略,Node通过污点拒绝Pod调度上去,Pod通过容忍忽略拒绝
- 容忍的详细配置:
kubectl explain pod.spec.tolerations ......... key # 对应着要容忍的污点的键,空意味着匹配所有的键 value # 对应着要容忍的污点的值 operator # key-value的运算符,支持Equal(默认)和Exists effect # 对应污点的effect,空意味着匹配所有影响 tolerationSeconds # 容忍时间, 当effect为NoExecute时生效,表示pod在Node上的停留时间
当operator为Equal的时候,如果Node节点有多个Taint,那么Pod每个Taint都需要容忍才能部署上去。
当operator为Exists的时候,有如下的三种写法:
- 容忍指定的污点,污点带有指定的effect:
- 容忍指定的污点,不考虑具体的effect:
- 容忍一切污点(慎用):
讯享网tolerations: # 容忍 - key: "tag" # 要容忍的污点的key operator: Exists # 操作符 effect: NoExecute # 添加容忍的规则,这里必须和标记的污点规则相同
tolerations: # 容忍 - key: "tag" # 要容忍的污点的key operator: Exists # 操作符
讯享网tolerations: # 容忍 - operator: Exists # 操作符
- 创建pod-toleration.yaml文件,内容如下:
apiVersion: v1 kind: Pod metadata: name: pod-toleration namespace: dev spec: containers: # 容器配置 - name: nginx image: nginx:1.17.1 imagePullPolicy: IfNotPresent ports: - name: nginx-port containerPort: 80 protocol: TCP tolerations: # 容忍 - key: "tag" # 要容忍的污点的key operator: Equal # 操作符 value: "test" # 要容忍的污点的value effect: NoExecute # 添加容忍的规则,这里必须和标记的污点规则相同
- 案例:
讯享网#给两个节点都打上污点 kubectl taint node 192.168.3.125 tag=test:NoSchedule kubectl taint node 192.168.3.125 tag=deploy:NoSchedule vim pod-toleration-test.yaml apiVersion: v1 kind: Pod metadata: name: pod-toleration namespace: dev spec: containers: # 容器配置 - name: nginx image: nginx:1.17.1 imagePullPolicy: IfNotPresent ports: - name: nginx-port containerPort: 80 protocol: TCP tolerations: # 容忍 - key: "tag" # 要容忍的污点的key operator: Equal # 操作符 value: "test" # 要容忍的污点的value effect: NoSchedule # 添加容忍的规则,这里必须和标记的污点规则相同 - key: "tag" # 要容忍的污点的key operator: Equal # 操作符 value: "deploy" # 要容忍的污点的value effect: NoExecute # 添加容忍的规则,这里必须和标记的污点规则相同
5.kubernetes的Pod控制器
5.1.Deployment控制器
- Deployment控制器并不直接管理Pod,而是通过管理ReplicaSet来间接管理Pod,即:Deployment管理ReplicaSet,ReplicaSet管理Pod。
- Deployment的主要功能如下:
-
- 支持ReplicaSet的所有功能。
-
- 支持发布的停止、继续。
-
- 支持版本滚动更新和版本回退。
- 创建nginx-deployment.yaml文件,在spec下添加更新策略
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment namespace: app spec: replicas: 3 revisionHistoryLimit: 10 #可保留的版本数 minReadySeconds: 5 #在等待设置的时间后才进行升级 strategy: #策略 type: RollingUpdate rollingUpdate: #滚动更新,就是杀死一部分,就启动一部分,在更新过程中,存在两个版本的Pod maxSurge: 30% #最大额外可以存在的副本数,可以为百分比,也可以为整数; 默认25% maxUnavailable: 30% #最大不可用状态的 ;Pod 的最大值,可以为百分比,也可以为整数,默认25% selector: matchLabels: app: nginx #matchExpressions: # Expressions匹配规则 # - {key: app, operator: In, values: [nginx-pod]} template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.17.1 imagePullpolicy: ifnotpresent ports: - containerPort: 80
- 镜像更新
讯享网(1)kubectl set image deployment nginx-deployment nginx=nginx:1.17.2 -n app (2)或者修改 nginx-deployment.yaml 中的image,再使用kubectl apply -f nginx-deployment.yaml --recard 更新资源 (3)kubectl edit deployment nginx-deployment -n app ,直接使用命令修改deployment #查看升级过程 kubectl get pod -n app -w

- 查看rs,发现原来的rs依旧存在,只是Pod的数量变为0,而后又产生了一个rs,Pod的数量变为3
kubectl get rs -n app

- 查看历史版本
讯享网kubectl rollout history deployment -n app

- 版本回滚
kubectl rollout undo deploy nginx-deployment --to-revision=1 -n app
- 金丝雀发布(在一批新的Pod资源创建完成后立即暂停更新过程)
讯享网(1)kubectl set image deploy nginx-deployment nginx=nginx:1.17.3 -n app && kubectl rollout pause deployment nginx-deployment -n app (2)kubectl apply -f nginx-deployment.yml --record && kubectl rollout pause deployment nginx-deployment -n app
5.2.Horizontal Pod Autoscaler(HPA)
HPA可以获取每个Pod的利用率,然后和HPA中定义的指标进行对比,同时计算出需要伸缩的具体值,最后实现Pod的数量的调整。
5.2.1.安装metrics-server(用来收集集群中的资源使用情况。)
#wget https://github.com/kubernetes-sigs/metrics-server/archive/v0.3.6.tar.gz wget https://oss.linuxtxc.com/metrics-server.zip #解压 unzip metrics-server.zip #进入metrics-server/deploy/1.8+/目录 cd metrics-server/deploy/1.8+ #修改metrics-server-deployment.yaml文件 vim metrics-server-deployment.yaml 按图中添加下面选项 hostNetwork: true image: registry.cn-hangzhou.aliyuncs.com/google_containers/metrics-server-amd64:v0.3.6 args: - --kubelet-insecure-tls - --kubelet-preferred-address-types=InternalIP,Hostname,InternalDNS,ExternalDNS,ExternalIP

- 安装安装metrics-server(v0.4.1)
讯享网wget https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.4.1/components.yaml 修改components.yaml 修改部分: - --kubelet-insecure-tls image: registry.cn-shanghai.aliyuncs.com/xuweiwei-kubernetes/metrics-server:v0.4.1

- 查看metrics-server生成的Pod:
kubectl get pod -n kube-system

5.2.2.错误排查
- 查看资源使用情况报错

- 排查错误
讯享网systemctl status kube-apiserver -l #或者 journalctl -u kube-apiserver

- metric-server安装要满足2个条件
- 在master节点要能访问metrics server pod ip(kubeadm部署默认已经满足该条件,二进制部署需注意要在master节点也部署node组件)
- apiserver启用聚合层支持(kubeadm默认已经启用,二进制部署需自己启用)
因为我是二进制安装的,所以在master上安装node组件就可以了
kubectl top pod -n app

5.2.3.部署HPA案例
- 使用之前创建的nginx-deployment,使用kubectl edit 将副本数改为 1

- 创建 nginx-service.yaml
讯享网apiVersion: v1 kind: Service metadata: name: nginx-service namespace: app spec: selector: # 标签选择器,用于确定当前Service代理那些Pod app: nginx-deployment type: NodePort ports: # - port: 80 # Service端口 protocol: TCP targetPort : 80 nodePort: 30081
- 创建nginx-hpa.yaml
apiVersion: autoscaling/v1 # 版本号 kind: HorizontalPodAutoscaler # 类型 metadata: # 元数据 name: nginx-hpa # deployment的名称 namespace: app #命名类型 spec: minReplicas: 1 # 最小Pod数量 maxReplicas: 10 # 最大Pod数量 targetCPUUtilizationPercentage: 3 # CPU使用率指标 scaleTargetRef: # 指定要控制的Nginx的信息 apiVersion: apps/v1 kind: Deployment name: nginx-deployment
讯享网#使用命令创建HPA控制器 kubectl autoscale deployment nginx-hpa --cpu-percent=3 --min=1 --max=10
- targets为unknown 的原因

- 需要安装metrics-server
- HPA对应的pod,需要设置request资源
#使用命令行设置pod 资源限制 kubectl set resources deployment/nginx-deployment --limits=cpu=800m
- 再次查看:

- 使用ab 命令访问测试

- 查看 HPA状态

5.3.DaemonSet
- DaemonSet类型的控制器可以保证集群中的每一台(或指定)节点上都运行一个副本,一般适用于日志收集、节点监控等场景
- DaemonSet控制器的特点:
-
- 每向集群中添加一个节点的时候,指定的Pod副本也将添加到该节点上。
-
- 当节点从集群中移除的时候,Pod也会被垃圾回收。
- DaemonSet的资源清单:
讯享网apiVersion: apps/v1 # 版本号 kind: DaemonSet # 类型 metadata: # 元数据 name: # 名称 namespace: #命名空间 labels: #标签 controller: daemonset spec: # 详情描述 revisionHistoryLimit: 3 # 保留历史版本 updateStrategy: # 更新策略 type: RollingUpdate # 滚动更新策略 rollingUpdate: # 滚动更新 maxSurge: 30% #最大额外可以存在的副本数,可以为百分比,也可以为整数; 默认25% maxUnavailable: 1 # 最大不可用状态的Pod的最大值,可用为百分比,也可以为整数,默认25% selector: # 选择器,通过它指定该控制器管理那些Pod matchLabels: # Labels匹配规则 app: nginx-pod matchExpressions: # Expressions匹配规则 - key: app operator: In values: - nginx-pod template: # 模板,当副本数量不足时,会根据下面的模板创建Pod模板 metadata: labels: app: nginx-pod spec: containers: - name: nginx image: nginx:1.17.1 ports: - containerPort: 80
- 案例
apiVersion: apps/v1 kind: DaemonSet metadata: name: node-exporter namespace: kube-system labels: k8s-app: node-exporter spec: selector: matchLabels: app: node-exporter template: metadata: labels: app: node-exporter spec: containers: - image: prom/node-exporter name: node-exporter ports: - containerPort: 9100 protocol: TCP name: http
5.4.Job
- Job主要用于负责批量处理短暂的一次性任务。J可以保证指定数量的Pod执行完成。
- Job的特点:
-
- 当Job创建的Pod执行成功结束时,Job将记录成功结束的Pod数量。
-
- 当成功结束的Pod达到指定的数量时,Job将完成执行。
- Job的资源清单:
讯享网apiVersion: batch/v1 # 版本号 kind: Job # 类型 metadata: # 元数据 name: # 名称 namespace: #命名空间 labels: # 标签 controller: job spec: # 详情描述 completions: 1 # 指定Job需要成功运行Pod的总次数,默认为1 parallelism: 1 # 指定Job在任一时刻应该并发运行Pod的数量,默认为1 activeDeadlineSeconds: 30 # 指定Job可以运行的时间期限,超过时间还没结束,系统将会尝试进行终止 backoffLimit: 6 # 指定Job失败后进行重试的次数,默认为6 manualSelector: true # 是否可以使用selector选择器选择Pod,默认为false selector: # 选择器,通过它指定该控制器管理那些Pod matchLabels: # Labels匹配规则 app: counter-pod matchExpressions: # Expressions匹配规则 - key: app operator: In values: - counter-pod template: # 模板,当副本数量不足时,会根据下面的模板创建Pod模板 metadata: labels: app: counter-pod spec: restartPolicy: Never # 重启策略只能设置为Never或OnFailure containers: - name: counter image: busybox:1.30 command: ["/bin/sh","-c","for i in 9 8 7 6 5 4 3 2 1;do echo $i;sleep 20;done"]
- Job案例
apiVersion: batch/v1 # 版本号 kind: Job # 类型 metadata: # 元数据 name: pc-job # 名称 namespace: dev #命名空间 spec: # 详情描述 manualSelector: true # 是否可以使用selector选择器选择Pod,默认为false parallelism: 1 指定job需要成功允许pods的次数。默认值:1 completions: 1 #指定job 在任一时刻应该并发运行pod 的数量。默认值:1 selector: # 选择器,通过它指定该控制器管理那些Pod matchLabels: # Labels匹配规则 app: counter-pod template: # 模板,当副本数量不足时,会根据下面的模板创建Pod模板 metadata: labels: app: counter-pod spec: restartPolicy: Never # 重启策略只能设置为Never或OnFailure containers: - name: counter image: busybox:1.30 command: [ "/bin/sh","-c","for i in 9 8 7 6 5 4 3 2 1;do echo $i;sleep 3;done" ]
讯享网#查看job运行情况 kubectl get job -n dev -w
5.5.CronJob(CJ)
- CronJob控制器以Job控制器为其管控对象,并借助它管理Pod资源对象,Job控制器定义的作业任务在其控制器资源创建之后便会立即执行,但CronJob可以以类似Linux操作系统的周期性任务作业计划的方式控制器运行时间点及重复运行的方式,换言之,CronJob可以在特定的时间点反复去执行Job任务。
- CronJob的资源清单:
apiVersion: batch/v1beta1 # 版本号 kind: CronJob # 类型 metadata: # 元数据 name: # 名称 namespace: #命名空间 labels: controller: cronjob spec: # 详情描述 schedule: #cron格式的作业调度运行时间点,用于控制任务任务时间执行 concurrencyPolicy: #并发执行策略 failedJobsHistoryLimit: #为失败的任务执行保留的历史记录数,默认为1 successfulJobsHistoryLimit: #为成功的任务执行保留的历史记录数,默认为3 jobTemplate: #job控制器模板,用于为cronjob控制器生成job对象,下面其实就是job的定义 metadata: {
} spec: completions: 1 #指定Job需要成功运行Pod的总次数,默认为1 parallelism: 1 #指定Job在任一时刻应该并发运行Pod的数量,默认为1 activeDeadlineSeconds: 30 #指定Job可以运行的时间期限,超过时间还没结束,系统将会尝试进行终止 backoffLimit: 6 #指定Job失败后进行重试的次数,默认为6 template: #模板,当副本数量不足时,会根据下面的模板创建Pod模板 spec: restartPolicy: Never #重启策略只能设置为Never或OnFailure containers: - name: counter image: busybox:1.30 command: [ "/bin/sh","-c","for i in 9 8 7 6 5 4 3 2 1;do echo $i;sleep 20;done" ]
- schedule:cron表达式,用于指定任务的执行时间。
-
- */1 * * * *:表示分 时 日 月 周。
-
- 分钟的值从0到59。
-
- 小时的值从0到23。
-
- 日的值从1到31。
-
- 月的值从1到12。
-
- 星期的值从0到6,0表示星期日。
-
- 多个时间可以用逗号隔开,范围可以用连字符给出:* 可以作为通配符,/表示每…
- concurrencyPolicy:并发执行策略
-
- Allow:运行Job并发运行(默认)。
-
- Forbid:禁止并发运行,如果上一次运行尚未完成,则跳过下一次运行。
-
- Replace:替换,取消当前正在运行的作业并使用新作业替换它。
- 案例
讯享网apiVersion: batch/v1beta1 kind: CronJob metadata: name: pc-cronjob namespace: dev labels: controller: cronjob spec: schedule: "*/1 * * * *" jobTemplate: metadata: spec: template: spec: restartPolicy: OnFailure containers: - name: timing image: busybox:latest command: ["echo","hello k8s cronjob!"]
#查看cronjob 任务pod kubectl get pod -n dev

5.6.StatefulSet(有状态服务)
- 无状态应用:
-
- 认为Pod都是一样的。
- 没有顺序要求。
- 不用考虑在哪个Node节点上运行。
- 随意进行伸缩和扩展。
- 有状态应用:
-
- 有顺序的要求。
- 认为每个Pod都是不一样的。
- 需要考虑在哪个Node节点上运行。
- 需要按照顺序进行伸缩和扩展。
- 让每个Pod都是独立的,保持Pod启动顺序和唯一性。
- StatefulSet是Kubernetes提供的管理有状态应用的负载管理控制器。
- StatefulSet部署需要HeadLinessService(无头服务)。
为什么需要HeadLinessService(无头服务)?
- 在用Deployment时,每一个Pod名称是没有顺序的,是随机字符串,因此是Pod名称是无序的,但是在StatefulSet中要求必须是有序 ,每一个Pod不能被随意取代,Pod重建后pod名称还是一样的。
- 而Pod IP是变化的,所以是以Pod名称来识别。Pod名称是Pod唯一性的标识符,必须持久稳定有效。这时候要用到无头服务,它可以给每个Pod一个唯一的名称 。
- StatefulSet常用来部署RabbitMQ集群、Zookeeper集群、MySQL集群、Eureka集群等。
- 案例模板
讯享网apiVersion: v1 kind: Service metadata: name: service-headliness namespace: dev spec: selector: app: nginx-pod clusterIP: None # 将clusterIP设置为None,即可创建headliness Service type: ClusterIP ports: - port: 80 # Service的端口 targetPort: 80 # Pod的端口 --- apiVersion: apps/v1 kind: StatefulSet metadata: name: pc-statefulset namespace: dev spec: replicas: 3 serviceName: service-headliness selector: matchLabels: app: nginx-pod template: metadata: labels: app: nginx-pod spec: containers: - name: nginx image: nginx:1.17.1 ports: - containerPort: 80
- Deployment和StatefulSet的区别:Deployment没有唯一标识而StatefulSet有唯一标识。
- StatefulSet的唯一标识是根据主机名+一定规则生成的。
- StatefulSet的唯一标识是
主机名.headless Service名称.命名空间.svc.cluster.local。
5.6.1.StatefulSet的金丝雀发布
- StatefulSet支持两种更新策略:OnDelete和RollingUpdate(默认),其中OnDelete表示删除之后才更新,RollingUpdate表示滚动更新
apiVersion: v1 kind: Service metadata: name: service-headliness namespace: dev spec: selector: app: nginx-pod clusterIP: None # 将clusterIP设置为None,即可创建headliness Service type: ClusterIP ports: - port: 80 # Service的端口 targetPort: 80 # Pod的端口 --- apiVersion: apps/v1 kind: StatefulSet metadata: name: pc-statefulset namespace: dev spec: replicas: 3 type: RollingUpdate updateStrategy: rollingUpdate: partition: 2 #表示从第2个分区开始更新,默认是0 serviceName: service-headliness #headliness Service名称 selector: matchLabels: app: nginx-pod template: metadata: labels: app: nginx-pod spec: containers: - name: nginx image: nginx:1.17.1 ports: - containerPort: 80
6.k8s 的service服务
- 在kubernetes中,Pod是应用程序的载体,我们可以通过Pod的IP来访问应用程序,但是Pod的IP地址不是固定的,这就意味着不方便直接采用Pod的IP对服务进行访问。
- 为了解决这个问题,kubernetes提供了为一组pod提供负载均衡,并且提供一个统一的入口地址,通过访问Service的入口地址就能访问到后面的Pod服务。
- Service在很多情况下只是一个概念,真正起作用的其实是kube-proxy服务进程,每个Node节点上都运行了一个kube-proxy的服务进程。当创建Service的时候会通过API Server向etcd写入创建的Service的信息,而kube-proxy会基于监听的机制发现这种Service的变化,然后它会将最新的Service信息转换为对应的访问规则。
讯享网# 10.97.97.97:80 是service提供的访问入口 # 当访问这个入口的时候,可以发现后面有三个pod的服务在等待调用, # kube-proxy会基于rr(轮询)的策略,将请求分发到其中一个pod上去 # 这个规则会同时在集群内的所有节点上都生成,所以在任何一个节点**问都可以。 [root@k8s-node1 ~]# ipvsadm -Ln IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn TCP 10.97.97.97:80 rr -> 10.244.1.39:80 Masq 1 0 0 -> 10.244.1.40:80 Masq 1 0 0 -> 10.244.2.33:80 Masq 1 0 0
- kube-proxy支持的两种工作模式:
-
- iptables模式:
-
-
- iptables模式下,kube-proxy为Service后端的每个Pod创建对应的iptables规则,直接将发向Cluster IP的请求重定向到一个Pod的IP上。
-
-
-
- 该模式下kube-proxy不承担四层负载均衡器的角色,只负责创建iptables规则。该模式的优点在于较userspace模式效率更高,但是不能提供灵活的LB策略,当后端Pod不可用的时候无法进行重试。
-
-
- ipvs模式:
-
-
- ipvs模式和iptables类似,kube-proxy监控Pod的变化并创建相应的ipvs规则。ipvs相对iptables转发效率更高,除此之外,ipvs支持更多的LB算法。
-
- 开启ipvs(必须安装ipvs内核模块,否则会降级为iptables):
kubectl edit cm kube-proxy -n kube-system

讯享网#删除原来的kube-proxy pod kubectl delete pod -l k8s-app=kube-proxy -n kube-system 测试ipvs模块是否开启成功 ipvsadm -Ln
6.1. Service类型
- Service的资源清单:
apiVersion: v1 # 版本 kind: Service # 类型 metadata: # 元数据 name: # 资源名称 namespace: # 命名空间 spec: selector: # 标签选择器,用于确定当前Service代理那些Pod app: nginx type: NodePort # Service的类型,指定Service的访问方式 clusterIP: #虚拟服务的IP地址,不写会默认生成 sessionAffinity: # session亲和性,支持ClientIP、None两个选项,默认值为None,ClientIP,即来自同一个客户端发起的所有请求都会转发到固定的一个Pod上 ports: # 端口信息 - port: 8080 # Service端口 protocol: TCP # 协议 targetPort : # Pod端口 nodePort: # 主机端口
6.1.1.Endpoint(service关联pod一种资源)
- Endpoint是kubernetes中的一个资源对象,存储在etcd中,用来记录一个service对应的所有Pod的访问地址,它是根据service配置文件中的selector描述产生的。
- 一个service由一组Pod组成,这些Pod通过Endpoints暴露出来,Endpoints是实现实际服务的端点集合。换言之,service和Pod之间的联系是通过Endpoints实现的。
讯享网#查看service 的详细信息 kubectl describe svc nginx-service -n app

spec.type的说明:
- ClusterIP:默认值,它是kubernetes系统自动分配的虚拟IP,只能在集群内部访问。
- NodePort:将Service通过指定的Node上的端口暴露给外部,通过此方法,就可以在集群外部访问服务。
- LoadBalancer:使用外接负载均衡器完成到服务的负载分发,注意此模式需要外部云环境的支持。
- ExternalName:把集群外部的服务引入集群内部,直接使用。
6.1.2.ClusterIP类型service
- 只允许集群内部访问
apiVersion: v1 kind: Service metadata: name: nginx-service namespace: app spec: selector: # 标签选择器,用于确定当前Service代理那些Pod app: nginx clusterIP: 10.0.0.133 # service的IP地址,如果不写,默认会生成一个 type: ClusterIP ports: # - port: 80 # Service端口 protocol: TCP targetPort : 80
6.1.3.HeadLiness类型的Service
- 这类Service不会分配Cluster IP,如果想要访问Service,只能通过Service的域名进行查询。

- 创建service-headliness.yaml文件,内容如下:
讯享网apiVersion: v1 kind: Service metadata: name: service-headliness namespace: dev spec: selector: app: nginx-pod clusterIP: None # 将clusterIP设置为None,即可创建headliness Service type: ClusterIP ports: - port: 80 # Service的端口 targetPort: 80 # Pod的端口
6.2.4.NodePort类型的Service
- NodePort的工作原理就是将Service的端口映射到Node的一个端口上,然后就可以通过
NodeIP:NodePort来访问Service了。 - 创建service-nodeport.yaml文件,内容如下:
apiVersion: v1 kind: Service metadata: name: service-nodeport namespace: dev spec: selector: app: nginx-pod type: NodePort # Service类型为NodePort ports: - port: 80 # Service的端口 targetPort: 80 # Pod的端口 nodePort: 30002 # 指定绑定的node的端口(默认取值范围是30000~32767),如果不指定,会默认分配
- 查看Service:
讯享网kubectl get svc service-nodeport -n dev -o wide
6.1.5.LoadBalancer类型的Service
- LoadBalancer和NodePort很相似,目的都是向外部暴露一个端口,区别在于LoadBalancer需要在集群的外部再配置一个负载均衡设备,外部服务发送到这个设备上的请求,会被设备负载之后转发到集群中。
6.1.6. ExternalName类型的Service
- ExternalName类型的Service用于引入集群外部的服务,它通过externalName属性指定一个服务的地址,然后在集群内部访问此Service就可以访问到外部的服务了。
- 创建service-externalname.yaml文件,内容如下:
apiVersion: v1 kind: Service metadata: name: test-external namespace: app spec: type: ExternalName externalName: 192.168.2.214 ports: - name: http port: 80 protocol: TCP targetPort: 80 #目标端口
6.1.7.k8s 接入外部数据库
- 集群内部访问外部数据库或者中间件一般采用endpoints与service关联方式映射。
- 创建endpoints-mysql.yaml文件,内容如下:
讯享网apiVersion: v1 kind: Endpoints metadata: name: mysql-214 namespace: app subsets: - addresses: - ip: 192.168.2.214 ports: - port: 16303
- 创建 service-mysql.yaml文件,内容如下:
apiVersion: v1 kind: Service metadata: name: mysql-214 #要与endpoints 的名称一样 namespace: app spec: type: ClusterIP ports: - port: 16303 # Service端口 protocol: TCP targetPort : 16303
6.1.8.部署案例
-
- 创建nginx-deployment.yaml 文件
讯享网apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment namespace: app spec: replicas: 1 strategy: #策略 type: RollingUpdate rollingUpdate: #滚动更新 maxSurge: 30% #最大额外可以存在的副本数,可以为百分比,也可以为整数; 默认25% maxUnavailable: 30% #最大不可用状态的 ;Pod 的最大值,可以为百分比,也可以为整数,默认25% selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.17.3 ports: - containerPort: 80
-
- 创建 nginx-service-nodeport.yaml
apiVersion: v1 kind: Service metadata: name: service-nodeport namespace: app spec: selector: app: nginx type: NodePort # Service类型为NodePort ports: - port: 80 # Service的端口 targetPort: 80 # Pod的端口 nodePort: 30082 # 指定绑定的node的端口(默认取值范围是30000~32767),如果不指定,会默认分配
-
- 测试访问
讯享网#查看service kubectl get svc service-nodeport -n app -o wide 或者 kubectl describe service service-nodeport -n app

6.2.ingress 资源
- Service对集群之外暴露服务的主要方式有两种:NodePort和LoadBalancer,但是这两种方式,都有一定的缺点:
-
- NodePort方式的缺点是会占用很多集群机器的端口,那么当集群服务变多的时候,这个缺点就愈发明显。
-
- LoadBalancer的缺点是每个Service都需要一个LB,浪费,麻烦,并且需要kubernetes之外的设备的支持。
- 基于这种现状,kubernetes提供了Ingress资源对象,Ingress只需要一个NodePort或者一个LB就可以满足暴露多个Service的需求。
6.2.1安装ingress需要的环境
#wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/mandatory.yaml #wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/provider/baremetal/service-nodeport.yaml [root@k8s_master ~]# wget --no-check-certificate https://oss.linuxtxc.com/ingress-controller.zip [root@k8s_master ~]# unzip ingress-controller.zip [root@k8s_master ~]# cd ingress-controller/ [root@k8s_master ~]# kubectl apply -f ./

6.2.2.Http代理
- 为服务创建 service,yaml文件内容如下:
讯享网apiVersion: v1 kind: Service metadata: name: nginx-service namespace: app spec: selector: # 标签选择器,用于确定当前Service代理那些Pod app: nginx type: ClusterIP ports: # - port: 80 # Service端口 protocol: TCP targetPort : 80 --- apiVersion: v1 kind: Service metadata: name: tomcat-service namespace: app spec: selector: app: tomcat type: ClusterIP ports: - port: 8080 targetPort: 8080
- 创建ingress-http.yaml文件,内容如下:
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: ingress-http namespace: app spec: rules: - host: nginx.linuxtxc.com http: paths: - path: / backend: serviceName: nginx-service servicePort: 80 - host: tomcat.linuxtxc.com http: paths: - path: / backend: serviceName: tomcat-service servicePort: 8080
- 查看ingress端口:
讯享网kubectl get ing ingress-http -n app

#查看访问ingress端口 kubectl get service -n ingress-nginx

- 访问URL:http://nginx.linuxtxc.com:32443(可以在本地hosts文件中添加解析访问)

6.2.3.Https代理
讯享网为ingress 配置https: (1)openssl req -newkey rsa:4096 -nodes -sha256 -keyout /opt/k8s/https/linuxtxc.com.key -x509 -out /opt/k8s/https/linuxtxc.com.crt -subj /C=CN/ST=BJ/L=BJ/O=DEVOPS/CN=linuxtxc.com -days 3650 (2)kubectl create secret tls tls-linuxtxc.com --key=/opt/k8s/https/linuxtxc.com.key --cert=/opt/k8s/https/linuxtxc.com.crt -n app req 产生证书签发申**令 -newkey 生成新私钥 rsa:4096 生成秘钥位数 -nodes 表示私钥不加密 -sha256 使用SHA-2哈希算法 -keyout 将新创建的私钥写入的文件名 -x509 签发X.509格式证书命令。X.509是最通用的一种签名证书格式。 -out 指定要写入的输出文件名 -subj 指定用户信息 -days 有效期
- 创建ingress-https.yaml
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: ingress-https namespace: app spec: tls: - hosts: - nginx.linuxtxc.com - tomcat.linxtxc.com secretName: tls-linuxtxc.com 指定秘钥 rules: - host: nginx.linuxtxc.com http: paths: - path: / backend: serviceName: nginx-service servicePort: 80 - host: tomcat.linuxtxc.com http: paths: - path: / backend: serviceName: tomcat-service servicePort: 8080
- 查看ingress访问端口
讯享网kubectl get service -n ingress-nginx
7.k8s的数据存储
- Volume是Pod中能够被多个容器访问的共享目录,它被定义在Pod上,然后被一个Pod里面的多个容器挂载到具体的文件目录下,kubernetes通过Volume实现同一个Pod中不同容器之间的数据共享以及数据的持久化存储。Volume的生命周期不和Pod中的单个容器的生命周期有关,当容器终止或者重启的时候,Volume中的数据也不会丢失。
- kubernetes的Volume支持多种类型,比较常见的有下面的几个:
-
- 简单存储:EmptyDir、HostPath、NFS。
-
- 高级存储:PV、PVC。
-
- 配置存储:ConfigMap、Secret。
7.1.EmptyDir
- 它是最基础的volume类型,一个EmptyDir就是Host 上的一个空目录,当pod被分配到 Node时创建,它的初始内容为空,当pod 被销毁时,EmptyDir中的数据也会永久删除
- EmptyDir的用途如下:
-
- 临时空间,例如用于某些应用程序运行时所需的临时目录,且无须永久保留。
-
- 一个容器需要从另一个容器中获取数据的目录(多容器共享目录)。
- 创建volume-emptydir.yaml,内容如下:(一个容器从一个容器中获取数据的目录(多容器共享目录))
apiVersion: v1 kind: Pod metadata: name: volume-emptydir namespace: dev spec: containers: - name: nginx image: nginx:1.17.1 imagePullPolicy: IfNotPresent ports: - containerPort: 80 volumeMounts: # 将logs-volume挂载到nginx容器中对应的目录,该目录为/var/log/nginx - name: logs-volume mountPath: /var/log/nginx - name: busybox image: busybox:1.30 imagePullPolicy: IfNotPresent command: ["/bin/sh","-c","tail -f /logs/access.log"] # 初始命令,动态读取指定文件 volumeMounts: #将logs-volume挂载到busybox容器中的对应目录,该目录为/logs - name: logs-volume mountPath: /logs volumes: # 声明volume,name为logs-volume,类型为emptyDir - name: logs-volume emptyDir: {
}
- 查看pod
讯享网kubectl get pod volume-emptydir -n dev -o wide

- 访问pod中的 nginx
curl 172.16.67.8

- 查看指定容器的标准输出:
讯享网kubectl logs -f volume-emptydir -n dev -c busybox

7.2.HostPath
- HostPath就是将Node主机中的一个实际目录挂载到Pod中,以供容器使用,这样的设计就可以保证Pod销毁了,但是数据依旧可以保存在Node主机上。
- 创建volume-hostpath.yaml文件,内容如下:
apiVersion: v1 kind: Pod metadata: name: volume-hostpath namespace: dev spec: containers: - name: nginx image: nginx:1.17.1 imagePullPolicy: IfNotPresent ports: - containerPort: 80 volumeMounts: # 将logs-volume挂载到nginx容器中对应的目录,该目录为/var/log/nginx - name: logs-volume mountPath: /var/log/nginx - name: busybox image: busybox:1.30 imagePullPolicy: IfNotPresent command: ["/bin/sh","-c","tail -f /logs/access.log"] # 初始命令,动态读取指定文件 volumeMounts: # 将logs-volume挂载到busybox容器中的对应目录,该目录为/logs - name: logs-volume mountPath: /logs volumes: # 声明volume,name为logs-volume,类型为hostPath - name: logs-volume hostPath: path: /opt/logs/nginx type: DirectoryOrCreate # 目录存在就使用,不存在就先创建再使用
type的值的说明:
- DirectoryOrCreate:目录存在就使用,不存在就先创建后使用。
- Directory:目录必须存在。
- FileOrCreate:文件存在就使用,不存在就先创建后使用。
- File:文件必须存在。
- Socket:unix套接字必须存在。
- CharDevice:字符设备必须存在。
- BlockDevice:块设备必须存在。
查看pod
讯享网kubectl get pod volume-hostpath -n dev -o wide

- 访问Pod中的Nginx:
curl 172.16.34.7

- 去node节点找到hostPath映射的目录(我是在node01上,如果在此目录中创建文件,到容器中也是可以看到的。)

7.3.NFS
- HostPath虽然可以解决数据持久化的问题,但是一旦Node节点故障了,Pod如果转移到别的Node节点上,又会出现问题,此时需要准备单独的网络存储系统,比较常用的是NFS
- NFS是一个网络文件存储系统,可以搭建一台NFS服务器,然后将Pod中的存储直接连接到NFS系统上,这样,无论Pod在节点上怎么转移,只要Node和NFS的对接没有问题,数据就可以成功访问。
7.3.1.安装NFS服务
- 下载软件包
讯享网yum install -y nfs-utils rpcbind
- 准备一个共享目录:
mkdir -pv /opt/data
- vim /etc/exports,将共享目录以读写权限暴露给
172.16.8.0/24网段中的所有主机:
讯享网/opt/data 172.16.8.0/24(rw,no_root_squash) #加载配置 exportfs -r #启动nfs服务 systemctl start rpcbind systemctl enable rpcbind systemctl start nfs-server systemctl enable nfs-server
- K8s node上安装nfs-utils ,但并不启动服务
yum -y install nfs-utils #查看NFS挂载情况(-d:仅显示已被NFS客户端加载的目录; -e:显示NFS服务器上所有的共享目录。) showmount -e 172.16.8.217

- 高可用备份方式,可以选择在某一节点上执行:
讯享网mount -t nfs 172.16.8.217:/opt/data /mnt
7.3.2.pod挂载案例
- 创建volume-nfs.yaml文件,内容如下:
apiVersion: v1 kind: Pod metadata: name: volume-nfs namespace: dev spec: containers: - name: nginx image: nginx:1.17.1 imagePullPolicy: IfNotPresent ports: - containerPort: 80 volumeMounts: # 将logs-volume挂载到nginx容器中对应的目录,该目录为/var/log/nginx - name: logs-volume mountPath: /var/log/nginx - name: busybox image: busybox:1.30 imagePullPolicy: IfNotPresent command: ["/bin/sh","-c","tail -f /logs/access.log"] # 初始命令,动态读取指定文件 volumeMounts: # 将logs-volume挂载到busybox容器中的对应目录,该目录为/logs - name: logs-volume mountPath: /logs volumes: # 声明volume - name: logs-volume nfs: server: 172.16.8.217 # NFS服务器地址 path: /opt/data/nfs # 共享文件路径
- 在NFS服务器上查看 文件共享情况

7.4.PV与PVC
7.4.1.PV(Persistent Volume)
- 是持久化卷的意思,是对底层的共享存储的一种抽象。它和底层具体的共享存储技术有关,并通过插件完成和共享存储的对接。(它没有namespace区别的划分)
讯享网pv的关键配置参数说明: 存储类型:底层实际存储的类型,kubernetes支持多种存储类型,每种存储类型的配置有所不同。 存储能力(capacity):目前只支持存储空间的设置(storage=1Gi),不过未来可能会加入IOPS、吞吐量等指标的配置。 访问模式(accessModes): 用来描述用户应用对存储资源的访问权限,访问权限包括下面几种方式: ReadWriteOnce(RWO):读写权限,但是只能被单个节点挂载。 ReadOnlyMany(ROX):只读权限,可以被多个节点挂载。 ReadWriteMany(RWX):读写权限,可以被多个节点挂载。 需要注意的是,底层不同的存储类型可能支持的访问模式不同。 回收策略( persistentVolumeReclaimPolicy): 当PV不再被使用之后,对其的处理方式,目前支持三种策略: Retain(保留):保留数据,需要管理员手动清理数据。 Recycle(回收):清除PV中的数据,效果相当于rm -rf /volume/*。 Delete(删除):和PV相连的后端存储完成volume的删除操作,常见于云服务器厂商的存储服务。 需要注意的是,底层不同的存储类型可能支持的回收策略不同。 存储类别(storageClassName):PV可以通过storageClassName参数指定一个存储类别。 具有特定类型的PV只能和请求了该类别的PVC进行绑定。 未设定类别的PV只能和不请求任何类别的PVC进行绑定。 状态(status):一个PV的生命周期,可能会处于4种不同的阶段。 Available(可用):表示可用状态,还未被任何PVC绑定。 Bound(已绑定):表示PV已经被PVC绑定。 Released(已释放):表示PVC被删除,但是资源还没有被集群重新释放。 Failed(失败):表示该PV的自动回收失败。
- 创建pv-nfs.yaml,内容如下(使用的之前创建的NFS服务):
apiVersion: v1 kind: PersistentVolume metadata: name: pv1 spec: nfs: # 存储类型吗,和底层正则的存储对应 path: /opt/data/pv1 server: 172.16.8.217 capacity: # 存储能力,目前只支持存储空间的设置 storage: 1Gi accessModes: # 访问模式 - ReadWriteMany persistentVolumeReclaimPolicy: Retain # 回收策略 --- apiVersion: v1 kind: PersistentVolume metadata: name: pv2 spec: nfs: # 存储类型吗,和底层正则的存储对应 path: /opt/data/pv2 共享文件路径 server: 172.16.8.217 capacity: # 存储能力,目前只支持存储空间的设置 storage: 2Gi accessModes: # 访问模式 - ReadWriteMany persistentVolumeReclaimPolicy: Retain # 回收策略 --- apiVersion: v1 kind: PersistentVolume metadata: name: pv3 spec: nfs: # 存储类型吗,和底层正则的存储对应 path: /opt/data/pv3 server: 172.16.8.217 capacity: # 存储能力,目前只支持存储空间的设置 storage: 3Gi accessModes: # 访问模式 - ReadWriteMany persistentVolumeReclaimPolicy: Retain # 回收策略
- 查看PV
讯享网kubectl get pv

7.4.2.PVC(Persistent Volume Claim)
- 是资源的申请,用来声明对存储空间、访问模式、存储类别需求信息,下面是PVC的资源清单文件:
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: pvc namespace: dev spec: accessModes: #访问模式 - ReadWriteMany selector: # 采用标签对PV选择 storageClassName: # 存储类别 resources: # 请求空间 requests: storage: 5Gi
PVC的关键配置参数说明:
- 访客模式(accessModes):用于描述用户应用对存储资源的访问权限。
- 用于描述用户应用对存储资源的访问权限:
-
- 选择条件(selector):通过Label Selector的设置,可使PVC对于系统中已存在的PV进行筛选。
-
- 存储类别(storageClassName):PVC在定义时可以设定需要的后端存储的类别,只有设置了该class的pv才能被系统选出。
-
- 资源请求(resources):描述对存储资源的请求。
- 创建pvc-test.yaml,内容如下:
讯享网apiVersion: v1 kind: PersistentVolumeClaim metadata: name: pvc1 namespace: dev spec: accessModes: # 访客模式 - ReadWriteMany resources: # 请求空间 requests: storage: 1Gi --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: pvc2 namespace: dev spec: accessModes: # 访客模式 - ReadWriteMany resources: # 请求空间 requests: storage: 1Gi --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: pvc3 namespace: dev spec: accessModes: # 访客模式 - ReadWriteMany resources: # 请求空间 requests: storage: 5Gi
- 查看PVC
kubectl get pvc -n dev -o wide #pvc3未绑定,是因为没有满足需求的pv

- 查看PV
讯享网kubectl get pv

7.4.3.创建pod使用PVC
- 创建pvc-pod.yaml文件,内容如下:
apiVersion: v1 kind: Pod metadata: name: pod1 namespace: dev spec: containers: - name: busybox image: busybox:1.30 command: ["/bin/sh","-c","while true;do echo pod1 >> /root/out.txt; sleep 10; done;"] volumeMounts: - name: volume mountPath: /root/ volumes: - name: volume persistentVolumeClaim: claimName: pvc1 readOnly: false --- apiVersion: v1 kind: Pod metadata: name: pod2 namespace: dev spec: containers: - name: busybox image: busybox:1.30 command: ["/bin/sh","-c","while true;do echo pod1 >> /root/out.txt; sleep 10; done;"] volumeMounts: - name: volume mountPath: /root/ volumes: - name: volume persistentVolumeClaim: claimName: pvc2 readOnly: false
- 查看NFS服务器上共享的的目录

- 资源释放:
-
- 用户删除PVC来释放PV。
-
- 当存储资源使用完毕后,用户可以删除PVC,和该PVC绑定的PV将会标记为“已释放”,但是还不能立刻和其他的PVC进行绑定。通过之前PVC写入的数据可能还留在存储设备上,只有在清除之后该PV才能再次使用。
- 资源回收:
-
- kubernetes根据PV设置的回收策略进行资源的回收。
-
- 对于PV,管理员可以设定回收策略,用于设置与之绑定的PVC释放资源之后如何处理遗留数据的问题。只有PV的存储空间完成回收,才能供新的PVC绑定和使用。
创建PVC后一直绑定不了PV的原因
- ①PVC的空间申请大小比PV的空间要大。
- ②PVC的storageClassName和PV的storageClassName不一致。
- ③PVC的accessModes和PV的accessModes不一致。
7.4.4.使用glusterfs 创建 pv,并挂载使用
讯享网#glusterfs分布式存储部署 wget http://oss.linuxtxc.com/%E7%AC%94%E8%AE%B0/%E5%88%86%E5%B8%83%E5%BC%8F%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9Fglusterfs%E5%AE%89%E8%A3%85%E6%96%87%E6%A1%A3.md #kubernetes 所有节点都安装 glusterfs客户端 yum install -y glusterfs glusterfs-fuse
- 创建glusterfs的endpoints
apiVersion: v1 kind: Namespace metadata: name: app --- apiVersion: v1 kind: Endpoints metadata: name: glusterfs-cluster namespace: app subsets: - addresses: - ip: 172.16.8.212 - ip: 172.16.8.213 - ip: 172.16.8.214 ports: - port: 49152 protocol: TCP
- 创建pv使用glusterfs
讯享网apiVersion: v1 kind: PersistentVolume metadata: name: glusterfs-pv01 spec: capacity: storage: 1Gi accessModes: - ReadWriteMany glusterfs: endpoints: glusterfs-cluster path: app-data #创建的存储卷 readOnly: false --- apiVersion: v1 kind: PersistentVolume metadata: name: glusterfs-pv02 spec: capacity: storage: 2Gi accessModes: - ReadWriteMany glusterfs: endpoints: glusterfs-cluster path: app-data #创建的存储卷 readOnly: false
- 创建PVC
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: glusterfs-pvc01 namespace: app spec: accessModes: - ReadWriteMany resources: requests: storage: 2Gi
- 创建使用Glusterfs卷的应用
讯享网apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment namespace: app spec: replicas: 2 selector: matchLabels: name: nginx template: metadata: labels: name: nginx spec: containers: - name: nginx image: nginx ports: - containerPort: 80 volumeMounts: - name: nginxglusterfs mountPath: "/usr/share/nginx/html" volumes: - name: nginxglusterfs persistentVolumeClaim: claimName: glusterfs-pvc
- 查看容器是否成功挂载
kubectl exec -it deployment-glu-pv-9fb5fb64-kl48h -n app mount | grep app-data

7.5.configmap
- ConfigMap是一种API对象,用来将非加密数据保存到键值对中。可以用作环境变量、命令行参数或者存储卷中的配置文件。
- ConfigMap可以将环境变量配置信息和容器镜像解耦,便于应用配置的修改。如果需要存储加密信息时可以使用Secret对象。
7.5.1.使用命令行创建
讯享网(1)使用目录创建 kubectl create configmap configmap名 --from-file=/path (--from-file,指定在目录下的所有文件都会被用在ConfigMap里面创建一个键值对,键的名字就是文件名,值就是文件的内容) (2)使用文件创建 kubectl create configmap configmap名 --from-file=./file1 --from-file=./file2 (--from-file,可以使用多次,同样键为文件名,值为文件中的内容) (3)通过key-value字符串创建 kubectl create configmap configmap名 --from-literal=key1=123 --from-literal=key2=234 (4)通过env文件创建 kubectl create configmap configmap名 --from-env-file=env.txt 其中,env.txt的文件格式为: key1=* key2=*
- 使用ConfigMap有以下几个限制条件:
-
- ConfigMap必须在pod之前创建
-
- configmap受namespace的限制,只能相同namespace的pod才可以引用
7.5.2.通过Volume 方式挂载
- 将ConfigMap中的内容挂载为容器内部的文件或目录
- 创建 configmap-nginx.yaml,内容如下:
apiVersion: v1 kind: ConfigMap metadata: name: configmap namespace: web data: stream.conf: | stream.conf { server { listen 1550; proxy_pass 192.168.3.125:16303; } }
讯享网 kubectl get cm -n web

- 将configmap中的配置通过volume挂载
apiVersion: v1 kind: Pod metadata: name: pod-configmap namespace: web spec: containers: - name: nginx image: nginx:1.17.1 volumeMounts: - name: config mountPath: /etc/nginx/vhosts #没有则会自动创建,目录下有文件则会覆盖掉 volumes: - name: config configMap: name: configmap #指的是要从哪个configmap里读取数据
讯享网kubectl exec -it pod-configmap -n web /bin/sh

7.5.3.通过SubPath 使原目录文件不被覆盖
- 创建 configmap-php.yaml,内容如下:
apiVersion: v1 kind: ConfigMap metadata: name: configmap-php namespace: web data: index.php: | <?php echo phpversion(); ?>
讯享网kubectl get cm -n web

- 创建 volume-configmap-php.yaml,内容如下
apiVersion: v1 kind: Pod metadata: name: pod-configmap-php namespace: web spec: containers: - name: nginx image: nginx:1.17.1 volumeMounts: - name: config mountPath: /usr/share/nginx/html/index.php
subPath: index.php #与configmap中的key相同 volumes: - name: config configMap: name: configmap-php #指的是要从哪个configmap里读取数据
讯享网 kubectl exec -it pod-configmap-php -n web /bin/sh

- 只覆盖指定的文件
apiVersion: v1 kind: Pod metadata: name: nginx-configmap namespace: app spec: containers: - name: nginx image: nginx:1.17.1 command: [ "/bin/sh", "-c", "sleep 3600" ] volumeMounts: - name: config mountPath: /etc/nginx/nginx.conf subPath: nginx.conf #subPath:要覆盖文件的相对路径 volumes: - name: config configMap: name: configmap-nginx #configMap的名称 items: #用于只挂载configmap中特定的key - key: nginx.conf #ConfigMap中key的名称 path: nginx.conf # 此处的path相当于 mv nginx.conf nginx.conf
7.6.Secret
- 跟configMap非常类似的对象,它主要是用于存储敏感信息,例如密码,密钥,证书等等。
- Secret有三种类型:
-
- Opaque
-
- kubernetes.io/dockerconfigjson
- ServiceAccount
7.6.1.Opaque
- base64 编码格式的 Secret,用来存储密码、密钥等;但数据也可以通过base64 –decode解码得到原始数据,所有加密性很弱。
讯享网#使用命令行 创建secret (1)kubectl create secret generic db-user-pass --from-file=./username.txt --from-file=./password.txt (2)kubectl create secret generic db-user-pass --from-literal=username=admin --from-literal=password=1f2d1e2e67df #手动创建base64加密 echo -n 'admin' | base64 echo -n '1f2d1e2e67df' | base64 #解密 echo 'MWYyZDFlMmU2N2Rm' | base64 --decode
- 创建 secret-opaque.yaml,内容如下:
apiVersion: v1 kind: Secret metadata: name: mysecret namespace: dev type: Opaque data: username: YWRtaW4= #修改为base64加密后的 password: MWYyZDFlMmU2N2Rm
讯享网 kubectl get secret mysecret -n dev -o yaml

- 也可以将一个非 base64 编码的字符串直接放入 Secret 中, 当创建或更新该 Secret 时,此字段将被编码。
apiVersion: v1 kind: Secret metadata: name: web-secret namespace: web type: Opaque stringData: config.yaml: | apiUrl: "https://my.api.com/api/v1" username: admin password:
- 创建pod-secret.yaml,将secert 挂载到 pod中,内容如下:
讯享网apiVersion: v1 kind: Pod metadata: name: pod-secret namespace: dev spec: containers: - name: nginx image: nginx:1.17.1 volumeMounts: - name: config mountPath: /secret/config readOnly: true volumes: - name: config secret: secretName: mysecret
kubectl exec -it pod-secret -n dev /bin/sh

- 只挂载Secret中特定的key
讯享网apiVersion: v1 kind: Pod metadata: name: pod-secret-01 namespace: dev spec: containers: - name: nginx image: nginx:1.17.1 volumeMounts: - name: secret mountPath: /opt readOnly: true volumes: - name: secret secret: secretName: mysecret items: - key: username path: cert/username #username 将存储在/opt/cert/username 下
kubectl exec -it pod-secret-01 -n dev /bin/sh

- 将Secret设置为环境变量
讯享网apiVersion: v1 kind: Pod metadata: name: secret-env-pod spec: containers: - name: redis image: redis env: - name: SECRET_USERNAME valueFrom: secretKeyRef: name: mysecret key: username - name: SECRET_PASSWORD valueFrom: secretKeyRef: name: mysecret key: password
7.6.2.kubernetes.io/dockerconfigjson
- 用来存储私有docker registry的认证信息。
kubectl create secret docker-registry myregistrykey --docker-server=192.168.3.124 --docker-username=admin --docker-password=admin123 --docker-email=<your-email> --namespace=dev
- 在创建 Pod 的时候,通过 imagePullSecrets 来引用刚创建的 myregistrykey
讯享网apiVersion: v1 kind: Pod metadata: name: dev spec: containers: - name: foo image: janedoe/awesomeapp:v1 imagePullSecrets: - name: myregistrykey
7.6.3.ServiceAccount
- 用来访问Kubernetes API,由Kubernetes自动创建,并且会自动挂载到Pod的 /run/secrets/kubernetes.io/serviceaccount 目录中。
- 每个namespace下有一个名为default的默认的ServiceAccount对象,这个ServiceAccount里有一个名为Tokens的可以作为Volume一样被Mount到Pod里的Secret,当Pod启动时这个Secret会被自动Mount到Pod的指定目录下,用来协助完成Pod中的进程访问API Server时的身份鉴权过程。
#创建一个sa 名称为admin kubectl create serviceaccount admin -n dev
- 如果一个Pod在定义时没有指定spec.serviceAccountName属性,则会默认赋值为default,可进行如下指定
讯享网apiVersion: v1 kind: Pod metadata: name: sa-demo namespace: dev labels: app: myapp release: canary spec: containers: - name: myapp image: nginx:1.17.2 ports: - name: nginx-port containerPort: 80 serviceAccountName: admin #此处指令为指定sa的名称
7.7.GlusterFS+Heketi实现volume动态扩容
- SC:是StorageClass的缩写,表示存储类;这种资源主要用来对pv资源的自动供给提供接口;所谓自动供给是指用户无需手动创建pv,而是在创建pvc时对应pv会由persistentVolume-controller自动创建并完成pv和pvc的绑定;使用sc资源的前提是对应后端存储必须支持restfull类型接口的管理接口,并且pvc必须指定对应存储类名称来引用SC;简单讲SC资源就是用来为后端存储提供自动创建pv并关联对应pvc的接口;
- Heketi是一个提供RESTful API管理GlusterFS卷的框架,便于管理员对GlusterFS进行操作:
#yum下载 #wget https://mirrors.aliyun.com/centos/7/storage/x86_64/gluster-9/Packages/h/heketi-9.0.0-1.el7.x86_64.rpm wget http://oss.linuxtxc.com/deploy/rpm/heketi-9.0.0-1.el7.x86_64.rpm #wget https://mirrors.aliyun.com/centos/7/storage/x86_64/gluster-9/Packages/h/heketi-client-9.0.0-1.el7.x86_64.rpm wget http://oss.linuxtxc.com/deploy/rpm/heketi-client-9.0.0-1.el7.x86_64.rpm
7.7.1.安装 heketi
讯享网#安装rpm包,我只在master上安装 yum http://oss.linuxtxc.com/deploy/rpm/heketi-9.0.0-1.el7.x86_64.rpm yum http://oss.linuxtxc.com/deploy/rpm/heketi-client-9.0.0-1.el7.x86_64.rpm
- 修改service文件
vim /usr/lib/systemd/system/heketi.service ...................... [Unit] Description=Heketi Server [Service] Type=simple WorkingDirectory=/var/lib/heketi EnvironmentFile=/etc/heketi/heketi.json User=root ExecStart=/usr/bin/heketi --config=/etc/heketi/heketi.json Restart=on-failure StandardOutput=syslog StandardError=syslog [Install] WantedBy=multi-user.target
- 修改heketi配置文件
讯享网vim /etc/heketi/heketi.json ............................. #修改端口,防止端口冲突 "port": "18080", ...... #允许认证 "use_auth": true, ...... #admin用户的key改为adminkey "key": "adminkey" #普通用户的key改为userkey "key": "userkey" ...... #修改执行插件为ssh,并配置ssh的所需证书,注意要能对集群中的机器免密ssh登陆,使用ssh-copy-id把pub key拷到每台glusterfs服务器上 "executor": "ssh", "sshexec": {
"keyfile": "/etc/heketi/heketi_key", "user": "root", "port": "22", "fstab": "/etc/fstab" }, ...... # 定义heketi数据库文件位置 "db": "/var/lib/heketi/heketi.db" ...... #调整日志输出级别 "loglevel" : "warning"
- 配置ssh密钥
[root@k8s-master heketi]# ssh-keygen -f /etc/heketi/heketi_key -t rsa -N '' [root@k8s-master heketi]# ssh-copy-id -i /etc/heketi/heketi_key.pub 172.16.8.212 [root@k8s-master heketi]# ssh-copy-id -i /etc/heketi/heketi_key.pub 172.16.8.213 [root@k8s-master heketi]# ssh-copy-id -i /etc/heketi/heketi_key.pub 172.16.8.214
- 验证登录
讯享网ssh -i /etc/heketi/heketi_key root@172.16.8.212

- 启动heketi
systemctl start heketi systemctl enable heketi
- 查看heketi服务状态
讯享网systemctl status heketi

7.7.2.heketi添加glusterfs
- Heketi添加cluster
heketi-cli --user admin --server http://172.16.8.124:18080 --secret adminkey --json cluster create ................................. {
"id":"7aed6bc432f7fa81e65e021542","nodes":[],"volumes":[],"block":true,"file":true,"blockvolumes":[]}

- 将所有glusterfs节点作为node添加到cluster
讯享网[root@k8s-master heketi]# heketi-cli --server http://172.16.8.124:18080 --user "admin" --secret "adminkey" node add --cluster "7aed6bc432f7fa81e65e021542" --management-host-name 172.16.8.212 --storage-host-name 172.16.8.212 --zone 1 [root@k8s-master heketi]# heketi-cli --server http://172.16.8.124:18080 --user "admin" --secret "adminkey" node add --cluster "7aed6bc432f7fa81e65e021542" --management-host-name 172.16.8.213 --storage-host-name 172.16.8.213 --zone 1 [root@k8s-master heketi]# heketi-cli --server http://172.16.8.124:18080 --user "admin" --secret "adminkey" node add --cluster "7aed6bc432f7fa81e65e021542" --management-host-name 172.16.8.214 --storage-host-name 172.16.8.214 --zone 1 注:要保存每个glusterfs节点ID

- 添加device,volume是基于device创建的,目前heketi仅支持使用裸分区或裸磁盘(未格式化)添加为device,不支持文件系统,所以每个glusterfs节点上要有未格式化的磁盘
[root@k8s-master heketi]# heketi-cli --server http://172.16.8.124:18080 --user "admin" --secret "adminkey" --json device add --name="/dev/sdb" --node "3aee8bc18c72fbcc547e8bff4" [root@k8s-master heketi]# heketi-cli --server http://172.16.8.124:18080 --user "admin" --secret "adminkey" --json device add --name="/dev/sdb" --node "833b827e2d72c73a597c7d82a5ebdbc5" [root@k8s-master heketi]# heketi-cli --server http://172.16.8.124:18080 --user "admin" --secret "adminkey" --json device add --name="/dev/sdb" --node "968afeb52b8924cac7ffac6db3963e03"

- 创建一个大小为2G,副本为2的volume
讯享网[root@k8s-master dev]# heketi-cli --server http://172.16.8.124:18080 --user "admin" --secret "adminkey" volume create --size 2 --replica 2 #通过下面信息,可以看到Heketi创建了名为vol_15249e32eb410cabe764e4a06e254a7e的数据卷。

7.7.3.创建资源使用volume
- 创建storageclass-glusterfs.yaml,内容如下:
apiVersion: v1 kind: Secret metadata: name: heketi-secret namespace: app data: # echo -n "mypassword" | base64 / base64 encoded "password" key: bXlwYXNzd29yZA== type: kubernetes.io/glusterfs --- apiVersion: storage.k8s.io/v1beta1 kind: StorageClass metadata: name: glusterfs provisioner: kubernetes.io/glusterfs allowVolumeExpansion: true parameters: resturl: "http://172.16.8.124:18080" clusterid: "7aed6bc432f7fa81e65e021542" restauthenabled: "true" restuser: "admin" #secretNamespace: "default" #secretName: "heketi-secret" restuserkey: "adminkey" gidMin: "40000" gidMax: "50000" volumetype: "replicate:2"
讯享网kubectl get storageclass -n app

- 创建glusterfs-pvc.yaml内容如下:
kind: PersistentVolumeClaim apiVersion: v1 metadata: name: glusterfs-pvc namespace: app annotations: volume.beta.kubernetes.io/storage-class: "glusterfs" spec: accessModes: - ReadWriteMany resources: requests: storage: 2Gi
讯享网 kubectl get pvc -n app #有绑定的volume才算创建成功,同时PV也会自动创建

- 创建 mysql-deployment.yaml,内容如下:
apiVersion: apps/v1 kind: Deployment metadata: name: mysql namespace: app spec: selector: matchLabels: name: mysql template: metadata: labels: name: mysql spec: containers: - name: mysql image: mysql:5.7 imagePullPolicy: IfNotPresent env: - name: MYSQL_ROOT_PASSWORD value: root ports: - containerPort: 3306 volumeMounts: - name: glusterfs-mysql-data mountPath: "/var/lib/mysql" volumes: - name: glusterfs-mysql-data persistentVolumeClaim: claimName: glusterfs-pvc readOnly: false
- 查看volume挂载情况
讯享网kubectl exec -it mysql-5b-n6xld -n app mount | grep 172

- 查看glusterfs集群状态
gluster volume status

7.7.4.动态修改PVC
- 查看当前PVC容量

讯享网#修改yaml配置 vim glusterfs-pvc.yaml kubectl apply -f glusterfs-pvc.yaml
- 再次查看 PVC
kubectl get pvc -n app

8.k8s的安全认证
8.1.概念描述
● API Server是访问和管理资源对象的唯一入口。任何一个请求访问API Server,都要经过下面的三个流程:
○ ① Authentication(认证):身份鉴别,只有正确的账号才能通过认证。
○ ② Authorization(授权):判断用户是否有权限对访问的资源执行特定的动作。
○ ③ Admission Control(注入控制):用于补充授权机制以实现更加精细的访问控制功能。
API Server目前支持的几种授权策略
● AlwaysDeny:表示拒绝所有请求,一般用于测试。
● AlwaysAllow:允许接收所有的请求,相当于集群不需要授权流程(kubernetes默认的策略)。
● ABAC:基于属性的访问控制,表示使用用户配置的授权规则对用户请求进行匹配和控制。
● Webhook:通过调用外部REST服务对用户进行授权。
● Node:是一种专用模式,用于对kubelet发出的请求进行访问控制。
● RBAC:基于角色的访问控制(kubeadm安装方式下的默认选项)。
● RBAC(Role Based Access Control) : 基于角色的访问控制,主要是在描述一件事情:给哪些对象授权了哪些权限。
● RBAC涉及到了下面几个概念:
○ 对象:User、Groups、ServiceAccount。
○ 角色:代表着一组定义在资源上的可操作的动作(权限)的集合。
○ 绑定:将定义好的角色和用户绑定在一起。
● RBAC引入了4个顶级资源对象:
○ Role、ClusterRole:角色,用于指定一组权限。
○ RoleBinding、ClusterRoleBinding:角色绑定,用于将角色(权限的集合)赋予给对象。
8.2.Role、ClusterRole
- Role的资源清单文件:
讯享网# Role只能对命名空间的资源进行授权,需要指定namespace apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: authorization-role namespace: dev rules: - apiGroups: [""] # 支持的API组列表,""空字符串,表示核心API群 resources: ["pods"] # 支持的资源对象列表 verbs: ["get","watch","list"]
- ClusterRole的资源清单文件:
# ClusterRole可以对集群范围内的资源、跨namespace的范围资源、非资源类型进行授权 apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: authorization-clusterrole rules: - apiGroups: [""] # 支持的API组列表,""空字符串,表示核心API群 resources: ["pods"] # 支持的资源对象列表 verbs: ["get","watch","list"]
讯享网rules中的参数说明: apiGroups: #支持的API组列表。 "","apps","autoscaling","batch"。 resources: #支持的资源对象列表。 "services","endpoints","pods","secrets","configmaps","crontabs","deployments","jobs","nodes","rolebindings","clusterroles","daemonsets","replicasets","statefulsets","horizontalpodautoscalers","replicationcontrollers","cronjobs"。 verbs: #对资源对象的操作方法列表。 "get", "list", "watch", "create", "update", "patch", "delete", "exec"。
8.3.RoleBinding、ClusterRoleBinding
- 角色绑定用来把一个角色绑定到一个目标对象上,绑定目标可以是User、Group或者ServiceAccount。
- RoleBinding的资源清单文件:
# RoleBinding可以将同一namespace中的subject对象绑定到某个Role下,则此Subject具有该Role定义的权限 apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: authorization-role-binding namespace: dev subjects: - kind: User name: test apiGroup: rbac.authorization.k8s.io roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: authorization-role
- ClusterRoleBinding的资源清单文件:
讯享网# ClusterRoleBinding在整个集群级别和所有namespaces将特定的subject与ClusterRole绑定,授予权限 apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: authorization-clusterrole-binding subjects: - kind: User name: test apiGroup: rbac.authorization.k8s.io roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: authorization-clusterrole
- RoleBinding引用ClusterRole进行授权
○RoleBinding可以引用ClusterRole,对属于同一命名空间内ClusterRole定义的资源主体进行授权。
○ 一种很常用的做法是,集群管理员为集群范围预定义好一组规则(ClusterRole),然后在多个命名空间中重复使用这些ClusterRole。这样可以大幅度提高授权管理工作效率,也使得各个命名空间下的基础性授权规则和使用体验保持一致。
# 虽然authorization-clusterrole是一个集群角色,但是因为使用了RoleBinding # 所以test用户只能读取dev命名空间中的资源 apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: authorization-clusterrole-binding subjects: - kind: User name: test apiGroup: rbac.authorization.k8s.io roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: authorization-clusterrole
8.4.RBAC案例
- 创建一个只能管理dev命名空间下Pods资源的账号。
讯享网#创建用户的私钥 cd /etc/kubernetes/pki (umask 077;openssl genrsa -out devuser.key 2048) #创建证书签署请求(O:组织名 CN:用户名) openssl req -new -key devuser.key -out devuser.csr -subj "/CN=devuser/O=devgroup" #签署证书 openssl x509 -req -in devuser.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out devuser.crt -days 3650 #设置集群、用户、上下文信息(不设置--kubeconfig,如--kubeconfig=/root/.devuser.config,则会默认放在家目录下的./kube 中) kubectl config set-cluster kubernetes --embed-certs=true --certificate-authority=/etc/kubernetes/pki/ca.crt --server=https://172.16.8.124:6443 kubectl config set-credentials devuser --embed-certs=true --client-certificate=devuser.crt --client-key=devuser.key kubectl config set-context devuser@kubernetes --cluster=kubernetes --user=devuser #切换账号到devuser kubectl config use-context devuser@kubernetes
#查看(当前还没有权限执行当前操作,还需要对用户授权) kubectl get pods -n dev

- 如果要使用linux的普通用户管理集群
讯享网[root@k8s_master ~]# useradd devuser [root@k8s_master ~]# mkdir /home/devuser/.kube [root@k8s_master ~]# cp .kube/config /home/devuser/.kube/ [root@k8s_master ~]# chown -R devuser:devuser /home/devuser/
- 查看管理账号,并切换
#输出合并后的kubeconfig的内容,格式为 YAML,密文内容不会显示(--kubeconfig,可以指定只显示某个账户的kubeconfig内容) kubectl config view #切回admin账户 kubectl config use-context kubernetes-admin@kubernetes
- 创建Role和RoleBinding,为devuser授权
- 创建dev-role.yaml文件,内容如下:
讯享网apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: dev-role namespace: dev rules: - apiGroups: [""] # 支持的API组列表,""空字符串,表示核心API群 resources: ["pods"] # 支持的资源对象列表 verbs: ["get","watch","list"] --- kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: authorization-role-binding namespace: dev subjects: - kind: User name: devuser apiGroup: rbac.authorization.k8s.io roleRef: kind: Role name: dev-role apiGroup: rbac.authorization.k8s.io
#切换成 devuser,再次查看 kubectl get pods -n dev

8.5.准入控制
- 通过了前面的认证和授权之后,还需要经过准入控制通过之后,API Server才会处理这个请求。
- 准入控制是一个可配置的控制器列表,可以通过在API Server上通过命令行设置选择执行哪些注入控制器。
讯享网--enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,ResourceQuota,DefaultTolerationSeconds
- 只有当所有的注入控制器都检查通过之后,API Server才会执行该请求,否则返回拒绝。
- 当前可配置的Admission Control(准入控制)
○ AlwaysAdmit:允许所有请求。○ AlwaysDeny:禁止所有请求,一般用于测试。
○ AlwaysPullImages:在启动容器之前总去下载镜像。
○ DenyExecOnPrivileged:它会拦截所有想在Privileged Container上执行命令的请求。
○ ImagePolicyWebhook:这个插件将允许后端的一个Webhook程序来完成admission controller的功能。
○ Service Account:实现ServiceAccount实现了自动化。
○ SecurityContextDeny:这个插件将使用SecurityContext的Pod中的定义全部失效。
○ ResourceQuota:用于资源配额管理目的,观察所有请求,确保在namespace上的配额不会超标。
○ LimitRanger:用于资源限制管理,作用于namespace上,确保对Pod进行资源限制。
○ InitialResources:为未设置资源请求与限制的Pod,根据其镜像的历史资源的使用情况进行设置。
○ NamespaceLifecycle:如果尝试在一个不存在的namespace中创建资源对象,则该创建请求将被拒 绝。当删除一个namespace时,系统将会删除该namespace中所有对象。
○ DefaultStorageClass:为了实现共享存储的动态供应,为未指定StorageClass或PV的PVC尝试匹配默认StorageClass,尽可能减少用户在申请PVC时所需了解的后端存储细节。
○ DefaultTolerationSeconds:这个插件为那些没有设置forgiveness tolerations并具有notready:NoExecute和unreachable:NoExecute两种taints的Pod设置默认的“容忍”时间,为5min。
○ PodSecurityPolicy:这个插件用于在创建或修改Pod时决定是否根据Pod的security context和可用的 PodSecurityPolicy对Pod的安全策略进行控制
9.k8s+prometheus+grafana实现集群监控
#下载yaml文件 https://oss.linuxtxc.com/k8s-prometheus-grafana.zip #解压 unzip k8s-prometheus-grafana.zip #创建资源 cd k8s-prometheus-grafana/ kubectl apply -f node-exporter.yaml kubectl apply -f grafana/ kubectl apply -f prometheus/
- 访问prometheus(http://192.168.3.124:30003/targets)

- 访问node-exporter(http://192.168.3.124:31672/metrics)

- 访问Grafana(http://192.168.3.124:30106/login),默认用户密码均为admin

- 添加数据源,以下使用的代理模式(推荐),仅限k8s内部访问

-
- 也可以使用直接访问模式

- 导入面板:Dashboards->Import(导入面板,可以直接输入模板编号315在线导入,或者下载好对应的json模板文件本地导入)

- 查看展示效果

10.k8s集群管理平台部署
10.1.kuboard安装
讯享网#下载 #wget http://oss.linuxtxc.com/deploy/yaml/kuboard-v3.yaml wget https://addons.kuboard.cn/kuboard/kuboard-v3.yaml kubectl apply -f kuboard-v3.yaml
访问 Kuboard
- 在浏览器中打开链接
http://172.16.8.124:30080 - 输入初始用户名和密码,并登录
- 用户名:
admin - 密码:
Kuboard123
- 用户名:

10.2.kubesphere安装
#wget https://github.com/kubesphere/ks-installer/releases/download/v3.2.1/kubesphere-installer.yaml #wget https://github.com/kubesphere/ks-installer/releases/download/v3.2.1/cluster-configuration.yaml wget http://oss.linuxtxc.com/deploy/yaml/kubesphere/kubesphere-installer.yaml wget http://oss.linuxtxc.com/deploy/yaml/kubesphere/cluster-configuration.yaml kubectl apply -f kubesphere-installer.yaml kubectl apply -f cluster-configuration.yaml #查看安装情况 kubectl logs -n kubesphere-system $(kubectl get pod -n kubesphere-system -l app=ks-install -o jsonpath='{.items[0].metadata.name}') -f

- 解决方法:
讯享网#yaml文件中的storageClass默认为空,需要在两处添加,我的storageClass为"glusterfs" vim cluster-configuration.yaml

#再次查看安装情况(安装成功后会有如下提示) kubectl logs -n kubesphere-system $(kubectl get pod -n kubesphere-system -l app=ks-install -o jsonpath='{.items[0].metadata.name}') -f

- 访问 curl:http://172.16.8.124:30880/

10.3.部署dashboard
讯享网wget https://oss.linuxtxc.com/deploy/yaml/kubernetes-dashboard.yaml kubectl apply -f kubernetes-dashboard.yaml #查看Nodeport访问端口 kubectl get service -n kubernetes-dashboard
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uHlpixpw-82)(C:\Users\linux\AppData\Roaming\Typora\typora-user-images\image-.png)]
- https://nodeIP:30081
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mPMbyF26-83)(C:\Users\linux\AppData\Roaming\Typora\typora-user-images\image-.png)]
#创建用户 kubectl create serviceaccount dashboard-admin -n kube-system #用户授权 kubectl create clusterrolebinding dashboard-admin --clusterrole=cluster-admin --serviceaccount=kube-system:dashboard-admin #获取token kubectl describe secrets -n kube-system $(kubectl -n kube-system get secret | awk '/dashboard-admin/{print $1}')
- 输入token后
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y4RhyYhs-84)(C:\Users\linux\AppData\Roaming\Typora\typora-user-images\image-.png)]
11.helm
1.1.helm安装
讯享网#GitHub下载地址 #https://github.com/helm/helm/releases wget https://get.helm.sh/helm-v3.5.4-linux-amd64.tar.gz tar -xf helm-v3.5.4-linux-amd64.tar.gz mv linux-amd64/helm /usr/local/bin/ #查看版本 helm version
1.2.helm安装harbor
#下载harbor Chart helm repo add harbor https://helm.goharbor.io helm fetch harbor/harbor --untar #进入目录 cd harbor
- 编辑values.yaml文件
讯享网


版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/43632.html