1.K8S集群部署
1.1.k8s快速入门
1.1.1.简介
Kubernetes简称k8s,是用于自动部署,扩展和管理容器化应用程序的开源系统。
- 中文官网:https://kubernetes.io/zh/
- 中文社区:https://www.kubernetes.org.cn/
- 官方文档:https://kubernetes.io/zh/docs/home/
- 社区文档:http://docs.kubernetes.org.cn/
部署方式演进:https://kubernetes.io/zh/docs/concepts/overview/what-is-kubernetes/
容器化技术的特点:
- 可移植性:不依赖具体的操作系统或云平台,比如在阿里云或腾讯云直接随意迁移。
- 占地小:容器只需要其应用程序以及它需要运行的所有容器和库的依赖清单,不需要将所有的依赖库都打包在一起。
- 共享 bin 和 lib:不同的容器可以共享 bin 和 lib,进一步节省了空间。
容器化部署面临问题:弹性伸缩,故障转移,部署模式等
Docker Swarm 是 Docker 自家针对集群化部署管理的解决方案,优点很明显,可以更紧密集成到Docker 生态系统中。虽说 Swarm 是 Docker 亲儿子,但依旧没有 k8s 流行,不流行很大程度是因为商业、生态的原因。
Kubernetes 为你提供了一个可弹性运行分布式系统的框架。 Kubernetes 会满足你的扩展要求、故障转移、部署模式等。
Kubernetes 为你提供:
-
服务发现和负载均衡
Kubernetes 可以使用 DNS 名称或自己的 IP 地址公开容器,如果进入容器的流量很大,
Kubernetes 可以负载均衡并分配网络流量,从而使部署稳定。 -
存储编排
Kubernetes 允许你自动挂载你选择的存储系统,例如本地存储、公共云提供商等。
-
自动部署和回滚
你可以使用 Kubernetes 描述已部署容器的所需状态,它可以以受控的速率将实际状态 更改为期望状态。例如,你可以自动化 Kubernetes 来为你的部署创建新容器, 删除现有容器并将它们的所有资源用于新容器。
-
自动完成装箱计算
Kubernetes 允许你指定每个容器所需 CPU 和内存(RAM)。 当容器指定了资源请求时,
Kubernetes 可以做出更好的决策来管理容器的资源。 -
自我修复
Kubernetes 重新启动失败的容器、替换容器、杀死不响应用户定义的 运行状况检查的容器,并且在准备好服务之前不将其通告给客户端。
-
密钥与配置管理
Kubernetes 允许你存储和管理敏感信息,例如密码、OAuth 令牌和 ssh 密钥。 你可以在不重建容器镜像的情况下部署和更新密钥和应用程序配置,也无需在堆栈配置中暴露密钥。
编排系统的需求催生 k8s
尽管Docker为容器化的应用程序提供了开放标准,但随着容器越来越多出现了一系列新问题:
- 如何协调和调度这些容器?
- 如何在升级应用程序时不会中断服务?
- 如何监视应用程序的运行状况?
- 如何批量重新启动容器里的程序?
解决这些问题需要容器编排技术,可以将众多机器抽象,对外呈现出一台超大机器。现在业界比较流行的有:k8s、Mesos、Docker Swarm。
在业务发展初期只有几个微服务,这时用 Docker 就足够了,但随着业务规模逐渐扩大,容器越来越多,运维人员的工作越来越复杂,这个时候就需要编排系统解救opers。
一个成熟的容器编排系统需要具备以下能力:
- 处理大量的容器和用户
- 负载均衡
- 鉴权和安全性
- 管理服务通信
- 多平台部署
Docker与k8s 难舍难分
-
Docker 和 k8s 在业界非常流行,都已经是事实上的标准。
-
Docker 是用于构建、分发、运行容器的平台和工具。
-
而 k8s 实际上是一个使用 Docker 容器进行编排的系统,主要围绕 pods 进行工作。Pods 是 k8s 生态中最小的调度单位,可以包含一个或多个容器。
-
Docker 和 k8s 是根本上不同的技术,两者可以很好的协同工作。
1.1.2.组件
https://kubernetes.io/zh/docs/concepts/overview/components/
当你部署完 Kubernetes, 即拥有了一个完整的集群。一个 Kubernetes 集群由一组被称作节点的机器组成。这些节点上运行 Kubernetes 所管理的容器化应用。集群具有至少一个工作节点。工作节点托管作为应用负载的组件的 Pod 。控制平面管理集群中的工作节点和 Pod 。 为集群提供故障转移和高可用性,这些控制平面一般跨多主机运行,集群跨多个节点运行。
1.控制平面组件(Control Plane Components)
控制平面的组件对集群做出全局决策(比如调度),以及检测和响应集群事件
-
kube-apiserver(api)
- 对外暴露k8s的api接口,是外界进行资源操作的唯一入口
- 提供认证、授权、访问控制、API注册和发现等机制
-
etcd
- etcd 是兼具一致性和高可用性的键值数据库,可以作为保存 Kubernetes 所有集群数据的后台数据库。
- Kubernetes 集群的 etcd 数据库通常需要有个备份计划。
-
kube-scheduler(seched)
- 控制平面组件,负责监视新创建的、未指定运行节点(node)的 Pods,选择节点让 Pod 在上面运行。
-
kube-controller-manager(c-m)
- 在主节点上运行 控制器 的组件。
- 这些控制器包括:
- 节点控制器(Node Controller): 负责在节点出现故障时进行通知和响应
- 副本控制器(Replication Controller): 负责为系统中的每个副本控制器对象维护正确数量的 Pod
- 端点控制器(Endpoints Controller): 填充端点(Endpoints)对象(即加入 Service 与 Pod)
- 服务帐户和令牌控制器(Service Account & Token Controllers): 为新的命名空间创建默认帐户和 API 访问令牌
-
cloud-controller-manager(c-c-m)
- 云控制器管理器是指嵌入特定云的控制逻辑的 控制平面组件。 云控制器管理器允许您链接聚合到云提供商的应用编程接口中, 并分离出相互作用的组件与您的集群交互的组件。
- 下面的控制器都包含对云平台驱动的依赖:
- 节点控制器(Node Controller): 用于在节点终止响应后检查云提供商以确定节点是否已被删除
- 路由控制器(Route Controller): 用于在底层云基础架构中设置路由
- 服务控制器(Service Controller): 用于创建、更新和删除云提供商负载均衡器
2.Node组件
节点组件在每个节点上运行,维护运行的 Pod 并提供 Kubernetes 运行环境。
-
kubelet
- 一个在集群中每个节点(node)上运行的代理。 它保证容器(containers)都 运行在 Pod中。
-
kube-proxy
- kube-proxy 是集群中每个节点上运行的网络代理, 实现 Kubernetes 服务(Service) 概念的一部分。
- kube-proxy 维护节点上的网络规则。这些网络规则允许从集群内部或外部的网络会话与 Pod进行网络通信。
-
容器运行时(Container Runtime)
- 容器运行环境是负责运行容器的软件。
- Kubernetes 支持多个容器运行环境: Docker、 containerd、CRI-O 以及任何实现 Kubernetes CRI (容器运行环境接口)。
1.1.3.核心概念
- Container:容器,可以是docker启动的一个容器
- Pod
- k8s使用Pod来组织一组容器
- 一个Pod中的所有容器共享同一网络
- Pod是k8s中最小部署单元
- Volume
- 声明在Pod容器中可访问的文件目录
- 可以被挂载在Pod中一个或多个容器指定路径下
- 支持多种后端存储抽象(本地存储,分布式存储,云存储…)
- Controllers:更高层次对象,部署和管理Pod
- ReplicaSet:确保预期的Pod副本数量
- Deplotment:无状态应用部署
- StatefulSet:有状态应用部署
- DaemonSet:确保所有Node都运行一个指定Pod
- Job:一次性任务
- Cronjob:定时任务
- Deployment
- 定义一组Pod的副本数目、版本等
- 通过控制器(Controller)维持Pod数目(自动回复失败的Pod)
- 通过控制器以指定的策略控制版本(滚动升级,回滚等)
- Service
- 定义一组Pod的访问策略
- Pod的负载均衡,提供一个或者多个Pod的稳定访问地址
- 支持多种方式(ClusterIP,NodePort,LoadBalance)
- Label:标签,用于对象资源的查询,筛选
- Namespace:命名空间,逻辑隔离
- 一个集群内部的逻辑隔离机制(鉴权,资源)
- 每个资源都属于一个namespace
- 同一个namespace所有资源名不能重复
- 不同namespace可以资源名重复
通过kubernetes的API来操作整个集群,可以通过kubectl,ui,curl最终发送 http+json/yaml 方式的请求给 API Server,然后控制k8s集群。k8s里的所有资源对象都可以采用yaml或JSON格式的文件定义或描述。
流程描述:
- 通过 Kubectl 提交一个创建 RC(Replication Controller)的请求,该请求通过API Server被写入etcd 中
- 此时 Controller Manager 通过 API Server 的监听资源变化的接口监听到此 RC 事件
- 分析之后,发现当前集群中还没有它所对应的 Pod 实例
- 于是根据 RC 里的 Pod 模板定义生成一个 Pod 对象,通过 API Server 写入 etcd
- 此事件被 Scheduler 发现,它立即执行一个复杂的调度流程,为这个新 Pod 选定一个落后的Node,然后通过 API Server 将这一结果写入到 etcd 中
- 目标 Node 上运行的 kubelet 进程通过 API Server 监测到这个 “新生的” Pod,并按照它的定义,启动该 Pod 并负责它的一生,直到 Pod 的生命结束
- 随后,我们通过 kubectl 提交一个新的映射到该 Pod 的 Service 创建请求
- ControllerManager 通过 Label 标签查询到关联的 Pod 实例,然后生成 Service 的 Endpoints 信息,并通过 API Server 写入到 etcd 中
- 接下来,所有 Node 上运行的 Proxy 进程通过 API Server 查询并监听 Service 对象与其对应的Endpoints 信息,建立一个软件方式的负载均衡来实现 Service 访问到后端 Pod 的流量转发功能。
1.1.4.Kubernetes 1.20 版本
Kubernetes 1.20 版本开始将弃用 Docker,是时候拥抱 Containerd 和 Podman 了!(了解)
Kubelet 中对 Docker 支持被弃用,并将在以后的版本中删除。Kubelet 使用一个名为 dockershim 的模块,该模块实现了对Docker的 CRI 支持,在此PR后续版本将删除 dockershim。
1.Kubelete 创建容器步骤
- Kubelet 通过 CRI 接口(gRPC)调用 dockershim,请求创建一个容器。CRI 即容器运行时接口,这一步中,Kubelet 可以视作一个简单的 CRI Client,而 dockershim 就是接收请求的 Server。目前dockershim 的代码其实是内嵌在 Kubelet 中的,所以接收调用就是 Kubelet 进程。
- dockershim 收到请求后,转化成 Docker Daemon 能听懂的请求,发到 Docker Daemon 上请求创建一个容器。
- Docker Daemon 早在 1.12 版本中就已经将针对容器的操作移到另一个守护进程 containerd 中,因此 Docker Daemon 仍然不能帮我们创建容器,而是要请求 containerd 创建一个容器。
- containerd 收到请求后,并不会自己直接去操作容器,而是创建一个叫做 containerd-shim 的进程,让 containerd-shim 去操作容器。是因为容器进程需要一个父进程来做诸如收集状态,维持stdin 等 fd 打开等工作。而假如这个父进程就是 containerd,那每次 containerd 挂掉或升级,整个宿主机上所有的容器都得退出了。而引入了 containerd-shim 就规避了这个问题(containerd 和shim 并不是父子进程关系)。
- 我们知道创建容器需要做一些设置 namespaces 和 cgroups,挂载 root filesystem 等等操作,而这些事该怎么做已经有了公开的规范,那就是 OCI。它的一个参考实现叫做 runC。于是,containerd-shim 在这一步需要调用 runC 这个命令行工具,来启动容器。
- runC 启动完容器后本身会直接退出,containerd-shim 则会成为容器进程的父进程,负责收集容器进程的状态,上报给 containerd,并在容器中 pid 为 1 的进程退出后接管容器中的子进程进行清理,确保不会出现僵尸进程。
通过上面来看, Docker Daemon 和 dockershim 看上去就是两个不干活的东西,Kubelet 为啥不直接调用 containerd 呢?其实和容器历程有关,这里不在阐述。
尽管现在已经有 CRI-O , containerd-plugin 这样更精简轻量的 Runtime 架构,但
dockershim 这一套作为经受了最多生产环境考验的方案,迄今为止仍是 Kubernetes 默认的 Runtime实现。不过 Containerd 逐渐被人们所知晓。
2.展望
虽然未来 Kubelet 删除 dockershim 支持,但并不说明 Docker 马上就不能在 Kubernetes 中使用,目前容器市场 Docker 还是占用很大的比例。这中间会有一个过渡期,大家可以关注 Containerd 或者Podman 。Centos8 开始,仓库源默认容器已经从 Docker 切换为 Podman 。
1.2.k8s集群安装
1.2.1.安装方式
- 二进制方式
- kubeadm(脚手架):推荐
- KubeSphere(KubKey):https://kubesphere.com.cn/docs/quick-start/all-in-one-on-linux/
1.2.2.kubeadm
kubuadm是官方社区推出的一个用于快速部署kubernetes集群的工具。这个工具能通过两条指令完成一个kubernetes集群的部署。
# 创建一个 Master 节点
$ kubeadm init
# 将一个 Node 节点加入到当前集群中
$ kubeadm join <Master 节点的 IP 和端口>
1.2.3.前置要求
- 一台或多台机器,操作系统 CentOS7.x-86_64
- 硬件配置:2GB 或更多 RAM,2个 CPU 或更多 CPU,硬盘30GB或更多
- 集群中所有机器之间网络互通
- 可以访问外网,需要拉取镜像
- 禁止swap分区
1.2.4.部署步骤
- 在所有节点上安装docker和kubeadm
- 部署Kubernetes Master
- 部署Kubernetes Node,将节点加入 Kubernetes 集群中
- 部署容器网络插件
- 部署 Dashboard Web 页面,可视化查看 Kubernetes 资源
1.2.5.环境准备
1.准备工作
- 使用 Vagrant 快速创建三个虚拟机,虚拟机启动前先设置 Virtualbox 主机网络。现全部统一为 192.168.56.1 ,以后所有虚拟机都是 192.168.56.x 的ip地址
- 设置虚拟机存储目录,防止硬盘空间不足
2.启动三个虚拟机
- 使用提供的 vagrant 文件,复制到非中文无空格目录下,运行 vagrant up 启动三个虚拟机。
- 其实 vagrant 完全可以一键部署全部 k8s 集群。
- https://github.com/rootsongjc/kubernetes-vagrant-centos-cluster
- http://github.com/davidkbainbridge/k8s-playground
Vagrantfile
Vagrant.configure("2") do |config|
(1..3).each do |i|
config.vm.define "k8s-node#{i}" do |node|
# 设置虚拟机的Box
node.vm.box = "centos/7"
# 设置虚拟机的主机名
node.vm.hostname="k8s-node#{i}"
# 设置虚拟机的IP
node.vm.network "private_network", ip: "192.168.56.#{99+i}",netmask: "255.255.255.0"
# 设置主机与虚拟机的共享目录
# node.vm.synced_folder "~/Documents/vagrant/share","/home/vagrant/share"
# VirtaulBox相关配置
node.vm.provider "virtualbox" do |v|
# 设置虚拟机的名称
v.name = "k8sб node#{i}"
# 设置虚拟机的内存大小
v.memory = 4096
# 设置虚拟机的CPU个数
v.cpus = 4
end
end
end
end
运行完成后,自动创建好三个虚拟机环境
- 进入三个虚拟机,开启root的密码访问权限(方便使用远程客户端连接),在每台虚拟机执行以下命令
# 进入系统
vagrant ssh k8s-node1
# 密码 vagrant
su root
vi /etc/ssh/sshd_config
# 修改
PasswordAuthentication yes
# 重启服务
systemctl restart sshd.service
exit
exit
- 设置 NAT 网络
每个节点设置网卡1为NAT网络,并且重置MAC地址
3.所有节点设置Linux环境
关闭防火墙
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
# 查看 swap 是否关闭
free -mh
查看及修改hostname
# 查看
hostname
# 修改
hostnamectl set-hostname k8s-master
添加主机名与IP对应关系
# 查看ip
ip addr
vi etc/hosts
10.0.2.15 k8s-master
10.0.2.4 k8s-node1
10.0.2.5 k8s-node2
将桥接的IPv4流量传递到iptables的链
cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF
# 查看是否写入成功
sysctl --system
同步时间(可选)
# 查看时间
date
# 安装 nepdate
yum install -y ntpdate
# 同步最新时间
ntpdate time.windows.com
4.所有节点备份[ 系统快照 ]
[ 备份:预准备环境ok ]
1.2.6.所有节点安装 Docker/Kubeadm/kubelet/kubectl
- kubeadm:初始化集群
- kubelet:在集群的每个节点上用来启动Pod和容器等
- kubectl:集群通信的命令行工具
Kubernetes默认CRI(容器运行时)为 Docker,因此先安装 Docker
1.安装Docker
1)卸载系统之前的Docker
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
2)安装 docker-ce
# 安装必须的依赖
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
# 设置 docker repo 的 yum 位置
sudo yum-config-manager --add-repo
https://download.docker.com/linux/centos/docker-ce.repo
# 安装 docker,以及 docker-cli
sudo yum install -y docker-ce docker-ce-cli containerd.io
3)配置 docker 加速
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-- EOF'
{
"registry-mirrors": ["https://hd8wo2ww.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
4)启动 docker 并设置 docker 开机自启
sudo systemctl enable docker
基础环境准备好,可以给三个虚拟机备份一下。
备份:【 docker20.10.5安装OK 】
2.添加阿里云yum源
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=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
EOF
3.安装kubeadm
# 不指定版本号,将安装最新版本
yum install -y kubelet-1.20.0 kubeadm-1.20.0 kubectl-1.20.0
# 开机启动
systemctl enable kubelet
systemctl start kubelet
1.2.7.部署k8s-master
Kubeadm 是一个提供了 kubeadm init 和 kubeadm join 的工具,作为创建 Kubernetes 集群的
“快捷途径” 的最佳实践。
https://kubernetes.io/zh/docs/reference/setup-tools/kubeadm/
1.初始化集群
在 k8s-master 主节点上执行
kubeadm init \
--apiserver-advertise-address=10.0.2.15 \
--kubernetes-version=v1.20.0 \
--image-repository registry.cn-hangzhou.aliyuncs.com/google_containers \
--service-cidr=10.96.0.0/12 \
--pod-network-cidr=10.244.0.0/16
科普:无类别域间路由(Classless Inter-Domain Routing、CIDR)是一个用于给用户分配IP地址以及在互联网上有效地路由IP数据包的对IP地址进行归类的方法。
运行完成后提前 保存好加入集群的令牌
2.测试kubectl(主节点执行)
执行kubeadm初始化集群成功后生成的指令
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
目前master状态为NotReady,等待网络加入完成即可
- 安装Pod网络插件(参考:1.2.8.安装Pod网络插件(CNI))
1.2.8.Node加入kubernetes集群
将其它两个节点加入master主节点,在k8s-node1 和 k8s-node2 节点上执行
kubeadm join 10.0.2.15:6443 --token so29bx.30m223ap90udbqw6 \
--discovery-token-ca-cert-hash
sha256:e34ec245cf4e6d62827809b05c146d4a9f65a33b7261b0c1ec546cbe4d139e6d
master节点查看k8s所有节点
执行 $ watch kubectl get pod -n kube-system -o wide 监控 pod 进度
1.2.9.安装Pod网络插件(CNI)
目前比较主流的插件
- Flannel
- Calico:https://www.projectcalico.org/
安装 Calico 插件
kubectl apply -f https: //docs.projectcalico.org/manifests/calico.yaml
稍等1-2分钟,网络插件下载好之后,三个节点就会变为Ready状态
如果Node一直是 NotReady 状态,基本上就是网络插件镜像没有拉取成功
caliao网络插件有3个镜像
# 查看指定命名空间的 pods
kubectl get pods -n kube-system
# 查看所有命名空间的 pods
kubectl get pods --all-namespaces
备份:[ k8s1.20.0集群搭建OK ]
1.2.9.入门操作 Kubernetes 集群
1.部署一个Tomcat
会随机部署到一个Node节点
kubectl create deployment tomcat6 --image=tomcate:6.0.53-jre8
# 查看 k8s 所有资源
kubectl get all
# 查看 Pod 部署信息
kubectl get all -o wide
# 获取Tomcat信息
kubectl get pods -o wide
容灾恢复:
- 若Tomcat所在的Node宕机,则会在另外一个Node重新拉取一个Tomcat容器运行
2.暴露 Tomcat 访问
# Pod 的 80 映射容器的 8080,service 会代理 Pod 的 80
kubectl expose deployment tomcat6 --port=80 --target-port=8080 --type=NodePort
# 查看暴露端口
kubectl get svc -o wide
kubectl get all
3.动态扩容测试
kubectl get deployment
# 扩容
kubectl scale --replicas=3 deployment tomcat6
由于扩容了多份,所有无论访问哪个 Node 的指定端口,都可以访问到 tomcat6
4.删除资源
kubectl get all
kubectl delete deployment.apps/tomcat6
kubectl delete service/tomcat6
2.Kubernetes细节
2.1.kubectl
2.1.1.kubectl文档
https://kubernetes.io/zh/docs/reference/kubectl/overview/
2.1.2.资源类型
https://kubernetes.io/zh/docs/reference/kubectl/overview/#%E8%B5%84%E6%BA%90%E7%B1%BB%E5%9E%8B
2.1.3.格式化输出
https://kubernetes.io/zh/docs/reference/kubectl/overview/#%E6%A0%BC%E5%BC%8F%E5%8C%96%E8%BE%93%E5%87%BA
2.1.4.常用操作
https://kubernetes.io/zh/docs/reference/kubectl/overview/#%E7%A4%BA%E4%BE%8B-%E5%B8%B8%E7%94%A8%E6%93%8D%E4%BD%9C
2.1.5.命令参考
https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands
2.2.yaml语法
2.2.1.yml模板
2.2.2.yml字段解析
k8s上搭建nginx容器使用的yaml文件
#必选,版本号,例如v1
apiVersion: v1
#必选,Pod
kind: Pod
#必选,元数据
metadata:
#必选,Pod名称
name: nginx
labels:
#自定义标签名字
app: nginx
#必选,Pod中容器的详细定义
spec:
#必选,Pod中容器列表,一个pod里会有多个容器
containers:
#必选,容器名称
- name: nginx
#必选,容器的镜像名称
image: nginx
#获取镜像的策略 Alawys表示下载镜像 IfnotPresent表示优先使用本地镜像,否则下载镜像,Nerver表示仅使用本地镜像
imagePullPolicy: IfNotPresent
#需要暴露的端口库号列表
ports:
#容器需要监听的端口号
- containerPort: 80
#Pod的重启策略,Always表示一旦不管以何种方式终止运行,kubelet都将重启,OnFailure表示只有Pod以非0退出码退出才重启,Nerver表示不再重启该Pod
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
type: NodePort
sessionAffinity: ClientIP
selector:
app: nginx
ports:
- port: 80
nodePort: 30080
2.3.入门操作
2.3.1.Pod是什么?Controller是什么?
https://kubernetes.io/zh/docs/concepts/workloads/pods/
- 就 Docker 概念的术语而言,Pod 类似于共享名字空间和文件系统卷的一组 Docker 容器。
- Pod天生地为其成员容器提供了两种共享资源:网络和 存储。
Pod 和控制器
你可以使用工作负载资源来创建和管理多个 Pod。 资源的控制器能够处理副本的管理、上线,并在 Pod失效时提供自愈能力。 例如,如果一个节点失败,控制器注意到该节点上的 Pod 已经停止工作, 就可以创建替换性的 Pod。调度器会将替身 Pod 调度到一个健康的节点执行。
下面是一些管理一个或者多个 Pod 的工作负载资源的示例:
- Deployment
- StatefulSet
- DaemonSet
负载资源的控制器通常使用 Pod 模板(Pod Template) 来替你创建 Pod 并管理它们。
2.3.2.Deployment和Service是什么?
Deployment:https://kubernetes.io/zh/docs/concepts/workloads/controllers/deployment/
一个 Deployment 为 Pods 和 ReplicaSets 提供声明式的更新能力。
Service:https://kubernetes.io/zh/docs/concepts/services-networking/service/#service-resource
Kubernetes Service 定义了这样一种抽象:逻辑上的一组 Pod,一种可以访问它们的策略 —— 通常称为微服务。 Service 所针对的 Pods 集合通常是通过选择算符来确定的。
2.3.3.Service的意义
1)部署nginx
kubectl create deployment nginx --image=nginx
2)暴露nginx访问
kubectl expose deployment nginx --port=80 --type=NodePort
- 统一应用访问入口
- Service可以对发送到Pod上的流量进行负载均衡
- Service管理一组Pod
- 防止Pod失联(服务发现),定义一组Pod的访问策略
- Service使用NodePort的方式暴露,这样访问每个节点的端口,都可以访问到这个Pod,如果节点宕机,就会出现问题
2.3.4.Labels和Service
https://kubernetes.io/zh/docs/concepts/overview/working-with-objects/labels/
Service通过 Label Selector(标签选择器)来匹配一系列的Pod,Label Selector允许在Label上做一系列的逻辑操作。
Label 是附加在对象(比如Pod)上的键值对,你可以把他们当做是社交媒体上面的标签(类似话题?)。
Label 对使用者来说是具体特别含义的,因此可以用来组织对象,类似:
- 生产环境(production, test, dev)
- 应用版本((beta, v1.3)
- 服务或者server类型(frontend, backend, database)
Label可以在对象创建的时候设置给它,也可以在其他任意时间修改。kubectl run命令会设置一些默认的Label/Label Selector在新的Pod或者Deployment上。Label和Label Selector之间的关联定义了Deployment和它创建的Pod之间的关联。现在我们可以在Service的帮助下暴露我们的应用了,并且可以给它们设置一些Label
2.3.5.Ingress
1.Ingress是什么?
https://kubernetes.io/zh/docs/concepts/services-networking/ingress/
Ingress 公开了从集群外部到集群内服务的 HTTP 和 HTTPS 路由。 流量路由由 Ingress 资源上定义的规则控制。
- 通过 Service 发现 Pod 进行关联
- 基于域名访问
- 通过 Ingress Controller 实现 Pod 负载均衡
- 支持 TCP/UDP 四层负载均衡和 HTTP 七层负载均衡
可以将 Ingress 配置为服务提供外部可访问的 URL、负载均衡流量、终止 SSL/TLS,以及提供基于名称的虚拟主机等能力。 Ingress 控制器 通常负责通过负载均衡器来实现 Ingress,尽管它也可以配置边缘路由器或其他前端来帮助处理流量。
Ingress 不会公开任意端口或协议。 将 HTTP 和 HTTPS 以外的服务公开到 Internet 时,通常使用Service.Type=NodePort 或 Service.Type=LoadBalancer 类型的服务。
2.Ingress Controller
为了让 Ingress 资源工作,集群必须有一个正在运行的 Ingress 控制器。
与作为 kube-controller-manager 可执行文件的一部分运行的其他类型的控制器不同,Ingress 控制器不是随集群自动启动的。 基于此页面,你可选择最适合你的集群的 ingress 控制器实现。
Kubernetes 作为一个项目,目前支持和维护 AWS, GCE 和 nginx Ingress 控制器。
3.Nginx Ingress
- 用于 Kubernetes 的 NGINX Ingress 控制器 能够与 NGINX Web 服务器(作为代理) 一起使用。
4.使用步骤
- 部署 Ingress Controller
- 创建 Ingress 规则
Node节点打标签,在 k8s-master 主节点上执行,给node打标签是保证Pod分配到该node节点
#给两个node节点打标签
kubectl label nodes k8s-node1 vanje/ingress-controller-ready=true
kubectl label nodes k8s-node2 vanje/ingress-controller-ready=true
部署 Ingress Controller
kubectl apply -f ingress-controller.yaml
ingress-controller.yaml
apiVersion: v1
kind: Namespace
metadata:
name: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
---
kind: ConfigMap
apiVersion: v1
metadata:
name: nginx-configuration
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
---
kind: ConfigMap
apiVersion: v1
metadata:
name: tcp-services
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
---
kind: ConfigMap
apiVersion: v1
metadata:
name: udp-services
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: nginx-ingress-serviceaccount
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: nginx-ingress-clusterrole
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- configmaps
- endpoints
- nodes
- pods
- secrets
verbs:
- list
- watch
- apiGroups:
- ""
resources:
- nodes
verbs:
- get
- apiGroups:
- ""
resources:
- services
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
- apiGroups:
- "extensions"
- "networking.k8s.io"
resources:
- ingresses
verbs:
- get
- list
- watch
- apiGroups:
- "extensions"
- "networking.k8s.io"
resources:
- ingresses/status
verbs:
- update
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: nginx-ingress-role
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- configmaps
- pods
- secrets
- namespaces
verbs:
- get
- apiGroups:
- ""
resources:
- configmaps
resourceNames:
# Defaults to "<election-id>-<ingress-class>"
# Here: "<ingress-controller-leader>-<nginx>"
# This has to be adapted if you change either parameter
# when launching the nginx-ingress-controller.
- "ingress-controller-leader-nginx"
verbs:
- get
- update
- apiGroups:
- ""
resources:
- configmaps
verbs:
- create
- apiGroups:
- ""
resources:
- endpoints
verbs:
- get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: nginx-ingress-role-nisa-binding
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: nginx-ingress-role
subjects:
- kind: ServiceAccount
name: nginx-ingress-serviceaccount
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: nginx-ingress-clusterrole-nisa-binding
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: nginx-ingress-clusterrole
subjects:
- kind: ServiceAccount
name: nginx-ingress-serviceaccount
namespace: ingress-nginx
---
apiVersion: apps/v1
#kind: Deployment
kind: DaemonSet
metadata:
name: nginx-ingress-controller
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
spec:
#replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
template:
metadata:
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
annotations:
prometheus.io/port: "10254"
prometheus.io/scrape: "true"
spec:
# wait up to five minutes for the drain of connections
terminationGracePeriodSeconds: 300
serviceAccountName: nginx-ingress-serviceaccount
hostNetwork: true
dnsPolicy: ClusterFirstWithHostNet
nodeSelector:
#kubernetes.io/os: linux
vanje/ingress-controller-ready: "true"
containers:
- name: nginx-ingress-controller
image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.30.0
args:
- /nginx-ingress-controller
- --configmap=$(POD_NAMESPACE)/nginx-configuration
- --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
- --udp-services-configmap=$(POD_NAMESPACE)/udp-services
- --publish-service=$(POD_NAMESPACE)/ingress-nginx
- --annotations-prefix=nginx.ingress.kubernetes.io
securityContext:
allowPrivilegeEscalation: true
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
# www-data -> 101
runAsUser: 101
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
ports:
- name: http
containerPort: 80
protocol: TCP
- name: https
containerPort: 443
protocol: TCP
livenessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 10
readinessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10254
scheme: HTTP
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 10
lifecycle:
preStop:
exec:
command:
- /wait-shutdown
---
apiVersion: v1
kind: LimitRange
metadata:
name: ingress-nginx
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
spec:
limits:
- min:
memory: 90Mi
cpu: 100m
type: Container
修改参数如下:
- kind: Deployment #修改为DaemonSet
- replicas: 1 #注销此行,DaemonSet不需要此参数
- hostNetwork: true
#添加该字段让docker使用物理机网络,在物理机暴露服务端口(80),注意物理机80端口提前不能被占用 - dnsPolicy: ClusterFirstWithHostNet #使用hostNetwork后容器会使用物理机网络包括DNS,会无法解析内部service,使用此参数让容器使用K8S的DNS
- nodeSelector:vanje/ingress-controller-ready: “true” #添加节点标签
- tolerations: 添加对指定节点容忍度
创建 Ingress 规则
ingress-tomcat7.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: web
spec:
rules:
- host: tomcat.yuandengta.com
http:
paths:
- backend:
serviceName: tomcat7
servicePort: 80
2.4.项目部署
查看创建tomcat的yaml
kubectl create deployment tomcat7 --image=tomcat:7.0-jdk8 --dry-run=client -o
yaml > tomcat7-deployment.yaml
修改 tomcat7-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: tomcat7
name: tomcat7
spec:
# 复制3份,会创建3个 Pod
replicas: 3
selector:
matchLabels:
app: tomcat7
template:
metadata:
labels:
app: tomcat7
spec:
containers:
- image: tomcat:7.0-jdk8
name: tomcat
部署
kubectl apply -f tomcat7-deployment.yaml
对外暴露
kubectl expose deployment tomcat7 --port=80 --target-port=8080 --type=NodePort
--dry-run=client -o yaml
修改 tomcat7-deployment.yaml ,复制红框选择的内容,将其粘贴到 tomcat7-deployment.yaml 文件中
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: tomcat7
name: tomcat7
spec:
replicas: 3
selector:
matchLabels:
app: tomcat7
template:
metadata:
labels:
app: tomcat7
spec:
containers:
- image: tomcat:7.0-jdk8
name: tomcat
---
apiVersion: v1
kind: Service
metadata:
labels:
app: tomcat7
name: tomcat7
spec:
ports:
- port: 80
protocol: TCP
targetPort: 8080
selector:
app: tomcat7
type: NodePort
删除之前的部署
kubectl get all
# 删除部署之后,关联的3个pod也会被级联删除
kubectl delete deployment.apps/tomcat7
再次部署 tomcat7-deployment.yaml
kubectl apply -f tomcat7-deployment.yaml
创建 Ingress 规则
vi ingress-tomcat7.yaml
ingress-tomcat9.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: web
spec:
rules:
- host: tomcat.yuandengta.com
http:
paths:
- backend:
serviceName: tomcat7
servicePort: 80
kubectl apply -f ingress-tomcat7.yaml
通过域名 tomcat.yuandengta.com 即可进行访问
若Tomcat无法访问:
- 进入Tomcat容器内部
- 将webapps.dist 目录移动到webapps即可
3.Web 界面 (Dashboard)
https://kubernetes.io/zh/docs/tasks/access-application-cluster/web-ui-dashboard/
3.1.部署 dashboard
kubectl apply -f kubernetes-dashboard.yaml
kubernetes-dashboard.yaml
# Copyright 2017 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
apiVersion: v1
kind: Namespace
metadata:
name: kubernetes-dashboard
---
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kubernetes-dashboard
---
kind: Service
apiVersion: v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kubernetes-dashboard
spec:
type: NodePort
ports:
- port: 443
targetPort: 8443
nodePort: 30001
selector:
k8s-app: kubernetes-dashboard
---
apiVersion: v1
kind: Secret
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard-certs
namespace: kubernetes-dashboard
type: Opaque
---
apiVersion: v1
kind: Secret
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard-csrf
namespace: kubernetes-dashboard
type: Opaque
data:
csrf: ""
---
apiVersion: v1
kind: Secret
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard-key-holder
namespace: kubernetes-dashboard
type: Opaque
---
kind: ConfigMap
apiVersion: v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard-settings
namespace: kubernetes-dashboard
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kubernetes-dashboard
rules:
# Allow Dashboard to get, update and delete Dashboard exclusive secrets.
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["kubernetes-dashboard-key-holder", "kubernetes-dashboard-certs", "kubernetes-dashboard-csrf"]
verbs: ["get", "update", "delete"]
# Allow Dashboard to get and update 'kubernetes-dashboard-settings' config map.
- apiGroups: [""]
resources: ["configmaps"]
resourceNames: ["kubernetes-dashboard-settings"]
verbs: ["get", "update"]
# Allow Dashboard to get metrics.
- apiGroups: [""]
resources: ["services"]
resourceNames: ["heapster", "dashboard-metrics-scraper"]
verbs: ["proxy"]
- apiGroups: [""]
resources: ["services/proxy"]
resourceNames: ["heapster", "http:heapster:", "https:heapster:", "dashboard-metrics-scraper", "http:dashboard-metrics-scraper"]
verbs: ["get"]
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
rules:
# Allow Metrics Scraper to get metrics from the Metrics server
- apiGroups: ["metrics.k8s.io"]
resources: ["pods", "nodes"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kubernetes-dashboard
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: kubernetes-dashboard
subjects:
- kind: ServiceAccount
name: kubernetes-dashboard
namespace: kubernetes-dashboard
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: kubernetes-dashboard
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: kubernetes-dashboard
subjects:
- kind: ServiceAccount
name: kubernetes-dashboard
namespace: kubernetes-dashboard
---
kind: Deployment
apiVersion: apps/v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kubernetes-dashboard
spec:
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
k8s-app: kubernetes-dashboard
template:
metadata:
labels:
k8s-app: kubernetes-dashboard
spec:
containers:
- name: kubernetes-dashboard
image: kubernetesui/dashboard:v2.2.0
imagePullPolicy: Always
ports:
- containerPort: 8443
protocol: TCP
args:
- --auto-generate-certificates
- --namespace=kubernetes-dashboard
# Uncomment the following line to manually specify Kubernetes API server Host
# If not specified, Dashboard will attempt to auto discover the API server and connect
# to it. Uncomment only if the default does not work.
# - --apiserver-host=http://my-address:port
volumeMounts:
- name: kubernetes-dashboard-certs
mountPath: /certs
# Create on-disk volume to store exec logs
- mountPath: /tmp
name: tmp-volume
livenessProbe:
httpGet:
scheme: HTTPS
path: /
port: 8443
initialDelaySeconds: 30
timeoutSeconds: 30
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsUser: 1001
runAsGroup: 2001
volumes:
- name: kubernetes-dashboard-certs
secret:
secretName: kubernetes-dashboard-certs
- name: tmp-volume
emptyDir: {}
serviceAccountName: kubernetes-dashboard
nodeSelector:
"kubernetes.io/os": linux
# Comment the following tolerations if Dashboard must not be deployed on master
tolerations:
- key: node-role.kubernetes.io/master
effect: NoSchedule
---
kind: Service
apiVersion: v1
metadata:
labels:
k8s-app: dashboard-metrics-scraper
name: dashboard-metrics-scraper
namespace: kubernetes-dashboard
spec:
ports:
- port: 8000
targetPort: 8000
selector:
k8s-app: dashboard-metrics-scraper
---
kind: Deployment
apiVersion: apps/v1
metadata:
labels:
k8s-app: dashboard-metrics-scraper
name: dashboard-metrics-scraper
namespace: kubernetes-dashboard
spec:
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
k8s-app: dashboard-metrics-scraper
template:
metadata:
labels:
k8s-app: dashboard-metrics-scraper
annotations:
seccomp.security.alpha.kubernetes.io/pod: 'runtime/default'
spec:
containers:
- name: dashboard-metrics-scraper
image: kubernetesui/metrics-scraper:v1.0.6
ports:
- containerPort: 8000
protocol: TCP
livenessProbe:
httpGet:
scheme: HTTP
path: /
port: 8000
initialDelaySeconds: 30
timeoutSeconds: 30
volumeMounts:
- mountPath: /tmp
name: tmp-volume
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsUser: 1001
runAsGroup: 2001
serviceAccountName: kubernetes-dashboard
nodeSelector:
"kubernetes.io/os": linux
# Comment the following tolerations if Dashboard must not be deployed on master
tolerations:
- key: node-role.kubernetes.io/master
effect: NoSchedule
volumes:
- name: tmp-volume
emptyDir: {}
3.2.创建账户授权
创建admin账号,授权管理集群,复制控制台最后输出的token用于登录即可
#选择token方式登录,下面获取token
kubectl create serviceaccount dashboard-admin -n kube-system
kubectl create clusterrolebinding dashboard-admin --clusterrole=cluster-admin
--serviceaccount=kube-system:dashboard-admin
kubectl describe secrets -n kube-system $(kubectl -n kube-system get secret |
awk'/dashboard-admin/{print $1}')
如果忘记token,使用以下命令获取
kubectl -n kube-system describe secret $(kubectl -n kube-system get secret |
grep admin-user | awk '{print $1}')
3.3.访问 Dashboard UI
访问:https://192.168.56.102:30001,输入token进行登录
点击登录,进入 kubernetes dashboard 控制台