

帅哥(靓仔)、美女,点个关注后续不迷路!
本章目录

0x02 基础概念
0.工作负载
1.Pods
实现原理
简单分类
2.资源清单
apiVersion - 对象资源版本
Kind - 对象资源
metadata - 对象资源原数据
spec - 对象资源详细描述
labels - 资源对象标签
selector - 资源对象标签选择器
annotations - 资源对象注解
3.Service
4.Network
0x03 简单Kubernetes安装实践
K8s 单控制平面部署流程
K8s 实践之小试牛刀

作者: WeiyiGeek
原文地址:https://blog.weiyigeek.top/2020/4-22-468.html

描述: 在进行学习K8S前,我们需要简单的对其相关术语进行学习,防止读者在阅读时一头的雾水,废话不多说,奥利给。
描述: 工作负载是在 Kubernetes 上运行的应用程序。
描述: Pod 是学习Kubernetes的最重要也是最基本的概念,所以对于我们初学者来说它是必须了解的;
Q: Pod 的定义?
答: , 简单的说它是K8s系统node节点中的最小组成单位, K8s设计Pod对象是为了将服务进程包装到相应的Pod中使其成为Pod中运行的容器(Conatiner); Pod ()通常运行在Node节点上, 在 Kubernetes 中,Pod 代表的是集群上处于运行状态的一组容器。 Pod 的共享上下文包括一组 Linux 名字空间、控制组(cgroup)和可能一些其他的隔离 方面,即用来隔离 Docker 容器的技术。并且在上下文中,每个独立的应用可能会进一步实施隔离。 Pod 是特定于应用的"逻辑主机",其中包含一个或多个应用容器, 这些容器是相对紧密的耦合在一起的。
Q: 什么是 Pod? 答: Pod 的共享上下文包括一组 Linux 名字空间、控制组(cgroup)和可能一些其他的隔离 方面,即用来隔离 Docker 容器的技术。在 Pod 的上下文中,每个独立的应用可能会进一步实施隔离。就 Docker 概念的术语而言,Pod 类似于共享名字空间和文件系统卷的一组 Docker 容器。
PS : 除了 Docker 之外,Kubernetes 支持很多其他容器运行时, Docker 是最有名的容器引擎使用 Docker 的术语来描述 Pod 会很有帮助。
描述: 在每个Pod运行之前会首先启动一个特殊(只要Pod建立都有它), 而其它容器则为业务容器,即 Pod 中的每个容器共享网络名字空间,包括 IP 地址和网络端口;在同一个 Pod 内,所有容器共享一个 IP 地址和端口空间,并且可以通过 localhost 发现对方。 他们也能通过如 SystemV 信号量或 POSIX 共享内存这类标准的进程间通信方式互相通信。
简单: 您可以想象指定的应用(容器)都运行在同一台主机(Pod)之中;
Q: Pause 容器作用不言而喻?
(1) 引入业务无开关并且不易死亡的Pause容器作为Pod的根容器,解决整体检测及判断行动有效和无效的问题,其状态代表了整个容器组的状态;
(2) 共享网络栈和存储栈;
Q: 容器的特权模式?
Pod 中的任何容器都可以使用容器规约中的安全性上下文中的 privileged 参数启用特权模式。 这对于想要使用使用操作系统管理权能(Capabilities,如操纵网络堆栈和访问设备) 的容器很有用。 容器内的进程几乎可以获得与容器外的进程相同的特权。 说明:你的容器运行时必须支持 特权容器的概念才能使用这一配置。
Q: Pod 异常处理调度机制?
(1) 默认情况下,当Pod里的某个容器停止时 Kubernetes 会自动检测到这个问题并重新启动该Pod(动作是:重启Pod里的所有容器);
(2) 工作节点宕机的情况下,则会将该Node上的所有Pod重新调度到其它节点之上。
补充说明:
Pause容器对应镜像属于Kubernetes平台的一部分,除了Pause容器外每个Pod还包括一个或多个紧密相关的用户业务容器;
同一个Pod中的服务端口不可重叠使用, 例如Nginx使用80Port则Tomcat只能使用8080Port, 否则可能导致容器无法启动或者重复启动;
Pod中除了Pause容器 、应用容器还可以包含在 Pod 启动期间运行的 Init 容器,其三者关系是Pause容器 > Init 容器。
我们可以大致分为以下:
1单实例(Singleton) 的 Pod () : Pod 一旦死亡便不能自动化的切换或者根据期望值进行创建 Pod;
2.控制器管理的 Pod :主要是使用工作负载资源及其控制器以实现应用的扩缩和自动修复。
RC (ReplicationController): 用来确保容器应用的副本数始终保持在用户定义的副本数(),即如果有容器异常退出其将会自动创建新的Pod来替代, 而如果异常多出来的容器也会自动回收
RS (ReplicaSet) :它与ReplicationController没有本质的不同只是名字不一样,在新版本K8s中, 但是虽然它可以独立使用; 建议采用Deployment来自动管理ReplicaSet,这样做的好处式无需担心跟其他机制的不兼容的问题;
Deployment : 它为Pod和ReplicaSet提供了一个声明式的定义(Declaratice)方法,用于替代以前的RC来方便管理应用其典型的应用场景如下:
StatefullSet : 为了(前面所说的)其利用场景报包括如下:
- 1.稳定的持久化存储, 即Pod重新调度后还是能访问到相同的持久化数据基于PVC来实现;
- 2.稳定的网络标志,即Pod重新调度后其PodName 和 HostName 不变,基于Headless Service即没有Cluster IP的Service来实现;
- 3.有序部署、有序扩展,即Pod是有顺序的,在部署或者扩展的时候要依据定义的顺序依次进行(`即从0到N-1在下一个Pod运行之前的所有之前的Pod必须是Running 和 Readt状态`)它们是基于Init Containers来实现;
- 4.有序收缩与有序删除(`即从N-1到0`) DaemonSet : 确保在全部或者一部分Node节点上运行一个Pod的副本,当有Node加入集群时也会为他们新增一个Pod;当有Node从集群移除时这些Pod也将被回收;当删除DaemonSet将会删除它创建的所有Pod,例如下面的一些典型用法:
- 1.运行集群存储Deamon; 例如在每个Node上运行Glusterd 、Ceph;
- 2.在每个Node上运行日志收集Daemon; 例如Fluentd、logstash;
- 3.在每个Node上运行监控Daemon; 例如Prometheus Node Exporter; Job : 负责批处理任务即仅执行一次的任务,它保证批处理任务的在一个或者多个Pod成功结束, 常常用于数据备份;
Cronjob : 管理基于时间的Job即在给定的时间点只运行一次,周期性地在给定时间点运行;
HPA (): 仅仅适用于Deployment 与 ReplicaSet在V1版本中仅支持根据Pod的CPU利用率进行扩容,在V1-Alpha版本中就是仅仅支持根据内存和用户自定义的Metric扩缩容;
F&Q
Q: 什么是Rolling-update?以及什么是rollbacks-update(undo)?
答: 滚动更新(即新版本替换旧版本但是旧版本容器并未被删除而是被暂停) 回滚更新(即线上版本回滚前一个或者某一个版本)
Q: 服务分类(资源清单)?什么是有状态服务?什么又是无状态服务?
有状态服务:DBMS (暂停或者离开某段时间后返回到集群中无法正常工作,由于这段时间内有新的数据产生) 无状态服务:LVS APACHE (暂停或者离开某段时间后返回到集群工仍然可以继续的正常工作,您可以把他比如作流水线的管理人员,其离开一会并会不导致流水线作业停止) PS : 我们所熟知的Docker其实主要是针对一个无状态的服务;
Q: Deployment 与 RC 间的关系?
答: 在Pod创建并不是由RC直接创建而是由Deployment进行创建并且RS也是由它创建的(Pod与RS都是由Deployment创建);

Q: 有序部署扩容与删除缩容注意事项?
答: 在同一个Pod中,例如当缩容时也需按照相应的反向顺序进行关闭;
描述: Kubenetes 所有的资源对象的定义和描述采用Yaml或者Json的文件格式, 将其比喻作剧本即Kubernetes按照要求定义进行相应资源的执行增删改查;
以下是K8S资源清单定义中比不可少的四个对象:
apiVersion - 对象资源版本
Kind - 对象资源
metadata - 对象资源原数据
spec - 对象资源详细描述
labels - 资源对象标签
描述: Labels 是 K8s 中另外一个核心概念, 它是一个KV键值对其可以附加在各种资源对象()之上的定义,并且一个资源对象可以定义多个lable标签(多对多的关系); 作用: 为指定资源对象绑定一个或者多个不同的Label来实现多维度的资源分组管理功能,, 例如在Node中可以利用标签来设置Pod的亲密性,在RS中利用匹配的标签来检测拥有该标签的数量保证Pod数量满足副本数,在SVC中利用标签可进行选择Pod进行负载均衡;
简单的说: Lable 是用来传递用户自定义属性,标注对象的特殊特点,比如用户可以更加直观从标签中看到某个Node节点中挂载的SSD硬盘或者是说测试环境;
标签(labels)示例:
版本标签:"release":"stable"
环境标签:"environment":"dev"
架构标签:"tire":"backend" # middleware
分区标签:"partition":"customerA"
质量管控标签:"track":"weekly" 补充知识:
1.K8s全部资源对象的 Label 我们都可以随时随地的增加、修改和删除,一个资源对象可以有多个不重复的Label。(下面首次学习者作为了解即可,无需深究)
# 1) 为一个Pod设置Label
$ kubectl label pods deploy-java-maven-0 role=jave-test
# pod/deploy-java-maven-0 labeled
$ kubectl get pods deploy-java-maven-0 --show-labels
# NAME READY STATUS RESTARTS AGE LABELS
# deploy-java-maven-0 1/1 Running 0 7d22h app=java-maven,controller-revision-hash=deploy-java-maven-748db8b9d9,release=stabel,role=jave-test,statefulset.kubernetes.io/pod-name=deploy-java-maven-0
# 2) 为一个node设置Lable
$ kubectl label nodes work-224 devnode=test
# 3) 强制更新已经设置的Lable
$ kubectl label pods deploy-java-maven-0 role=front-overwrite --overwrite
# pod/deploy-java-maven-0 labeled
$ kubectl get pods deploy-java-maven-0 --show-labels
# NAME READY STATUS RESTARTS AGE LABELS
# deploy-java-maven-0 1/1 Running 0 7d22h app=java-maven,controller-revision-hash=deploy-java-maven-748db8b9d9,release=stabel,role=front-overwrite,statefulset.kubernetes.io/pod-name=deploy-java-maven-0
# 4) 删除指定lable
$ kubectl label pods deploy-java-maven-0 role-
# pod/deploy-java-maven-0 labeled
$ kubectl get pods deploy-java-maven-0 --show-labels
# NAME READY STATUS RESTARTS AGE LABELS
# deploy-java-maven-0 1/1 Running 0 7d22h app=java-maven,controller-revision-hash=deploy-java-maven-748db8b9d9,release=stabel,statefulset.kubernetes.io/pod-name=deploy-java-maven-0
selector - 资源对象标签选择器
描述: 有了标签Label后我们还需要配合标签选择器,来进行标签(Lable)的查询和筛选使之分配给该标签的资源对象相应的资源(或者说绑定相应的资源);;
那如何使用标签以及选择器?
描述: 通过标签选择器Label Selector查询和筛选拥有某些Label的资源对象,而K8s通过类似于SQL的简单又通用的对象(where 条件)查询机制; 通过采用等式类和集合类两种方式进行匹配在Node、Pod、RS、Service中的标签;
例如: Lable 为 name = nginx 附加到一个Pod时,那么对应的Lable Selector表达式类比于SQL语句等同于: ;
# 等式类(Equality-Based)-操作表达式(等于或者不等于):
name = redis-app
env != product
# 集合类(Set-Based)-操作表达式(包含、不包含、存储或者不存在):
name In (redis-cluster, redis-slave) # , 表示分隔其中里面的条件关系是AND
name Notin (redis-slave)
name Exists (redis-slave)
name DoesNotExists (redis-slave)
# 使用说明:在Deloyment、ReplicaSet、DaemonSet或者Job等Pod管理控制器对都可以在Selector使用基于集合的筛选定义
selector:
matchLables: # 用于定义Lables匹配的Pod资源对象
app: nginx
matchExpressions: # 用于定义一组Lable其与直接定义在Selector中作用一样
- {key: name, operator: In, value: [appweb]}

方式1:下面的Deployment控制器创建Pod的资源清单示例
apiVersion: apps/v1 #与k8s集群版本有关,使用 kubectl api-versions 即可查看当前集群支持的版本
kind: Deployment #该配置的类型,我们使用的是 Deployment
metadata: #译名为元数据,即 Deployment 的一些基本属性和信息
name: nginx-deployment #Deployment 的名称
labels: #标签,可以灵活定位一个或多个资源,其中key和value均可自定义,可以定义多组,目前不需要理解
app: nginx #为该Deployment设置key为app,value为nginx的标签
enviroment: test
spec: #这是关于该Deployment的描述,可以理解为你期待该Deployment在k8s中如何使用
replicas: 1 #副本数量(由Deployment控制器创建并且监控)
selector: #标签选择器与Pod模板中的标签需要共同作用
matchLabels: #匹配选择包含标签app=nginx的资源 # 基于等式
app: nginx
matchExpressions: # 基于集合
- {key: name, operator: In, value: [web-app]}
template: #这是选择或创建的Pod的模板
metadata: #Pod的元数据
labels: #Pod副本拥有的标签,上面的selector即选择包含标签app:nginx的Pod(有了它我们的delopyment控制器才知道匹配的标签已经有一个Pod在运行了)
app: nginx
name: web-app
spec: #期望Pod实现的功能(即在pod中部署)
containers: #生成container,与docker中的container是同一种
- name: nginx #container的名称
image: nginx:latest #使用镜像nginx最新版本创建container,该container默认80端口可访问
方式2: 通过注解()的方式也可以进行标签选择匹配(后续有示例的时候补充)
Tips : 如果使用一组集合的筛选条件,基于集合操作的表达式匹配标签。也可以通过多个Lable Selector表达式组合实现更为复杂的条件选择,表达式之间用逗号或者AND进行分割;
Tips : 如果同时设置matchLables 与 matchExpressions 则两者条件为‘与’的关系;
总结: 使用 Label 可以给对象创建多组标签, 和 共同构成了k8s系统中最核心的应用模型,使得被管理对象能够被精细的分组管理,同时实现了整个集群的高可以用性;
描述: 上面我们说过除了使用标签将元数据附加到 Kubernetes 对象,你还可以使用 Kubernetes注解为对象附加任意的非标识的元数据,客户端程序(例如工具和库)能够获取这些元数据信息。
那到底有哪些信息可以使用注解来记录? 通常为如下用途
由声明性配置所管理的字段。 将这些字段附加为注解,能够将它们与客户端或服务端设置的默认值、 自动生成的字段以及通过自动调整大小或自动伸缩系统设置的字段区分开来。
构建、发布或镜像信息(如时间戳、发布 ID、Git 分支、PR 数量、镜像哈希、仓库地址)。
指向日志记录、监控、分析或审计仓库的指针。
可用于调试目的的客户端库或工具信息:例如,名称、版本和构建信息。
用户或者工具/系统的来源信息,例如来自其他生态系统组件的相关对象的 URL。
轻量级上线工具的元数据信息:例如,配置或检查点。
负责人员的电话或呼机号码,或指定在何处可以找到该信息的目录条目,如团队网站。
从用户到最终运行的指令,以修改行为或使用非标准功能。
温馨提示: 注解不用于标识和选择对象.
注解中的元数据,可以很小,也可以很大,可以是结构化的,也可以是非结构化的,能够包含标签不允许的字符,请注意注解语法和标签一样都是键/值(KV)对(), 换句话说,你不能使用数字、布尔值、列表或其他类型的键或值。例如:
"metadata": {
"annotations": {
"key1" : "value1",
"key2" : "value2"
}
}
例如,下面是一个 Pod 的配置文件,其注解中包含 imageregistry: https://hub.docker.com/:
apiVersion: v1
kind: Pod
metadata:
name: annotations-demo
annotations:
imageregistry: "https://hub.docker.com/"
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
Q: 什么是Service (SVC) 服务发现?为啥需要Service?
答:在K8中Services服务是分布式集群架构的核心,一个Service对象主要拥有如下功能特征拥有一个唯一的名称以及拥有一个虚拟IP(ClusterIP/ServiceIP或者VIP)和端口号; 简单的说 Service 通常有多个相关的服务进程来提供服务并且每个服务进程都拥有一个独立的访问点, K8s能够让我们通过连接到指定的Service上, ; 作用: 通过K8s内建的透明负载均衡和故障恢复机制,不管后端有多少服务进程也不管某个服务进程是否会由于发生故障而重新部署到其他Node上,都不会影响到我们对服务的正常调用,就不必再为服务IP地址变化而无法访问的问题头疼;
Q: K8s中如何使用Service 服务发现原理?
答: 为了建立Service与Pod间的关联关系,K8s首先会给每个Pod贴上一个标签(Label)它也是K8s中非常重要,例如标签, 然后给相应的Service定义标签选择器(Label Selector); 例如Redis Service的标签选择器的选择条件为app=redis意为该Service钥作用于所有包含app=redis的Label的Pod上, 这样将巧妙地解决了Service与Pod的关联问题; 你可以将Label与标签选择器类比为CSS样式,可以通过指定的标签设置页面上所有该标签的CSS样式;
Service 服务发现图示

描述: 在K8s的网络模型假定了所有的Pod都在一个可以直接联通扁平化()的网络空间中例如在里面是现成的网络模型,而在私有云的搭建部署K8s集群时候需要我们自己设置网络通信,将不同节点上的Docker容器之间的互相访问先打通然后再运行Kubernetes这是因为Pod Service间的网络是私有虚拟的网络;
Q: 与Pod间的网络通讯模式?
答: 各Pod之间的通讯是采用Overlay Network 覆盖网络即虚拟网桥Bridge实现 Pod 与 Service 之间的通信是通过iPtables底层一堆的转换机制实现;
Q: 不同情况下的网络通信方式我们以Flannel为例
1.同一个Pod内部通信:前面我们说过同一个Pod共享同一个网络命名空间与共享一个Linux协议栈,简单的说就是;
2.不同Pod间通信:
3.Pod 至 Service 网络: 目前全部采用iptables维护和转发, 但是可以利用LVS组件进行替换;
4.Pod到外网: Pod向外网发送请求查找路由表然后转发数据包到宿主机的网卡,宿主机网卡完成路由选择后IPtables执行Masquerade把源IP地址更改为宿主机网卡的IP(NAT转发)然后再向外网服务发送请求;
5.外网访问Pod:通过Service映射的端口
组件通讯示意图如下:
K8S网络解决方案
(1) K8s + Flannel (该插件是 CoreOS 团队针对于Kubernetes设计的一个网络规划服务)
(2) K8s + Calico (Calico 是一种容器之间互通的网络方案),后续在实践中使用。
PS: 在 K8s 中是通过CNI接口接入第三方的网络解决方案的组件;
描述:前面我们说过 Kubernetes 是一个由 Google 发起的开源自动化部署,缩放,以及容器化管理应用程序的容器编排系统。
部署 Kubernetes 曾经是一件相当麻烦的事情,早期版本中,Kubelet、Api-Server、Etcd、Controller-Manager 等每一个组件都需要自己单独去部署,还要创建自签名证书来保证各个组件之间的网络访问。但程序员大概是最爱与麻烦做斗争的群体,随着 Kubernetes 的后续版本不断改进(如提供了自动生成证书、Api-Server 等组件改为默认静态 Pod 部署方式),使得部署和管理 Kubernetes 集群正在变得越来越容易起来。
目前主流安装 Kubernetes 方式大致有:
使用 Kubeadm 部署 Kubernetes 集群
使用 Rancher 部署、管理 Kubernetes 集群(其他如 KubeSphere 等在 Kubernetes 基础上构建的工具均归入此类)
使用 Minikube 在本地单节点部署 Kubernetes 集群(其他如 Microk8s 等本地环境的工具均归入此类)
以上集中部署方式都有很明显的针对性,个人开发环境以 Minikube 最简单,生产环境以 Rancher 最简单,在云原生环境中,自然是使用环境提供的相应工具。不过笔者推荐首次接触 Kubernetes 的同学最好还是选择 Kubeadm 来部署,毕竟这是官方提供的集群管理工具,是相对更底层、基础的方式,充分熟悉了之后再接触其他简化的方式会快速融会贯通。 以上部署方式无需全部阅读,根据自己环境的情况选择其一即可。
安装环境基本需求
1)两台或多台以上的Linux虚拟机或者物理机。
2)每台Linux处理器最小需求为2 CPU 核或更多、内存最小需求 2 GB 或更多的 RAM。
3)每台Linux不可以有重复的主机名、IP地址、MAC 地址或 product_uuid。
4)每台Linux进行网络配置确保网络通畅(建议禁用系统防火墙)即可以正常互联以及访问外部网络。
5)检查每台Linux 的某些端口(API-Server组件默认6443端口)是否被占用,以及时间、时区是否正常.
6)禁用每台Linux 的用交换分区,以保证保证 kubelet 正常工作。
Step 1.环境配置要求查看验证,注意此处K8S版本相对比与当前v1.23.5相差较多,所以此处只是简单熟悉其流程。
# 1.安装Master/Node节点(cpu和磁盘至少1C和2G)
2台 2核4G 的服务器
# 注意:内核版本的选择
CentOS 7.8 kernel version>= 4.19.x
# docker 版本 至少 1.9 以上
docker 19.03.8
# etc 至少2.0版本以上
# 2.实际测试环境(两台):
# 系统版本
CentOS Linux release 7.8.2003 (Core)
# 内核版本
CentOS Linux (5.6.10-1.el7.elrepo.x86_64) 7 (Core)
# 核心数:请使用 lscpu 命令,核对 CPU 信息
# Architecture: x86_64 本安装文档不支持 arm 架构
# CPU(s): 2 CPU 内核数量不能低于 2
cat /proc/cpuinfo | grep -c 'processor'
2
# 内存容量(6G)
cat /proc/meminfo
MemTotal: 6090864 kB
MemFree: 5709020 kB
MemAvailable: 5695728 kB
Buffers: 2108 kB
Cached: 193996 kB Step 2.安装准备以及软件版本:
* 我的任意节点 centos 版本为 7.6 或 7.7
* 我的任意节点 CPU 内核数量大于等于 2,且内存大于等于 4G
* 我的任意节点 hostname 不是 localhost,且不包含下划线、小数点、大写字母
* 我的任意节点都有固定的内网 IP 地址
* 我的任意节点都只有一个网卡,如果有特殊目的,我可以在完成 K8S 安装后再增加新的网卡
* 我的任意节点上 Kubelet使用的 IP 地址 可互通(无需 NAT 映射即可相互访问),且没有防火墙、安全组隔离
* 我的任意节点不会直接使用 docker run 或 docker-compose 运行容器
# K8s系统安装所需软件一览
Kubernetes v1.18.x
* kubeadm
* kubectl
* kubelet
* kube-apiserver
* kube-control-manager
* kube-proxy
* kube-scheduler
* calico 3.13.1
* nginx-ingress 1.5.5
* coredns
* etcd
Docker-ce 19.03.8
* docker-cli
* nfs-utils Step 3.安装流程(Master与NODE节点都要执行)
#0.临时关闭swap和SELinux(这是必须的,置于为什么要这么做在下一讲中进行说明)
swapoff -a
setenforce 0
sed -i 's/^SELINUX=enforcing$/SELINUX= disabled/' /etc/selinux/config
#1.修改hostname
hostnamectl set-hostname master-01|node-01
# 查看修改结果
hostnamectl status
# 设置 hostname 解析
echo "127.0.0.1 $(hostname)" >> /etc/hosts
#2.检查网络(所有节点上 Kubernetes 所使用的 IP 地址必须可以互通(无需 NAT 映射、无安全组或防火墙隔离)
ip route show && ip addr show ens192
# default via 10.10.107.1 dev ens192 proto static metric 100
# 10.10.107.0/24 dev ens192 proto kernel scope link src 10.10.107.191 metric 100
# 2: ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
# link/ether 00:50:56:ac:a5:af brd ff:ff:ff:ff:ff:ff
# inet 10.10.107.191/24 brd 10.10.107.255 scope global noprefixroute ens192
# valid_lft forever preferred_lft forever
# inet6 fe80::44ce:84ab:ef25:36cc/64 scope link noprefixroute
# valid_lft forever preferred_lft forever
# 3.安装docker及kubelet (在 master 节点和 worker 节点都要执行)
# 最后一个参数 1.18.2 用于指定 kubenetes 版本,支持所有 1.18.x 版本的安装
# 腾讯云 docker hub 镜像
# export REGISTRY_MIRROR="https://mirror.ccs.tencentyun.com"
# DaoCloud 镜像
# export REGISTRY_MIRROR="http://f1361db2.m.daocloud.io"
# 华为云镜像
# export REGISTRY_MIRROR="https://05f073ad3c0010ea0f4bc00b7105ec20.mirror.swr.myhuaweicloud.com"
# 阿里云 docker hub 镜像
export REGISTRY_MIRROR=https://registry.cn-hangzhou.aliyuncs.com
curl -sSL https://kuboard.cn/install-script/v1.18.x/install_kubelet.sh | sh -s 1.18.2

Step 4.对于 Master 节点的操作
# 4.初始化 master 节点环境变量说明
# * APISERVER_NAME 不能是 master 的 hostname
# * APISERVER_NAME 必须全为小写字母、数字、小数点,不能包含减号
# * POD_SUBNET 所使用的网段不能与 master节点/worker节点 所在的网段重叠: `export POD_SUBNET=10.100.0.1/16 命令`
# 只在 master 节点执行替换 x.x.x.x 为 master 节点实际 IP(请使用内网 IP)
# export 命令只在当前 shell 会话中有效,开启新的 shell 窗口后,如果要继续安装过程,请重新执行此处的 export 命令
export MASTER_IP=10.10.107.191
# 替换 apiserver.demo 为 您想要的 dnsName
export APISERVER_NAME=apiserver.weiyi
# Kubernetes 容器组所在的网段,该网段安装完成后,由 kubernetes 创建,事先并不存在于您的物理网络中
export POD_SUBNET=10.100.0.1/16
echo "${MASTER_IP} ${APISERVER_NAME}" >> /etc/hosts
curl -sSL https://kuboard.cn/install-script/v1.18.x/init_master.sh | sh -s 1.18.2
# 5.检查 master 初始化结果
# 只在 master 节点执行执行如下命令,等待 3-10 分钟,直到所有的容器组处于 Running 状态
watch kubectl get pod -n kube-system -o wide
# NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
# calico-kube-controllers-5b8b769fcd-pv4g2 1/1 Running 0 11m 10.100.77.1 k8s <none> <none>
# calico-node-ssfqz 1/1 Running 0 11m 10.10.107.191 k8s <none> <none>
# coredns-546565776c-96nnf 1/1 Running 0 11m 10.100.77.3 k8s <none> <none>
# coredns-546565776c-bnkvl 1/1 Running 0 11m 10.100.77.2 k8s <none> <none>
# etcd-k8s 1/1 Running 0 11m 10.10.107.191 k8s <none> <none>
# kube-apiserver-k8s 1/1 Running 0 11m 10.10.107.191 k8s <none> <none>
# kube-controller-manager-k8s 1/1 Running 0 11m 10.10.107.191 k8s <none> <none>
# kube-proxy-8s5lv 1/1 Running 0 11m 10.10.107.191 k8s <none> <none>
# kube-scheduler-k8s 1/1 Running 0 11m 10.10.107.191 k8s <none> <none>
# 查看 master 节点初始化结果
kubectl get nodes -o wide
# NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
# k8s Ready master 6m58s v1.18.2 10.10.107.191 <none> CentOS Linux 7 (Core) 5.6.10-1.el7.elrepo.x86_64 docker://19.3.8
# 6.获得 join命令参数(master节点上运行)
kubeadm token create --print-join-command
# W0506 22:22:32.850186 31335 configset.go:202] WARNING: kubeadm cannot validate component configs for API groups [kubelet.config.k8s.io kubeproxy.config.k8s.io]
# 将node加入到master节点中命令
kubeadm join apiserver.weiyi:6443 --token nuv3rj.j58fccxrcpmvabze --discovery-token-ca-cert-hash sha256:c35aafc3b03ff86c50798adb5745c893c4f6e79b3fdf16c24d348511d3100f0c

Step 5.在Works 节点中的操作
# 7.只在 worker 节点执行
# 替换 x.x.x.x 为 master 节点的内网 IP
export MASTER_IP=10.10.107.191
# 替换 apiserver.demo 为初始化 master 节点时所使用的 APISERVER_NAME
export APISERVER_NAME=apiserver.weiyi
echo "${MASTER_IP} ${APISERVER_NAME}" >> /etc/hosts
# 8.在上面步骤六中kubeadm token create 命令的输出 token
# 但是注意有效时间为 2 个小时,您可以使用此 token 初始化任意数量的 worker 节点。
kubeadm join apiserver.weiyi:6443 --token nuv3rj.j58fccxrcpmvabze --discovery-token-ca-cert-hash sha256:c35aafc3b03ff86c50798adb5745c893c4f6e79b3fdf16c24d348511d3100f0c
# [preflight] Running pre-flight checks
# [preflight] Reading configuration from the cluster...
# [preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -oyaml'
# [kubelet-start] Downloading configuration for the kubelet from the "kubelet-config-1.18" ConfigMap in the kube-system namespace
# [kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
# [kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
# [kubelet-start] Starting the kubelet
# [kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap...
# This node has joined the cluster:
# * Certificate signing request was sent to apiserver and a response was received.
# * The Kubelet was informed of the new secure connection details.
# Run 'kubectl get nodes' on the control-plane to see this node join the cluster.
Step 6.安装校验
# 9.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
# 10.只在 master 节点执行,可以看到STATUS状态一切正常
kubectl get nodes -o wide
# NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
# k8s Ready master 16h v1.18.2 10.10.107.191 <none> CentOS Linux 7 (Core) 5.6.10-1.el7.elrepo.x86_64 docker://19.3.8
# node Ready <none> 10h v1.18.2 10.10.107.192 <none> CentOS Linux 7 (Core) 5.6.10-1.el7.elrepo.x86_64 docker://19.3.8 描述:在 Kubernetes 上部署第一个应用程序,下图是在上面k8s原理图基础添加上了。
1.基础复习 正对于前面所学的一些基础知识进行加深学习: 资源控制器: 译名为部署, 在k8s中通过发布 可以创建应用程序 ,这个实例会被包含在称为 Pod 的概念中 Pod 是 k8s 中最小可管理单元。它提供了一种完全不同的方式来管理应用程序(持续监控创建应用程序实例), 通过创建应用程序实例并确保它们在集群节点中的运行实例个数, (自我修复机制);
Deployment 处于 master 节点上,通过发布 Deployment,master 节点会选择合适的 worker 节点创建 Container(即图中的正方体),Container 会被包含在 Pod (即蓝色圆圈)里。
#K8s Cluster
Master 节点:
- Deployment 控制器
Worker 节点:
- Node
- pod
- Container App # 工作负载
- Node Processes

2.实践应用部署: 描述:使用 kubectl 方式进行部署 nginx Deployment
Step1.创建文件
apiVersion: apps/v1 #与k8s集群版本有关,使用 kubectl api-versions 即可查看当前集群支持的版本
kind: Deployment #该配置的类型,我们使用的是 Deployment
metadata: #译名为元数据,即 Deployment 的一些基本属性和信息
name: nginx-deployment #Deployment 的名称
labels: #标签,可以灵活定位一个或多个资源,其中key和value均可自定义,可以定义多组,目前不需要理解
app: nginx #为该Deployment设置key为app,value为nginx的标签
spec: #这是关于该Deployment的描述,可以理解为你期待该Deployment在k8s中如何使用
replicas: 1 #副本数量(由Deployment控制器创建并且监控)
selector: #标签选择器,与上面的标签共同作用,目前不需要理解
matchLabels: #选择包含标签app:nginx的资源
app: nginx
template: #这是选择或创建的Pod的模板
metadata: #Pod的元数据
labels: #Pod副本拥有的标签,上面的selector即选择包含标签app:nginx的Pod(有了它我们的delopyment控制器才知道匹配的标签已经有一个Pod在运行了)
app: nginx
spec: #期望Pod实现的功能(即在pod中部署)
containers: #生成container,与docker中的container是同一种
- name: nginx #container的名称
image: nginx:latest #使用镜像nginx最新版本创建container,该container默认80端口可访问
Step2.应用后可以可分别查看到一个名为 nginx-deployment 的 Deployment 和一个名为 nginx-deployment-xxxxxxx 的 Pod
$ kubectl apply -f nginx-deployment.yaml
# deployment.apps/nginx-deployment created
Step3.查看部署结果。
# 查看 Deployment
kubectl get deployments
# NAME READY UP-TO-DATE AVAILABLE AGE
# nginx-deployment 1/1 1 1 36s
# 查看 Pod 与指定
kubectl get pods
# NAME READY STATUS RESTARTS AGE
# nginx-deployment-674ff86d-btmt4 1/1 Running 0 53s
kubectl get pods -n default -o wide
# NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
# nginx-deployment-674ff86d-btmt4 1/1 Running 0 3h2m 10.100.167.129 node <none> <none>
至此你已经成功在k8s上部署了一个实例的nginx应用程序,
3.公布应用程序 描述:在创建Service()的时候,通过设置配置文件中的 字段的值,可以以不同方式向外部暴露应用程序:
方式如下:
1.ClusterIP(默认): 在群集中的内部IP上公布服务,这种方式的 Service(服务)只在集群内部可以访问到
2.NodePort : 使用 NAT 在集群中每个的同一端口上公布服务。这种方式下,可以通过访问集群中任意节点+端口号的方式访问服务 (可以端口范围),且此时 ClusterIP 的访问方式仍然可用。
3.LoadBalancer: 在云环境中(需要云供应商可以支持)创建一个集群外部的负载均衡器,并为使用该负载均衡器的 IP 地址作为服务的访问地址。。
Service 关联的Pod创建一个Replication Control(简称RC) 其RC文件包括以下三个关键信息;
Pod定义
Pod运行的副本数量(Replicas)-后面讲解Scaling伸缩应用程序
Pod的被监控的目标标签(Label)
示例:nginx Deployment 创建一个 Service
(1) 上面创建nginx的Deployment中定义了Labels,如下:
metadata: #译名为元数据,即Deployment的一些基本属性和信息
name: nginx-deployment #Deployment的名称
labels: #标签,可以灵活定位一个或多个资源,其中key和value均可自定义,可以定义多组
app: nginx #为该Deployment设置key为app,value为nginx的标签
(2) 创建编辑文件 nginx-service.yaml 内容如下:
$nano nginx-service.yaml
apiVersion: v1 # k8s集群版本
kind: Service # Service 资源控制器
metadata:
name: nginx-service #Service 的名称
labels: #Service 自己的标签
app: nginx #为该 Service 设置 key 为 app,value 为 nginx 的标签
spec: #这是关于该 Service 的定义,描述了 Service 如何选择 Pod,如何被访问
selector: #标签选择器
app: nginx #选择包含标签 app:nginx 的 Pod
ports:
- name: nginx-port #端口的名字
protocol: TCP #协议类型 TCP/UDP
port: 80 #集群内的其他容器组可通过 80 端口访问 Service
nodePort: 30000 #通过任意节点的 30000 端口访问 Service ( The range of valid ports is 30000-32767)
targetPort: 80 #将请求转发到匹配 Pod 的 80 端口
type: NodePort #Serive的类型,ClusterIP/NodePort/LoaderBalancer
(3) 执行命令并检查执行结果
#构建Deploymenet部署pod中的container,利用services中的Lables来关联已经创建的Container
kubectl apply -f nginx-service.yaml
service/nginx-service created
#查看构建的services可查看到名称为 nginx-service 的服务
kubectl get services -o wide
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
# kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 40h <none>
# nginx-service NodePort 10.96.63.155 <none> 80:30000/TCP 32s app=nginx
(4) 访问服务(在master或者worker中执行)
#Master
[root@K8s ~]# curl http://10.10.107.191:30000/hello.html
[root@K8s ~]# curl http://10.100.77.0:30000/hello.html #tunl0
Hello World,Kubernetes!
#Worker
[root@K8s ~]# curl http://10.10.107.192:30000/hello.html
[root@K8s ~]# curl http://10.100.167.128:30000/hello.html #tunl0
Hello World,Kubernetes!
#Node
[root@K8s ~]# curl http://10.100.167.129:80/hello.html
Hello World,Kubernetes!
到目前为止,我们已经成功部署好项目,并能够对其进行访问!
4.伸缩应用程序 描述:当流量增加时,我们需要对应用程序进行伸缩操作以满足系统性能需求。而在K8s中伸缩(Scaling)的实现可以;
Tips:我们前面创建了一个Deployment然后通过服务(Services)提供访问Pod的方式,下面通过更改部署中的 replicas(副本数)来完成扩展;
spec:
replicas: 2 #使用该Deployment创建两个应用程序实例
示例:下图中 Service A 只将访问流量转发到 IP 为 10.0.0.5 的Pod上修改了 Deployment 的 replicas 为 4 后,Kubernetes 又为该 Deployment 创建了 3 新的 Pod,这 4 个 Pod 有相同的标签。 因此Service A通过标签选择器与新的 Pod建立了对应关系,将访问流量通过负载均衡在 4 个 Pod 之间进行转发。

示例:将 nginx Deployment 扩容到 2 个副本
apiVersion: apps/v1 #与k8s集群版本有关,使用 kubectl api-versions 即可查看当前集群支持的版本
kind: Deployment #该配置的类型,我们使用的是 Deployment
metadata: #译名为元数据,即 Deployment 的一些基本属性和信息
name: nginx-deployment #Deployment 的名称
labels: #标签,可以灵活定位一个或多个资源,其中key和value均可自定义,可以定义多组,目前不需要理解
app: nginx #为该Deployment设置key为app,value为nginx的标签
spec: #这是关于该Deployment的描述,可以理解为你期待该Deployment在k8s中如何使用
replicas: 2 #使用该Deployment创建一个应用程序实例(动态扩容)
selector: #标签选择器,与上面的标签共同作用,目前不需要理解
matchLabels: #选择包含标签app:nginx的资源
app: nginx
template: #这是选择或创建的Pod的模板
metadata: #Pod的元数据
labels: #Pod的标签,上面的selector即选择包含标签app:nginx的Pod
app: nginx
spec: #期望Pod实现的功能(即在pod中部署)
containers: #生成container,与docker中的container是同一种
- name: nginx #container的名称
image: nginx:latest #使用镜像nginx最新版本创建container,该container默认80端口可访问
ports:
- containerPort: 80
执行命令进行部署扩容执行, kubectl apply -f nginx-deployment.yaml
查看结果执行,watch kubectl get pods -o wide

应用访问:
[root@K8s ~]# curl http://10.100.167.132/test.html
<b>Scaling - 10.100.167.132</b>
[root@K8s ~]# curl http://10.100.167.131/test.html
<b>Scaling - 10.100.167.131</b>
#Cluster IP / Worker Node IP
http://10.10.107.191:30000/test.html

PS : 一旦运行了多个应用程序实例,就可以在不停机的情况下执行滚动更新了;
5.执行滚动更新 描述:在 Kubernetes 中通过 Rolling Update 滚动更新来进行应用版本的迭代部署,滚动更新允许以下操作:;
将应用程序从准上线环境升级到生产环境(通过更新容器镜像)
回滚到以前的版本
持续集成和持续交付应用程序,无需停机
补充说明:
将应用程序 Scale Up(扩容)为多个实例,这是执行更新而不影响应用程序可用性的前提()
k8s更新多副本的 Deployment 的版本时,会逐步的创建新版本的 Pod,逐步的停止旧版本的 Pod,以便使应用一直处于可用状态。
在K8S中更新是版本化的,任何部署更新都可以恢复为以前的(稳定)版本。
示例:
1.原本 Service A 将流量负载均衡到 4 个旧版本的 Pod (当中的容器为 绿色)上
2.更新完 Deployment 部署文件中的镜像版本后,master 节点选择了一个 worker 节点,并根据新的镜像版本创建 Pod(紫色容器)。
新 Pod 拥有唯一的新的 IP, 同时 master 节点选择一个旧版本的 Pod 将其移除; 此时 Service A 将新 Pod 纳入到负载均衡中。

3.同步骤2再创建一个新的 Pod 替换一个原有的 Pod
4.如此 Rolling Update 滚动更新,直到所有旧版本 Pod 均移除,新版本 Pod 也达到 Deployment 部署文件中定义的副本数,则滚动更新完成

实践案例,更新 nginx Deployment Step1.修改文件nginx-deployment-update.yaml中 image 镜像的标签,如下所示
apiVersion: apps/v1 #与k8s集群接口版本有关,使用 kubectl api-versions 即可查看当前集群支持的版本
kind: Deployment # Deployment 资源控制器
metadata: #译名为元数据,即 Deployment 的一些基本属性和信息
name: nginx-deployment #Deployment 的名称
labels: #标签,可以灵活定位一个或多个资源,其中key和value均可自定义,可以定义多组,目前不需要理解
app: nginx #为该Deployment设置key为app,value为nginx的标签
spec: #这是关于该Deployment的描述,可以理解为你期待该Deployment在k8s中如何使用
replicas: 2 #使用该Deployment创建一个应用程序实例(动态扩容)
selector: #标签选择器,与上面的标签共同作用,目前不需要理解
matchLabels: #选择包含标签app:nginx的资源
app: nginx
template: #这是选择或创建的Pod的模板
metadata: #Pod的元数据
labels: #Pod的标签,上面的selector即选择包含标签app:nginx的Pod
app: nginx
spec: #期望Pod实现的功能(即在pod中部署)
containers: #生成container,与docker中的container是同一种
- name: nginx #container的名称
image: nginx:1.17.9 #使用镜像nginx:1.17.9替换原来的nginx:1.17.10
ports:
- containerPort: 80 #容器开放端口
Step2.执行部署命令与查看过程结果
#部署命令
kubectl apply -f nginx-deployment-update.yaml
#观察到 pod 逐个被替换的过程
watch kubectl get pods -l app=nginx
#替换版本查看
kubectl describe pods -l app=nginx | egrep "^Name:|Image:"
Name: nginx-deployment-b48955944-bz4xr
Image: nginx:1.17.9
Name: nginx-deployment-b48955944-ng6cs
Image: nginx:1.17.9


原文地址:https://blog.weiyigeek.top/2020/4-22-468.html

本文至此完毕,更多技术文章,尽情期待下一章节!

已发布的相关历史文章(点击即可进入)
1.我在B站学云原生之Kubernetes基础入门学习概述系统架构及组件浅析
4.我在B站学云原生之Docker容器数据持久化介绍与实践
6.我在B站学云原生之Docker容器Registry私有镜像仓库搭建实践
7.我在B站学云原生之Docker容器Dockerfile镜像构建浅析与实践
8.我在B站学云原生之Docker容器镜像构建最佳实践浅析
9.我在B站学云原生之Docker容器优化镜像体积缩小技巧实践
11.我在B站学云原生之Docker容器编排工具docker-compose安装使用实践
13.我在B站学云原生之Docker容器镜像构建存储原理浅析与实践
14.我在B站学云原生之Docker容器Registry私有镜像仓库安全配置与GC回收实践
17.我在B站学云原生之Docker容器相关辅助工具使用介绍
18.我在B站学云原生之Docker容器安装运行所遇异常问题解决集合
19.我在B站学云原生之Harbor企业级私有镜像存储仓库入门实践
20.我在B站学云原生之如何使用Skopeo工具做一个优雅的镜像搬运工
1.我在B站学云原生之快速拥抱下一代容器引擎Podman来替代Docker容器
2.我在B站学云原生之快速拥抱下一代容器引擎Podman常用命令浅析与简单配置

欢迎各位志同道合的朋友一起学习交流,如文章有误请在下方留下您宝贵的经验知识,个人邮箱地址【master#weiyigeek.top】或者 个人公众号【WeiyiGeek】联系我。

更多文章来源于【WeiyiGeek Blog - 为了能到远方,脚下的每一步都不能少】 个人博客。
个人主页: 【 https://weiyigeek.top 】
博客地址: 【 https://blog.weiyigeek.top 】

https://weiyigeek.top - Always keep a beginner's mind, don't forget the beginner's mind
专栏书写不易,如果您觉得这个专栏还不错的,请给这篇专栏【点个赞、投个币、收个藏、关个注,转个发、留个言】,这将对我的肯定,谢谢!。
echo "【点个赞】,动动你那粗壮的拇指或者芊芊玉手,亲!"
printf("%s", "【投个币】,万水千山总是情,投个硬币行不行,亲!")
fmt.Printf("【收个藏】,阅后即焚不吃灰,亲!")
System.out.println("【关个注】,后续浏览查看不迷路哟,亲!")
console.info("【转个发】,让更多的志同道合的朋友一起学习交流,亲!")
cout << "【留个言】,文章写得好不好、有没有错误,一定要留言哟,亲! " << endl;

谢谢,各位帅哥、美女四连支持!!这就是我的动力!
更多网络安全、系统运维、应用开发、全栈文章,尽在【个人博客 - https://blog.weiyigeek.top】站点,谢谢支持!