Kubernetes容器编排解决方案【基础篇】
-author: liuchao
-email: mirs_chao@163.com
-gitee: https://gitee.com/mirschao
1. kubernetes简要概述
Kubernetes 是用于自动部署, 扩展和管理容器化应用程序的开源系统. 它将组成应用程序的容器组合成逻辑单元, 以便于管理和服务发现. Kubernetes 源自Google 15 年生产环境的运维经验, 同时凝聚了社区的最佳创意和实践
在容器化应用的大趋势下, 越来越多的单体应用被划分成了无数个微小的服务, 从之前的裸机部署单体服务到现今使用容器承载服务运行; 容器越来越贴近研发、运维、测试等IT职能部门, 越来越多的人也渐渐转向了云进行开发, 而不再单独强调单体一致性问题; 这一切的功臣就是 — 容器;
其实容器这个产物, 早在Linux内核诞生后就已经有了它, 那时候程序员创建一个容器需要编写代码, 调用Linux内核中的Cgroup 和 NameSpace用作资源限制, 而创建出来的容器所观看到的底层文件系统却是和宿主机是同一套文件系统, 导致在容器中操作文件就相当于更改了宿主机的文件系统, 这就大大暴露了容器的应用性差的特性; 后来横空出世的docker解决了这个问题, docker创造了一个叫做镜像的东西, 并将其进行分层, 使得用户在启动容器的时候将镜像拷贝一份读写层挂载到容器中, 让容器看到的底层文件系统只是镜像中的内容从而避免了上述的问题, 镜像带来的好处远不止这一个, 比如在生产、测试、研发三个环境中总是因为环境不统一造成上线后的应用很快崩溃的局面, 而有了镜像就不需要考虑环境的问题, 因为所有的服务运行在容器中, 而提供给容器运行的底层文件系统是镜像, 只要使用的是同一个镜像那么不管在什么环境中, 都是一样的效果, 这对于运维、测试、研发三类人而言就能彻底的和应用运行环境要考虑的事情甩手拜拜了; 而docker这个引擎又提供了很多易于使用的控制容器的指令, 大大降低了程序员操作的难度, 又提供相应的镜像和存储镜像的公共仓库, 使得容器技术飞速发展起来;
就在容器飞速发展的第五年里, Google发布了容器编排系统 kubernetes, 它解决了容器在多个宿主机间调度的问题, 同时提供可靠的API接口来控制容器的运行, 并时刻保持容器启动的状态, 融合了故障自愈、服务发现等新功能; 从而占领了容器市场的高地; 从此容器圈内又向容器编排发起了猛烈的攻势;
1.1 kubernetes 功能简介
-
服务发现和负载均衡
Kubernetes 可以使用 DNS 名称或自己的 IP 地址公开容器, 如果进入容器的流量很大, Kubernetes 可以负载均衡并分配网络流量, 从而使部署稳定. 常用的DNS插件为coreDNS, 用作服务发现和集群中容器通讯; 负载均衡器常使用集群内的service资源进行对外暴露服务, 同时也提供ingress插件接口对外暴露服务
-
存储编排
Kubernetes 允许你自动挂载你选择的存储系统, 例如本地存储、公共云提供商等. 对于集群内部的应用有时会需要持久化数据, 这时容器如果被删除数据也会随之消失, 所以一个稳定的外部存储集群就显得很重要了; 常见的对k8s提供存储能力的集群有: heketi + gluesterfs 、Rook + Ceph、阿里云OSS等, 配合集群内的storageclass可直接向存储集群申请存储空间
-
自动部署和回滚
你可以使用 Kubernetes 描述已部署容器的所需状态, 它可以以受控的速率将实际状态 更改为期望状态. 例如, 你可以自动化 Kubernetes 来为你的部署创建新容器, 删除现有容器并将它们的所有资源用于新容器. 控制k8s集群中容器的状态大多数时候都会采用 yaml 资源配置清单的形式, 方便记忆也易于识别
-
自动完成装箱计算
Kubernetes 允许你指定每个容器所需 CPU 和内存(RAM). 当容器指定了资源请求时, Kubernetes 可以做出更好的决策来管理容器的资源. 这就与Linux操作系统中的资源限额有关系了, 有些容器在接收高并发访问的时候, 往往会无限制的占用宿主机资源, 从而导致其他服务容器争抢不到应有的资源进行运行和服务, 从而导致大面积瘫痪
-
自我修复
Kubernetes 重新启动失败的容器、替换容器、杀死不响应用户定义的 运行状况检查的容器, 并且在准备好服务之前不将其通告给客户端. 在创建pod的时候, 只有当设置在pod中的探针全部探测正常后才会将pod连接到集群内网络中对外进行服务, 否则将通过监控告警给运维人员; 同样的对于k8s中的容器会受到kubelet和kube-apiserver的双重管理, kubelet上报容器运行状态, api-server向etcd中请求期望状态, 比较后让其达到期望的状态, 从而保证其功能/服务容器永久保持在线
-
密钥与配置管理
Kubernetes 允许你存储和管理敏感信息, 例如密码、OAuth 令牌和 ssh 密钥. 你可以在不重建容器镜像的情况下部署和更新密钥和应用程序配置, 也无需在堆栈配置中暴露密钥. 对于无状态应用(exam: nginx)的配置文件, 可以使用k8s中的configmap资源进行存储, 但对于密码和某些私密信息而言就可以使用secret资源进行存储, 从而避免频繁更改和私密信息泄漏的风险
1.2 Kubernetes架构及组件
一个 Kubernetes 集群由一组被称作节点的机器组成。这些节点上运行 Kubernetes 所管理的容器化应用。集群具有至少一个工作节点。工作节点托管作为应用负载的组件的 Pod 。控制平面管理集群中的工作节点和 Pod 。 为集群提供故障转移和高可用性,这些控制平面一般跨多主机运行,集群跨多个节点运行。

-
kube-apiserver
API 服务器是 Kubernetes 控制面的组件, 该组件公开了 Kubernetes API。 API 服务器是 Kubernetes 控制面的前端。Kubernetes API 服务器的主要实现是 kube-apiserver。 kube-apiserver 设计上考虑了水平伸缩,也就是说,它可通过部署多个实例进行伸缩。 你可以运行 kube-apiserver 的多个实例,并在这些实例之间平衡流量。
-
etcd
etcd 是兼具一致性和高可用性的键值数据库,可以作为保存 Kubernetes 所有集群数据的后台数据库。你的 Kubernetes 集群的 etcd 数据库通常需要有个备份计划。要了解 etcd 更深层次的信息,请参考 etcd 文档。
-
kube-scheduler
控制平面组件,负责监视新创建的、未指定运行节点(node)的 Pods,选择节点让 Pod 在上面运行。调度决策考虑的因素包括单个 Pod 和 Pod 集合的资源需求、硬件/软件/策略约束、亲和性和反亲和性规范、数据位置、工作负载间的干扰和最后时限。
-
kube-controller-manager
运行控制器进程的控制平面组件。从逻辑上讲,每个控制器都是一个单独的进程, 但是为了降低复杂性,它们都被编译到同一个可执行文件,并在一个进程中运行。这些控制器包括:
-
节点控制器(Node Controller):负责在节点出现故障时进行通知和响应
-
任务控制器(Job controller):监测代表一次性任务的 Job 对象,然后创建 Pods 来运行这些任务直至完成
-
端点控制器(Endpoints Controller):填充端点(Endpoints)对象(即加入 Service 与 Pod)
-
服务帐户和令牌控制器(Service Account & Token Controllers):为新的命名空间创建默认帐户和 API 访问令牌
-
-
cloud-controller-manager
云控制器管理器是指嵌入特定云的控制逻辑的 控制平面组件。 云控制器管理器使得你可以将你的集群连接到云提供商的 API 之上, 并将与该云平台交互的组件同与你的集群交互的组件分离开来。
cloud-controller-manager仅运行特定于云平台的控制回路。 如果你在自己的环境中运行 Kubernetes,或者在本地计算机中运行学习环境, 所部署的环境中不需要云控制器管理器。与kube-controller-manager类似,cloud-controller-manager将若干逻辑上独立的 控制回路组合到同一个可执行文件中,供你以同一进程的方式运行。 你可以对其执行水平扩容(运行不止一个副本)以提升性能或者增强容错能力。下面的控制器都包含对云平台驱动的依赖:-
节点控制器(Node Controller):用于在节点终止响应后检查云提供商以确定节点是否已被删除
-
路由控制器(Route Controller):用于在底层云基础架构中设置路由
-
服务控制器(Service Controller):用于创建、更新和删除云提供商负载均衡器
-
-
Node 组件: 节点组件在每个节点上运行,维护运行的 Pod 并提供 Kubernetes 运行环境。
-
kubelet
一个在集群中每个节点(node)上运行的代理。 它保证容器(containers)都 运行在 Pod 中。kubelet 接收一组通过各类机制提供给它的 PodSpecs,确保这些 PodSpecs 中描述的容器处于运行状态且健康。 kubelet 不会管理不是由 Kubernetes 创建的容器。
-
kube-proxy
kube-proxy 是集群中每个节点上运行的网络代理, 实现 Kubernetes 服务(Service) 概念的一部分。kube-proxy 维护节点上的网络规则。这些网络规则允许从集群内部或外部的网络会话与 Pod 进行网络通信。如果操作系统提供了数据包过滤层并可用的话,kube-proxy 会通过它来实现网络规则。否则, kube-proxy 仅转发流量本身。
-
容器运行时(Container Runtime)
容器运行环境是负责运行容器的软件。Kubernetes 支持容器运行时,例如 Docker、 containerd、CRI-O 以及 Kubernetes CRI (容器运行环境接口) 的其他任何实现。
-
插件(Addons)
插件使用 Kubernetes 资源实现集群功能。 因为这些插件提供集群级别的功能,插件中命名空间域的资源属于
kube-system命名空间。下面描述众多插件中的几种。有关可用插件的完整列表,请参见 插件(Addons)。-
DNS
尽管其他插件都并非严格意义上的必需组件,但几乎所有 Kubernetes 集群都应该 有集群 DNS, 因为很多示例都需要 DNS 服务。集群 DNS 是一个 DNS 服务器,和环境中的其他 DNS 服务器一起工作,它为 Kubernetes 服务提供 DNS 记录。Kubernetes 启动的容器自动将此 DNS 服务器包含在其 DNS 搜索列表中。
-
Web 界面(仪表盘)
Dashboard 是 Kubernetes 集群的通用的、基于 Web 的用户界面。 它使用户可以管理集群中运行的应用程序以及集群本身并进行故障排除。
-
容器资源监控
容器资源监控 将关于容器的一些常见的时间序列度量值保存到一个集中的数据库中,并提供用于浏览这些数据的界面。
-
集群层面日志
集群层面日志 机制负责将容器的日志数据 保存到一个集中的日志存储中,该存储能够提供搜索和浏览接口 ELK/Loki+grafana
-
2. Kubernetes 集群部署
2.1 测试环境集群部署
| role | ipaddress | configure |
|---|---|---|
| k8s-master | 10.9.68.98 | 4 core, 4Gb; 50GBS, CentOS 7.9 |
| k8s-worker-01 | 10.9.68.93 | 4 core, 4Gb; 100GBS, CentOS 7.9 |
| k8s-worker-02 | 10.9.68.91 | 4 core, 4Gb; 100GBS, CentOS 7.9 |
⚠️**不要用克隆机器作这次的实验**
测试集群部署采用单master节点部署, 可以使IT人员得到一个完整功能的测试Kubernetes集群; 由于其构建简单, 所以其内部很多相关设计没有凸显出来, 想了解Kubernetes的组件配置工作及细节请移至 生产环境集群部署 查看;
#>>> 下载部署k8s集群的安装仓库
$ git clone https://gitee.com/mirschao/k8sconfig.git
$ cd k8sconfig/kubeadm-deploys
$ sed -i 's/MASTER/10.9.68.98/' initialenv.sh
$ sed -i 's/WORKER1/10.9.68.93/' initialenv.sh
$ sed -i 's/WORKER2/10.9.68.91/' initialenv.sh
-
初始化每个节点(all master & all node)
$ bash initialenv.sh -
安装 kubeadm 程序(all master & all node)
$ yum list kubeadm.x86_64 --showduplicates | sort -r kubeadm.x86_64 1.21.2-0 kubernetes kubeadm.x86_64 1.21.14-0 kubernetes kubeadm.x86_64 1.21.13-0 kubernetes #> master中执行 $ yum -y install kubeadm-1.21.14-0 kubelet-1.21.14-0 kubectl-1.21.14-0 #> worker中执行 $ yum -y install kubeadm-1.21.14-0 kubelet-1.21.14-0 #> master及worker节点均要执行 $ cat <<-EOF >/etc/sysconfig/kubelet KUBELET_EXTRA_ARGS="--cgroup-driver=systemd" EOF $ systemctl enable --now kubelet -
生成集群初始化配置文件(only k8s-master)
$ kubeadm config print init-defaults >initial.yaml #> 配置初始化文件 $ IPADDRESS=$(ifconfig | grep ens33 -A 2 | awk 'NR==2{ print $2 }') $ sed -i "s/1.2.3.4/${IPADDRESS}/" initial.yaml $ REGISTRYADDR="registry.cn-hangzhou.aliyuncs.com/google_containers" $ sed -i "s#k8s.gcr.io#${REGISTRYADDR}#" initial.yaml $ sed -i "s# node# ${ HOSTNAME}#" initial.yaml #> 拉取初始化所需要的镜像文件 $ kubeadm config images pull --config initial.yaml #> 初始化集群 $ kubeadm init --config initial.yaml --upload-certs our Kubernetes control-plane has initialized successfully! To start using your cluster, you need to run the following as a regular user: #######>>>以下三步需要在命令行中执行, 最好创建一个用户进行设置<<<####### mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config Alternatively, if you are the root user, you can run: #######>>>以下设置需要在命令行中执行, 最好加入~/.bashrc中进行设置<<<####### export KUBECONFIG=/etc/kubernetes/admin.conf You should now deploy a pod network to the cluster. Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at: https://kubernetes.io/docs/concepts/cluster-administration/addons/ Then you can join any number of worker nodes by running the following on each as root: kubeadm join 10.9.68.98:6443 --token abcdef.0123456789abcdef \ --discovery-token-ca-cert-hash sha256:834e4ada6f3abd2525e0d43a7a1b53b0abf713d5f64dd555fc927d90dc8dac0b #> 部署calico网络插件 $ sed -i 's#etcd_endpoints: "http://<ETCD_IP>:<ETCD_PORT>"#etcd_endpoints: "https://10.9.68.98:2379"#g' calico-etcd.yaml $ ETCD_CA=`cat /etc/kubernetes/pki/etcd/ca.crt | base64 | tr -d '\n'` $ ETCD_CERT=`cat /etc/kubernetes/pki/etcd/server.crt | base64 | tr -d '\n'` $ ETCD_KEY=`cat /etc/kubernetes/pki/etcd/server.key | base64 | tr -d '\n'` $ sed -i "s@# etcd-key: null@etcd-key: ${ETCD_KEY}@g; s@# etcd-cert: null@etcd-cert: ${ETCD_CERT}@g; s@# etcd-ca: null@etcd-ca: ${ETCD_CA}@g" calico-etcd.yaml $ sed -i 's#etcd_ca: ""#etcd_ca: "/calico-secrets/etcd-ca"#g; s#etcd_cert: ""#etcd_cert: "/calico-secrets/etcd-cert"#g; s#etcd_key: ""#etcd_key: "/calico-secrets/etcd-key"#g' calico-etcd.yaml $ sed -i 's@# - name: CALICO_IPV4POOL_CIDR@- name: CALICO_IPV4POOL_CIDR@g; s@# value: "192.168.0.0/16"@ value: '"192.168.0.0/16"'@g;' calico-etcd.yaml $ kubectl apply -f calico-etcd.yaml #> 配置calicoctl设置 $ wget https://github.com/projectcalico/calico/releases/download/v3.23.1/calicoctl-linux-amd64 -O /usr/local/bin/calicoctl $ chmod a+x /usr/local/bin/calicoctl $ calicoctl node status Calico process is running. IPv4 BGP status +----------------+-------------------+-------+----------+-------------+ | PEER ADDRESS | PEER TYPE | STATE | SINCE | INFO | +----------------+-------------------+-------+----------+-------------+ | 10.9.68.93 | node-to-node mesh | up | 13:53:54 | Established | | 10.9.68.91 | node-to-node mesh | up | 13:59:43 | Established | +----------------+-------------------+-------+----------+-------------+ IPv6 BGP status No IPv6 peers found. -
对于集群后续的配置和设置
#> 集群网络规则采用 ipvs 模式 $ kubectl edit configmap kube-proxy -n kube-system ... 43 mode: "ipvs" ... $ kubectl get pod -n kube-system NAME READY STATUS RESTARTS AGE calico-kube-controllers-7f494f5676-79nlm 1/1 Running 0 4m8s calico-node-g5xnl 1/1 Running 0 4m8s calico-node-gtdv7 1/1 Running 0 4m8s calico-node-wtf9x 0/1 PodInitializing 0 4m8s coredns-6f6b8cc4f6-5ghl9 1/1 Running 0 21m coredns-6f6b8cc4f6-xrr9t 1/1 Running 0 21m etcd-k8s-master 1/1 Running 0 21m kube-apiserver-k8s-master 1/1 Running 0 21m kube-controller-manager-k8s-master 1/1 Running 0 21m kube-proxy-28hd5 1/1 Running 0 16m kube-proxy-b76xv 1/1 Running 0 17m kube-proxy-bz7pd 1/1 Running 0 21m kube-scheduler-k8s-master 1/1 Running 0 21m $ kubectl delete pod kube-proxy-28hd5 -n kube-system pod "kube-proxy-28hd5" deleted $ kubectl delete pod kube-proxy-b76xv -n kube-system pod "kube-proxy-b76xv" deleted $ kubectl delete pod kube-proxy-bz7pd -n kube-system pod "kube-proxy-bz7pd" deleted $ kubectl get pod -n kube-system NAME READY STATUS RESTARTS AGE calico-kube-controllers-7f494f5676-79nlm 1/1 Running 0 5m21s calico-node-g5xnl 1/1 Running 0 5m21s calico-node-gtdv7 1/1 Running 0 5m21s calico-node-wtf9x 0/1 PodInitializing 0 5m21s coredns-6f6b8cc4f6-5ghl9 1/1 Running 0 22m coredns-6f6b8cc4f6-xrr9t 1/1 Running 0 22m etcd-k8s-master 1/1 Running 0 22m kube-apiserver-k8s-master 1/1 Running 0 22m kube-controller-manager-k8s-master 1/1 Running 0 22m kube-proxy-htks4 1/1 Running 0 11s kube-proxy-rdtvw 1/1 Running 0 26s kube-proxy-zv84c 1/1 Running 0 38s kube-scheduler-k8s-master 1/1 Running 0 22m #> 如果集群初始化失败:(每个节点都要执行) $ kubeadm reset -f; ipvsadm --clear; rm -rf ~/.kube $ systemctl restart kubelet #> 如果忘记token值 $ kubeadm token create --print-join-command $ kubeadm init phase upload-certs --upload-certs -
测试集群是否成功安装
$ cat <<-EOF | kubectl apply -f - apiVersion: v1 kind: Pod metadata: name: webserver spec: containers: - name: nginx-contianer image: nginx:1.21 ports: - containerPort: 80 EOF
2.2 生产环境集群部署
Pod-net-segment: 192.168.0.0/16
Service-net-segment: 10.96.0.0/12
| role | ipaddress | Configure |
|---|---|---|
| loadbalancer | 10.9.12.99 | None |
| prod-master-01 & etcd | 10.9.12.101 | 4core, 4Gb, 50G; CentOS 7.9 |
| prod-master-02 & etcd | 10.9.12.102 | 4core, 4Gb, 50G; CentOS 7.9 |
| pro |


2万+

被折叠的 条评论
为什么被折叠?



