针对Kubernetes快速入门和kubernetes快速入门pdf这两个问题,本篇文章进行了详细的解答,同时本文还将给你拓展(三)Kubernetes快速入门、KubernetesPythonAPI
针对Kubernetes 快速入门和kubernetes快速入门 pdf这两个问题,本篇文章进行了详细的解答,同时本文还将给你拓展(三)Kubernetes 快速入门、Kubernetes Python API快速入门、Kubernetes 学习 4 kubernetes 应用快速入门、Kubernetes 学习 5 kubernetes 资源清单定义入门等相关知识,希望可以帮助到你。
本文目录一览:- Kubernetes 快速入门(kubernetes快速入门 pdf)
- (三)Kubernetes 快速入门
- Kubernetes Python API快速入门
- Kubernetes 学习 4 kubernetes 应用快速入门
- Kubernetes 学习 5 kubernetes 资源清单定义入门
Kubernetes 快速入门(kubernetes快速入门 pdf)
我保证本文是最详尽的 Kubernetes 技术文档,从我在后台排版了这么漫长的时间就能看出来。废话不多说 —— 牢牢占据容器技术统治地位的 Kubernetes,其重要性想必不言而喻。
以下为译文:
为什么银行肯花大价钱雇我做 Kubernetes 如此简单的工作?—— 我一直很奇怪这一点,因为我觉得任何人都可以在 3 个小时内学会这项技术。
如果你怀疑我说的,就来挑战一下吧!读完本文,你绝对可以学会如何在 Kubernetes 集群上运行基于微服务的应用程序。我保证你可以做到,因为我就是这样向我的客户介绍 Kubernetes 的。
本文的教程与其他资源有何不同?有很大不同。大多数的教程都从最简单的内容讲起:Kubernetes 的概念和 kubectl 的命令。本文则是基于读者了解应用程序的开发、微服务和 Docker 容器等基础之上。
本文中,我们会涉及的内容包括:
在计算机上运行基于微服务的应用程序;为微服务应用程序的每个服务建立容器映像;Kubernetes 的基本介绍;在 Kubernetes 管理的集群内部署基于微服务的应用程序。
通过一步步深入学习,让大家能够领会 Kubernetes 的简单易用。只有你了解它的使用环境时,才能轻松掌握 Kubernetes。废话不多说,我们开始吧。
应用程序示范
如下应用程序有一个功能:每次输入接受一个句子;使用文本分析,计算句子所表达的情绪。
图 1:情感分析网络应用
从技术的角度看来,这个应用程序包含 3 个微服务,每个都包含特定功能:
SA-Frontend:前端, Nginx 网络服务器,提供 ReactJS 静态文件;SA-WebAp:网络应用, Java 网络应用程序,处理来自前端的请求;SA-Logic:逻辑处理, Python 应用程序,执行情感分析。你需要知道微服务是无法独立工作的,它们引入了 “关注点分离”(separation of concerns),但是它们之间依然需要交互。
图 2:情感分析网络应用中的数据流
我们可以通过微服务之间的数据流来描述这种交互:
客户端应用程序请求初始页面 index.html(index.html 页面会反过来加载 ReactJS 应用程序的脚本);用户与应用程序的交互触发到 Spring 网络应用的请求;Spring 网络应用将请求发送给 Python 应用做情感分析;Python 应用计算情感值,并返回结果;Spring 网络应用将结果返回给 React 应用(然后由 React 应用将结果显示给用户)。点击此处下载这些应用程序的代码:https://github.com/rinormaloku/k8s-mastery。现在就可以克隆这个代码仓库,接下来我们要做更加精彩的东西。
在计算机上运行基于微服务的应用程序
我们需要启动所需的 3 个服务。让我们从最有意思的部分 —— 前端应用程序开始。
设置 React 的本地部署
为了运行 React 应用程序,首先你需要在计算机上安装 NodeJS 和 NPM。安装好这些后,在终端中进入目录 sa-frontend。然后运行如下命令:
npm install
该命令会将 React 应用程序的所有 Javascript 依赖都下载到文件夹 node_modules 中(package.json 文件中定义了所有依赖)。在所有依赖都解决后,运行如下命令:
npm start
这样就可以了!我们运行了 React 应用程序,现在可以通过默认端口 localhost:3000 访问该应用程序了。你可以自由修改代码,并从浏览器中观察即时效果。这里用到了热模块替换(即在运行时用替换模块来减少页面刷新次数)技术,可以减轻前端开发的工作。
准备好 React 应用的产品环境
为了搭建产品环境,我们需要建立应用程序的静态网页,并通过网络服务器提供服务。
为了搭建 React 应用程序,首先在终端中进入目录 sa-frontend。然后运行如下命令:
npm run build
该命令会在项目的文件目录中生成一个名叫 “build” 的文件夹。该文件夹内包含了 ReactJS 应用程序所需的所有静态文件。
利用 Nginx 提供静态文件
首先安装并启动 Nginx 网络服务器。然后将 sa-frontend/build 目录内的文件移动到 [nginx 安装目录]/html。
如此一来,我们就可以通过 [nginx 安装目录]/html/index.html 来访问 index.html 文件了,而它是 Nginx 服务的默认文件。
默认情况下,Nginx 网络服务器会监听端口 80。你可以通过修改 [nginx 安装目录]/conf/nginx.conf 文件中的 server.listen 字段来指定不同的端口。
打开浏览器,并访问端口 80,可以看到 ReactJS 应用程序加载成功。
图 3:Nginx 提供的 React 应用程序服务
在输入框 “Type your sentence”(输入句子)中输入句子,然后点击 SEND(发送)按钮,但是页面会返回错误 404(你可以检查浏览器的控制台)。为什么?让我们检查一下代码。
检查代码
我们可以在 App.js 文件中看到,点击 “SEND” 按钮会触发 analyzeSentence。该方法的代码如下所示(我们对每一段代码进行了编号 “# 号码”,具体解释如下所示):
analyzeSentence() { fetch(''http://localhost:8080/sentiment'', { // #1 method: ''POST'',headers: {''Content-Type'': ''application/json''},body: JSON.stringify({sentence: this.textField.getValue()})// #2 }) .then(response => response.json()) .then(data =>this.setState(data)); // #3}
#1:POST 方法调用的 URL(应用程序应该在该 URL 上监听访问);#2:发送到应用程序的请求主体如下所示:
{sentence: “I like yogobella!”}
#3:返回值将更新该组件的状态,而状态的变更将重新渲染这个组件。如果我们收到数据(即包含用户输入的句子和极性的 JSON 对象),那么我们会显示组件 polarityComponent,因为满足条件而且我们可以如下定义该组件:
const polarityComponent = this.state.polarity !== undefined ? <Polarity sentence={this.state.sentence} polarity={this.state.polarity}/> :null;
一切看起来都很好。但是我们还差什么呢?你可能已经发现我们没有在 localhost:8080 上设置任何东西!我们必须启动 Spring 网络应用程序监听这个端口!
图 4:缺失的 Spring 网络应用程序微服务
建立 Spring 网络应用程序
为了设置 Spring 网络应用程序,你必须安装 JDK8 和 Maven,并设置它们的环境变量。设置好后,我们继续下个部分。
将应用程序打包成 Jar 文件
在终端中进入 sa-webapp 目录,并运行如下命令:
mvn install
该命令会在目录 sa-webapp 中生成一个名叫 target 的文件夹。target 文件夹内有打包好的 Java 应用程序包:’sentiment-analysis-web-0.0.1-SNAPSHOT.jar’。
启动应用程序
进入 target 目录,并通过如下命令启动应用程序:
java-jarsentiment-analysis-web-0.0.1-SNAPSHOT.jar
等等…… 出错了。应用程序启动失败,我们可以看到如下异常信息:
Error creating bean with name ''sentimentController'': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder ''sa.logic.api.url''in value "${sa.logic.api.url}"
这里显示的重要信息是 SentimentController 中的 sa.logic.api.url。我们检查一下这段代码。
检查代码
@CrossOrigin(origins = "*")@RestControllerpublicclassSentimentController{@Value("${sa.logic.api.url}")// #1private String saLogicApiUrl;@PostMapping("/sentiment")public SentimentDto sentimentAnalysis(@RequestBody SentenceDto sentenceDto) { RestTemplate restTemplate = new RestTemplate();return restTemplate.postForEntity( saLogicApiUrl + "/analyse/sentiment", // #2 sentenceDto, SentimentDto.class) .getBody(); }}
#1:SentimentController 有一个名叫 saLogicApiUrl 的字段。这个字段的赋值是由 sa.logic.api.url 属性定义的。#2:saLogicApiUrl 与值 “/analyse/sentiment” 连接在一起,共同构成了 Sentiment Analysis 请求的 URL。
定义属性
在 Spring 中默认的属性资源是 application.properties(具体位置在 sa-webapp/src/main/resources 中)。但是这不是定义属性的唯一方式,我们可以通过之前的命令完成属性定义:
java -jar sentiment-analysis-web-0.0.1-SNAPSHOT.jar --sa.logic.api.url=WHAT.IS.THE.SA.LOGIC.API.URL
应该由 Python 应用程序运行时定义的值初始化该属性,如此一来 Spring 网络应用程序就可以知道在运行时把信息传递到哪里了。
为了简单起见,我们假设在 localhost:5000 上运行 Python 应用程序。请记得哦!
运行如下命令,然后我们来看看最后一个服务:Python 应用程序。
java -jar sentiment-analysis-web-0.0.1-SNAPSHOT.jar --sa.logic.api.url=http://localhost:5000
建立 Python 应用程序
为了启动 Python 应用程序,首先我们需要安装 Python3 和 Pip,以及设置它们的环境变量。
安装依赖
在终端中进入 sa-logic/sa (代码库),然后运行如下命令:
python-mpipinstall-rrequirements.txtpython-mtextblob.download_corpora
启动应用
在利用 Pip 安装好依赖后,我们就可以通过运行如下命令启动应用程序了:
python sentiment_analysis.py* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
这意味着应用程序已经启动,并在 localhost 的端口 5000 上监听 HTTP 请求了。
检查代码
让我们检查代码,看看处理逻辑部分的 Python 应用程序在干什么:
from textblob import TextBlobfrom flask import Flask, request, jsonifyapp = Flask(__name__) #1@app.route("/analyse/sentiment", methods=[''POST'']) #2def analyse_sentiment(): sentence = request.get_json()[''sentence''] #3 polarity = TextBlob(sentence).sentences[0].polarity #4return jsonify( #5 sentence=sentence, polarity=polarity )if __name__ == ''__main__'': app.run(host=''0.0.0.0'', port=5000) #6
#1:实例化一个 Flask 对象;#2:定义 POST 请求访问的路径;#3:从请求主体内抽出 “sentence” 属性;#4:初始化匿名 TextBlob 对象,并从第一个句子(我们只有一个)中获取极性;#5:在相应体内返回句子和极性;#6:运行 flask 对象应用来监听 localhost:5000 上的请求。
所有的服务都设置好,可以互相交流了。试试看重开前端的 localhost:80。
图 6:微服务架构完成
在下面一节中,我们将介绍如何在 Docker 容器内启动这些服务,因为这是在 Kubernetes 集群内运行这些服务的前提条件。
为每个服务创建容器映像
Kubernetes 是容器管理平台。可想而知我们需要容器去管理它们。但是容器是什么?Docker 官方文档的最佳答案如下:
容器映像是轻量级的、独立的、可执行软件包,包含所有可运行的东西:代码、运行时、系统工具、系统库、设置。对于基于 Linux 和 Windows 的应用,不论环境如何,容器化的软件都可以照常运行。
这意味着容器可以在任何计算机上运行,甚至是在产品服务器上,都没有任何差别。
为了更形象地描述,让我们来对比一下 React 应用程序在虚拟机上和容器内运行的情况。
通过虚拟机提供 React 静态文件
使用虚拟机的缺点包括:
资源效率低下,每个虚拟机都需要一个完全成熟的操作系统;对平台有依赖性。本地机器上运行得很好的功能未必能在产品服务器上正常工作;与容器相比,更重而且规模伸缩较慢。
图 7:虚拟机上提供静态文件的 Nginx 网络服务器
通过容器提供 React 静态文件
使用容器的优点包括:
资源效率很高,在 Docker 的帮助下使用主机操作系统;对平台没有依赖性。可以在本地机器上运行的容器可以在任何机器上正常工作;通过映像层提供轻量级服务。
图 8:在容器内提供静态文件的 Nginx 网络服务器
以上是使用容器最突出的特色和优势。更多信息,请参阅 Docker 官方文档:https://www.docker.com/what-container。
为 React 应用建立容器映像(Docker 简介)
Docker 容器最基本的组件是 .dockerfile。该 Dockerfile 文件最基本的组成是容器镜像,我们将通过下列一系列说明,介绍如何创建一个符合应用程序需求的容器镜像。
在开始定义 Dockerfile 之前,让我们先回想一下使用 Nginx 服务 React 静态文件的步骤:
创建静态文件(npm run build);启动 Nginx 服务器;将前端项目的 build 文件夹的内容复制到 nginx/html 目录中。在下一节中,你会注意到创建容器与建立本地 React 的过程非常相似。
为前端定义 Dockerfile
前端 Dockerfile 的建立只有两个步骤。这是因为 Nginx 团队为我们提供了基本的 Nginx 映像,我们可以直接利用。这两个步骤如下:
启动基本的 Nginx 映像;将 sa-frontend/build 目录复制到容器的 nginx/html 中。转换成的 Dockerfile 如下所示:
FROM nginxCOPY build /usr/share/nginx/html
很惊讶吧?这个文件是可读的,我们可以概括为:
从 Nginx 映像开始(不管里面是什么)。将 build 目录复制到映像的 nginx/html 目录中。然后就好了!
你可能在想,我该从哪儿复制 build 文件呢?例如:/usr/share/nginx/html。非常简单:在 Docker Hub 的 Nginx 映像文档中有记载。
建立并推送容器
在推送映像之前,我们需要一个容器注册来托管映像。Docker Hub 是一个免费的云容器服务,我们将使用它来做演示。接下来有 3 个任务需要完成:
安装 Docker CE;注册 Docker Hub;在终端中运行如下命令登录:docker login -u="$DOCKER_USERNAME" -p="$DOCKER_PASSWORD"
在完成上述任何后,请进入目录 sa-frontend。然后运行如下命令(请用你的 docker hub 用户名替换 $DOCKER 用户名,例如:rinormaloku/sentiment-analysis-frontend)。
docker build -f Dockerfile -t $DOCKER_USER_ID/sentiment-analysis-frontend .
现在我们可以删掉 -f Dockerfile 了,因为我们已经在包含 Dockerfile 的目录中了。
我们可以使用 docker push 命令来推送映像:
docker push $DOCKER_USER_ID/sentiment-analysis-frontend
请确认映像已成功地被推送到 docker hub 代码库。
运行容器
现在任何人都可以获取 $DOCKER_USER_ID/sentiment-analysis-frontend 中的映像并运行:
docker pull $DOCKER_USER_ID/sentiment-analysis-frontenddocker run -d -p 80:80$DOCKER_USER_ID/sentiment-analysis-frontend
Docker 容器已经处于运行状态了!
在进行下一步之前,让我们先来讲解一下 80:80,很多人对此比较不解:
第一个 80 是主机的端口号(例如:我的计算机);第二个 80 是容器的端口号,请求都会被转送到这里。
图 9:从主机到容器的端口匹配
这是从 <主机端口> 匹配到 < 容器端口 > 的。也就是说每个发往主机 80 端口的请求都会被匹配到容器的 80 端口,如图 9 所示。
因为在主机上(你的计算机)80 端口上运行的端口可以访问 localhost:80。如果本地不支持 Docker,那么你可以在 <docker 机器 ip>:80 上打开应用程序。运行 docker-machine ip 命令可以找到 Docker 机器的 IP。
试试看!你现在应该可以访问 React 应用程序了。
Dockerignore 文件
刚才我们看到建立 SA-Frontend 的映像非常慢,不好意思,应该是超级慢。这是因为我们必须将建立过程中的环境文件发送给 Docker 服务。更具体地来说,建立过程中的环境文件指的是在建立映像的时候,所有会用到的 Dockerfile 目录中的数据。
以我们的例子来说,SA-Frontend 文件包括如下文件夹:
sa-frontend:| .dockerignore| Dockerfile| package.json| README.md+---build+---node_modules+---public\---src
但是我们只需要 build 文件夹。上传其他的文件会浪费时间。我们可以通过删除其他目录来节约时间。这就需要用到 .dockerignore。你可能觉得这与 .gitignore 很相似,例如你可以所有想要忽略的目录都添加到 .dockerignore,如下所示:
node_modulessrcpublic
这个 .dockerignore 文件应该与 Dockerfile 在同一文件夹中。现在建立映像文件只需要几秒钟了。
让我们继续看看 Java 应用程序。
为 Java 应用程序建立容器映像
你知道吗?你已经差不多学习了所有关于创建容器映像的知识!这就是为什么这一小节这么短的原因。
在 sa-webapp 中打开 Dockerfile,你会看到只有两个新的关键字:
ENV SA_LOGIC_API_URL http://localhost:5000…EXPOSE 8080
关键字 ENV 在 Docker 容器内声明了环境变量。这可以让我们在启动容器的时候为情感分析 API 提供 URL。
另外,关键字 EXPOSE 提供了一个端口,供我们以后访问。但是等等,我们在 SA-Frontend 的时候没有做这一步,说得很对!这个端口仅用于文档,换句话说就是这个端口是用来向阅读 Dockerfile 的人提供信息的。
你应该已经掌握了创建和推送容器映像。如果遇到任何困难,可以阅读 sa-webapp 中的 README.md 文件。
为 Python 应用程序创建容器映像
sa-logic 的 Dockerfile 中没有新的关键字。现在你已经是 Docker 达人了。
关于如何建立和推送容器映像,请阅读 sa-logic 目录中的 README.md 文件。
测试容器化的应用程序
你能相信没有测试过的东西吗?我也不信。所以我们来测试一下这些容器吧。
1. 运行 sa-logic 容器,并配置监听端口 5050:
docker run -d -p 5050:5000$DOCKER_USER_ID/sentiment-analysis-logic
2. 运行 sa-webapp 容器,并配置监听端口 8080(因为我们改变了 Python 应用监听的端口,所以我们需要重写环境变量 SA_LOGIC_API_URL):
$ docker run -d -p 8080:8080 -e SA_LOGIC_API_URL=''http://<container_ip or docker machine ip>:5000'' $DOCKER_USER_ID/sentiment-analysis-web-app
3. 运行 sa-frontend 容器:
docker run -d -p 80:80$DOCKER_USER_ID/sentiment-analysis-frontend
然后就可以了。在浏览器中打开 localhost:80。
请注意:如果你改变 sa-webapp 的端口,或使用 Docker 机器的 IP,那么你需要更新 sa-frontend 中的 App.js,让 analyzeSentence 从新的 IP 或端口获取 URL。然后你需要建立并使用更新后的映像。
图 10:在容器内运行微服务
智力问答题 —— 为什么使用 Kubernetes?
本节中,我们学习了 Dockerfile,如何使用它创建映像,以及推送映像到 Docker 注册目录的命令。另外,我们探讨了如何通过忽略没用的文件,减少需要发送的建立过程中的环境文件。最后我们从容器上运行了应用程序。
接下来,我们介绍为什么要使用 Kubernetes?我们将在下面深入介绍 Kubernetes,这里我想给你留个智力问答题。
如果我们的情感分析网络应用完成得很好,突然间访问量暴涨到每分钟数百万的请求,那么我们的 sa-webapp 和 sa-logic 将面临巨大的负荷压力。请问,我们如何才能扩大容器的规模?
Kubernetes 简介
我向你保证我没有夸大其词,读完本文你会问 “为什么我们不称它为 Supernetes?”
图 11:Supernetes
Kubernetes 是什么?
从容器启动微服务后,我们有一个问题,让我们通过如下问答的形式具体描述这个问题:
问:我们怎么扩大或缩小容器?答:我们启动另外一个容器。问:我们如何在容器间分摊负荷?如果当前服务器的负荷达到最大,那我们是否需要另外一个服务器?我们如何最大化硬件使用率?答:唔...... 呃......(让我搜一下)问:如果在打更新补丁的时候,不影响到所有的服务?如果服务出了问题,如何才能返回之前能正常工作的版本?
Kubernetes 可以解决以上所有问题(以及更多问题!)。我可以用一句话总结 Kubernetes:“Kubernetes 是容器控制平台,可以抽象所有的底层基础设施(容器运行用到的基础设施)。”
我们对容器控制平台有个模糊的概念。在本文后续部分,我们将看看它的实际应用,但是这是第一次我们提到 “底层基础设施的抽象”,所以我们来详细看看这个概念。
底层基础设施的抽象
Kubernetes 通过一个简单的 API 提供底层基础设施的抽象,我们可以向该 API 发送请求。这些请求可以让 Kubernetes 尽最大能力应对。例如,可以简单地要求 “Kubernetes 添加映像 x 的 4 个容器。” 然后 Kubernetes 会找出使用中的节点,并在内添加新的容器(如图 12 所示)。
图 12:向 API 发送请求
这对开发人员来说意味着什么?意味着开发人员不需要在意节点的数目,也不需要在意从哪里运行容器以及如何与它们交流。开发人员不需要管理硬件优化,或担心节点关闭(它们将遵循墨菲法则),因为新的节点会添加到 Kubernetes 集群。同时 Kubernetes 会在其他运行的节点中添加容器。Kubernetes 会发挥最大的作用。
在图 2 中我们看到了一些新东西:
API 服务器:与集群交互的唯一方式。负责启动或停止另外一个容器,或检查当前状态,日志等;Kubelet:监视节点内的容器,并与主节点交流;Pod:初始阶段我们可以把 pod 当成容器。就介绍这么多,跟深入的介绍会导致我们分心,我们可以等到后面一点再介绍,有一些有用的资源,比如官方文档,或者阅读 Marko Luka 的著作《Kubernetes in Action》,以及 Sébastien Goasguen & Michael Hausenblas 的《Kubernetes Cookbook》。
标准化的云服务提供商
Kubernetes 另外一个深入人心的点是:它标准化了云服务提供商。这是一个很大胆的宣言,我们通过如下例子来具体看一看:
比如,有一个 Azure、Google 云平台或其他云服务提供商的专家,他担任了一个搭建在全新的云服务提供商的项目。这可能引起很多后果,比如说:他可能无法在截止期限内完成;公司可能需要招聘更多相关的人员,等等。
相对的,Kubernetes 就没有这个问题。因为不论是哪家云服务提供商,你都可以在上面运行相同的命令。你可以以既定的方式向 API 服务器发送请求。Kubernetes 会负责抽象,并实装这家云服务商。
停一秒钟仔细想一下,这是极其强有力的功能。对公司来说,这意味着他们不需要绑定到一家云服务商。他们可以计算别家云服务商的开销,然后转移到别家。他们依旧可以保留原来的专家,保留原来的人员,他们还可以花更少的钱。
说了这么多,在下一节中让我们来实际使用 Kubernetes。
Kubernetes 实践 ——Pod
我们建立了微服务在容器上运行,虽然颇为坎坷,但还是可以工作的。我们还提到这种解决方案不具有伸缩性和弹性,而 Kubernetes 可以解决这些问题。在本文的后续章节,我们会将各个服务转移到由 Kubernetes 管理的容器中,如图 13 所示。
图 13:在 Kubernetes 管理的集群中运行微服务
在本文中,我们将使用 Minikube 进行本地调试,尽管所有东西都是运行在 Azure 和 Google 云平台中的。
安装和启动 Minikube
请参阅安装 Minikube 的官方文档:
https://kubernetes.io/docs/tasks/tools/install-minikube/ 在安装 Minikube 的同时,你可以捎带着安装 Kubectl。Kubectl 是向 Kubernetes API 服务器发送请求的客户端。
可以通过运行 minikube start 命令启动 Minikube,在启动后,运行 kubectl get nodes 命令可以得到如下结果:
kubectlgetnodesNAMESTATUSROLESAGEVERSIONminikubeReady <none> 11mv1.9.0
Minikube 提供给我们的 Kubernetes 集群只有一个节点,但是记住我们并不在乎有多少个节点,Kubernetes 会负责抽象,对我们来说深入掌握 Kubernetes 并不重要。
在下一节中,我们将介绍 Kubernetes 的第一个资源:Pod。
Pod
我大爱容器,相信现在你也很喜欢容器。那为什么 Kubernetes 给我们最小的可部署计算单元 Pod 呢?Pod 是干什么的?由一个或一组容器组成的 Pod 可以共享相同的运行环境。
但是我们真的需要在一个 Pod 内运行两个容器吗?呃…… 一般来说,只会运行一个容器,我们的例子中也是这样的。但是有些情况下,比如两个容器需要共享卷,或它们之间是通过跨进程的交流方式交流的,又或者它们被绑到一起,那么就可以使用 Pod。Pod 的另一个特征是:如果我们希望使用其他 Rke 等技术的话,我们可以做到不依赖 Docker 容器。
图 14:Pod 属性
总的来说,Pod 的主要属性包括(如图 14 所示):
每个 Pod 可以在 Kubernetes 集群内拥有唯一的 IP 地址;Pod 可以拥有多个容器。这些容器共享同一个端口空间,所以他们可以通过 localhost 交流(可想而知它们无法使用相同的端口),与其他 Pod 内容器的交流可以通过结合 Pod 的 IP 完成;一个 Pod 内的容器共享同一个卷、同一个 IP、端口空间、IPC 命名空间。注:容器有个自己独立的文件系统,尽管他们可以通过 Kubernetes 的资源卷共享数据。
更多详细内容,请参阅相关的官方文档:
https://kubernetes.io/docs/concepts/workloads/pods/pod/
Pod 的定义
如下是我们的第一个 pod sa-frontend 的清单文件,我们会对文件内容进行逐一解释。
apiVersion: v1kind: Pod # 1metadata: name: sa-frontend # 2spec: # 3 containers: - image: rinormaloku/sentiment-analysis-frontend # 4 name: sa-frontend # 5 ports: - containerPort: 80 # 6
#1 kind:指定我们想创建的 Kubernetes 资源的类型。这里是 Pod。#2 name:定义该资源的名字。我们在这里命名为 sa-frontend。#3 spec:该对象定义了资源应有的状态。Pod Spec 中最重要的属性是容器的数组。#4 image:是指我们希望在本 Pod 中启动的容器的映像。#5 name:Pod 中容器中唯一的名字。#6 containerPort:是指容器监听的端口号。这只是为了提供文档信息(即便没有这个端口也不会影响访问)。
创建 SA Frontend 的 Pod
你可以在 resource-manifests/sa-frontend-pod.yaml 中找到上述 Pod 的定义。你可以在终端中进入该文件夹,或在命令行输入完整的路径。然后执行如下命令:
kubectl create -f sa-frontend-pod.yamlpod "sa-frontend" created
可以通过如下命令确认 Pod:
kubectl get podsNAME READY STATUS RESTARTS AGEsa-frontend 1/1 Running 07s
如果该 Pod 还处于容器生成中的状态的话,你可以在运行命令的时候加入参数 --watch,当 Pod 进入运行状态的时候,终端会显示信息。
从外部访问应用程序
为了从外部访问应用程序,我们需要创建服务类型的 Kubernetes 资源,具体内容我们将在后续章节讲解,虽然通过服务类型的资源支持外部访问是更合适的做法,但是此处为了快速调试,我们还有另外一个办法,即转发端口:
kubectlport-forwardsa-frontend-pod 88:80Forwardingfrom 127.0.0.1:88-> 80
在浏览器中访问 127.0.0.1:88,即可打开 React 应用程序。
扩大规模的错误方法
我们说过 Kubernetes 的主要特色之一就是伸缩性,为了证明这一点,让我们运行另外一个 Pod。我们通过如下定义创建另外一个 Pod 资源:
apiVersion: v1kind: Pod metadata: name: sa-frontend2 # The only changespec: containers: - image: rinormaloku/sentiment-analysis-frontend name: sa-frontend ports: - containerPort: 80
然后,通过如下命令创建新的 Pod:
kubectl create -f sa-frontend-pod2.yamlpod "sa-frontend2" created
可以通过如下命令确认第二个 Pod:
kubectl get podsNAME READY STATUS RESTARTS AGEsa-frontend 1/1 Running 07ssa-frontend2 1/1 Running 07s
现在我们有两个运行中的 Pod。
请注意:这不是最终的解决方案,还有很多缺陷。我们将在另一个 Kubernetes 资源的部署一节中改善这个方案。
总结 Pod
提供静态文件的 Nginx 网络服务器在另个不同的 Pod 内运行。现在我们有两个问题:
怎样对外开放这些服务,让用户通过 URL 来访问它们?怎样平衡 Pod 之间的负荷?
图 15:服务之间的负荷平衡
Kubernetes 提供了服务类型的资源。在下一节中我们将详细介绍。
Kubernetes 实践 —— 服务
Kubernetes 服务资源可以作为一组提供相同服务的 Pod 的入口。这个资源肩负发现服务和平衡 Pod 之间负荷的重任,如图 16 所示。
图 16:Kubernetes 服务维护 ID 地址
在 Kubernetes 集群内,我们拥有提供不同服务的 Pod(前端、Spring 网络应用和 Flask Python 应用程序)。所以这里的问题是:服务如何知道该处理哪个 Pod?例如:它如何生成这些 Pod 的终端列表?
这个问题可以用标签来解决,具体分两个步骤:
给所有服务处理的对象 Pod 贴上标签;在服务中使用一个选择器,该选择器定义了所有贴有标签的对象 Pod。下列视图看起来更清晰:
图 17:带有标签的 Pod 和它们的清单文件
我们可以看到 Pod 都贴着标签 “app: sa-frontend”,服务用这个标签找到目标 Pod。
标签
标签提供了一种简单的方法用于管理 Kubernetes 资源。它们有一对键值表示,且可以用于所有资源。按照图 17 中的例子,修改清单文件。
在修改完毕后保存文件,并通过如下命令应用这些变更:
kubectl apply -f sa-frontend-pod.yamlWarning: kubectl apply should be used on resource created by either kubectl create--save-config or kubectl applypod "sa-frontend" configuredkubectl apply -f sa-frontend-pod2.yaml Warning: kubectl apply should be used onresource created by either kubectl create--save-config or kubectl applypod "sa-frontend2" configured
我们看到了一个警告(在应用的时候,而非创建,明白了)。在第二行我们看到部署了 pod “sa-frontend” 和 “sa-frontend2”。我们可以过滤想要查看的 Pod:
kubectl get pod -l app=sa-frontendNAME READY STATUS RESTARTS AGEsa-frontend 1/1 Running 02hsa-frontend2 1/1 Running 02h
验证带有标签的 Pod 的另一种方法是在上述命令中加入标志符 --show-labels,那么结果中会显示每个 Pod 的所有标签。
很好!Pod 已经贴上了标签,我们准备好通过服务找到它们了。让我们定义 LoadBalancer 类型的服务,如图 18 所示。
图 18:用 LoadBalancer 服务平衡负荷
服务的定义
LoadBalancer 服务的 YAML 定义如下所示:
apiVersion: v1kind: Service # 1metadata: name: sa-frontend-lbspec: type: LoadBalancer # 2 ports: - port: 80 # 3 protocol: TCP # 4 targetPort: 80 # 5 selector: # 6 app: sa-frontend # 7
#1 kind:服务;#2 type:指定类型,我们选择 LoadBalancer,因为我们想平衡 Pod 之间的负荷;#3 ports:指定服务获取请求的端口;#4 protocol:定义交流;#5 targetPort:可以将来访的请求转发到这个端口;#6 selector:包含选择 pod 属性的对象;#7 app:sa-frontend 定义了哪个是目标 Pod,只有拥有标签 “app: sa-frontend” 的才是目标 Pod。
通过运行如下命令创建服务:
kubectl create -f service-sa-frontend-lb.yamlservice "sa-frontend-lb" created
可以通过运行如下命令检查的服务的状态:
kubectl get svcNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEsa-frontend-lb LoadBalancer 10.101.244.40 <pending> 80:30708/TCP 7m
External-IP 处于 pending 状态(不用再等了,这个状态不会变的)。这是因为我们使用的是 Minikube。如果我们在 Azure 或 Google 云服务上运行,那么我们可以得到一个公开的 IP,那么全世界都可以访问我们的服务了。
尽管如此,Minikube 也不会置我们于不顾,它提供一个非常有用的本地调试命令,如下所示:
minikube service sa-frontend-lbOpening kubernetes service default/sa-frontend-lb indefault browser...
这可以在浏览器中打开指向该服务的 IP。服务受到请求后,会将请求转发给其中一个 Pod(不用理会是哪个)。通过利用服务作为访问入口,这种抽象可以让我们看到并将多个 Pod 当成一个来交互。
服务的总结
在本节中,我们介绍了给资源贴标签,在服务中使用标签作为选择器,我们还定义并创建了一个 LoadBalancer 的服务。这满足了我们希望伸缩应用程序规模的需求(只需加入新的贴了标签的 Pod),并通过将服务作为访问入口在 Pod 之间做负载均衡。
Kubernetes 实践 —— 部署
Kubernetes 部署可以帮助每一个应用程序的生命都保持相同的一点:那就是变化。此外,只有挂掉的应用程序才会一尘不变,否则,新的需求会源源不断地涌现,更多代码会被开发出来、打包以及部署。这个过程中的每一步都有可能出错。
部署资源可以自动化应用程序从一版本升迁到另一版本的过程,并保证服务不间断,如果有意外发生,它可以让我们迅速回滚到前一个版本。
部署实践
现在我们有两个 Pod 和一个服务开放,而且它们之间有负载均衡(如图 19 所示)。我们提到过现有的 Pod 还远远不够完美。需要分开管理每一个 Pod(创建、更新、删除和监视他们的情况)。快速更新和迅速回滚根本不可能!这样是不行的,部署 Kubernetes 资源可以解决这里的每个问题。
图 19:现状
在继续下面的内容之前,让我们复述下我们的目标,通过概述可以让我们更好的理解部署资源的清单文件的定义。我们想要的是:
映像 rinormaloku/sentiment-analysis-frontend 的两个 Pod;部署期间服务不间断;Pod 贴有标签 app: sa-frontend,所以我们可以通过 sa-frontend-lb 服务找到各个服务。在下一节中,我们可以将这些需求反映到部署的定义中。
部署的定义
如下资源定义的 YAML 文件可以达成以上所有提到的点:
apiVersion: extensions/v1beta1kind: Deployment # 1metadata: name: sa-frontendspec: replicas: 2 # 2 minReadySeconds: 15strategy: type: RollingUpdate # 3 rollingUpdate: maxUnavailable: 1 # 4 maxSurge: 1 # 5 template: # 6 metadata: labels: app: sa-frontend # 7 spec: containers: - image: rinormaloku/sentiment-analysis-frontend imagePullPolicy: Always # 8 name: sa-frontend ports: - containerPort: 80
#1 kind:部署;#2 replicas:是部署 Spec 对象的一个属性,定义了我们想运行多少的 Pod。所以是 2;#3 type:指定从当前版本升迁到下个版本的时候,部署使用的策略。此处的策略 RollingUpdate 可以保证部署期间服务不间断;#4 maxUnavailable:是 RollingUpdate 对象的一个属性,定义了在升级的时候,最大允许停止的 Pod 数量(与希望的状态相比)。对我们的部署来说,我们有 2 个副本,这意味着在一个 Pod 停止后,我们还会有另外一个 Pod 运行,所以可以保证应用程序可访问;#5 maxSurge:是 RollingUpdate 对象的另一个属性,定义了添加到部署的最大 Pod 数量(与希望的状态相比)。对我们的部署来说,这意味着在向新版本迁移的时候,我们可以加一个 Pod,那么我们可以同时拥有个 3 个 Pod;#6 template:指定 Pod 的模板,部署在创建新 Pod 的时候,会用到该模板。很可能这个非常相似的 Pod 会立即吸引你;#7 app: sa-frontend:根据模板创建的 Pod 将被贴上该标签;#8 imagePullPolicy:当设置成 Always 的时候,每一次新部署都会重新获取容器映像。
坦白来说,这一堆的文本让我更糊涂了,所以还是让我们来看个例子:
kubectl apply -f sa-frontend-deployment.yamldeployment "sa-frontend" created
照例让我们确认是否一切如约履行了:
kubectl get podsNAME READY STATUS RESTARTS AGEsa-frontend 1/1 Running 02dsa-frontend-5d5987746c-ml6m4 1/1 Running 01msa-frontend-5d5987746c-mzsgg 1/1 Running 01msa-frontend2 1/1 Running 02d
现在我们有 4 个运行中的 Pod,两个是由部署创建的,而另外两个是我们手动创建的。通过 kubectl delete pod <pod-name> 命令删除其中一个手动创建的 Pod。
练习:删除其中一个部署创建的 Pod,看看结果怎样。在阅读如下的解释前,请先想想原因。
解释:删除一个 Pod 后,部署注意到当前的状态(只有 1 个 Pod 在运行)与希望的状态(2 个 Pod 处于运行状态),所以它会再启动一个 Pod。
那么,除了保持希望的状态外,使用部署还有什么好处?让我们先来看看好处。
好处 1:采用零停机时间部署 (Zero-downtime)
产品经理带着新的需求来找我们,说客户想要在前端加一个绿色的按钮。开发者写好了代码后,只需提供给我们一样必须的东西,容器映像 rinormaloku/sentiment-analysis-frontend:green。然后就该我们了,我们需要采用零停机时间部署,这项工作很难吗?让我们试试看!
编辑 deploy-frontend-pods.yaml 文件,将容器映像改为新的映像:rinormaloku/sentiment-analysis-frontend:green。保存变更,并运行如下命令:
kubectl apply -f deploy-frontend-green-pods.yaml --recorddeployment "sa-frontend" configured
让我们通过如下命令检查下上线的状态:
kubectl rollout status deployment sa-frontendWaiting for rollout to finish: 1 old replicas are pending termination...Waiting for rollout to finish: 1 old replicas are pending termination...Waiting for rollout to finish: 1 old replicas are pending termination...Waiting for rollout to finish: 1 old replicas are pending termination...Waiting for rollout to finish: 1 old replicas are pending termination...Waiting for rollout to finish: 1of2 updated replicas are available...deployment "sa-frontend" successfully rolled out
从部署上看来,上线已经成功。在这个过程中副本被逐个替换。意味着应用程序始终在线。在继续下面的内容前,先让我们来确认一下更新确实有效。
确认部署
让我们在浏览器中确认更新的结果。运行我们之前用到过的命令 minikube service sa-frontend-lb,它会打开浏览器。我们可以看到按钮 SEND 已更新了。
图 20:绿色按钮
“RollingUpdate” 背后的情况
在我们应用了新的部署后,Kubernetes 会将新状态与旧的相比。在我们的例子中,新状态需要两个 rinormaloku/sentiment-analysis-frontend:green 映像的 Pod。这与当前的运行状态不同,所以 Kubernetes 会执行 RollingUpdate。
图 21:RollingUpdate 替换 Pod
这里的 RollingUpdate 会根据我们指定的规格执行,也就是 “maxUnavailable: 1″和 “maxSurge: 1″。这意味着部署需要终止一个 Pod,并且仅可以运行一个新的 Pod。这个过程会不断重复,一直到所有的 Pod 被替换(如图 21 所示)。
我们继续介绍第二个好处。
声明:出于娱乐的目的,下面的部分我按照小说的形式来书写。
好处 2:回滚到前一个状态
产品经理跑进办公室说,他遇到一个大麻烦!产品经理大喊道:“产品环境中的应用程序有一个很关键的 bug!!需要马上回滚到前一个版本”。你冷静地看着他,眼睛都没有眨一下,就转向了心爱的终端,然后开始敲:
kubectl rollout history deployment sa-frontenddeployments "sa-frontend"REVISION CHANGE-CAUSE1 <none> 2 kubectl.exe apply --filename=sa-frontend-deployment-green.yaml --record=true
你看了一眼前一个部署,然后问产品经理:“上个版本很多 bug,那前一个版本运行得很完美吗?” 产品经理吼道:“是啊,你没听见我说嘛?!” 你没理他,你知道该如何处理,于是你开始敲:
kubectl rollout undo deployment sa-frontend --to-revision=1deployment "sa-frontend" rolled back
然后,你轻轻地刷新了页面,之前的修改全都不见了!产品经理瞠目结舌地看着你。你拯救了大家!完
我知道…… 这是个很无聊的故事。在 Kubernetes 出现之前,这个故事挺好的,更加戏剧化,让人高度紧张,而且这种状态持续了很长时间。那段旧时光还是很美好的!
大多数的命令都自带说明,只是有一些细节你需要自己搞清楚。为什么第一个版本中字段 CHANGE-CAUSE 的值为 <none>,而同时第二次改版的时候,CHANGE-CAUSE 的值为 “kubectl.exe apply –filename=sa-frontend-deployment-green.yaml –record=true”。
你应该可以发现这是因为在应用新的映像的时候,我们用到了标志符 --record。
在下一节中,我们将使用之前所有的概念,完成整个架构。
Kubernetes 和其他一切的实战应用
现在我们学习了完成架构的所有必须的资源,因此这一节会非常快。图 22 中灰色的部分是需要做的事情。让我们从底部开始:部署 sa-logic 的部署。
图 22:当前应用程序状态
部署 SA-Logic
在终端中进入资源清单文件所在的目录,然后运行如下命令:
kubectl apply -f sa-logic-deployment.yaml --recorddeployment "sa-logic" created
SA-Logic 的部署会创建三个 Pod(Pod 上运行着我们的 Python 应用)。该命令还会给 Pod 贴上 app: sa-logic 的标签。有了这个标签,我们就能从 SA-Logic 服务中利用选择器来选择这些 Pod。请花点时间打开 sa-logic-deployment.yaml,查看其内容。
这里的概念都是一样的,因此我们可以直接讲解下一个资源:SA-Logic 服务。
SA Logic 服务
首先来解释下为什么需要该服务。我们的 Java 应用(在 SA-WebApp 部署的 Pod 中运行)依赖于 Python 应用提供的情感分析。但现在,与我们在本地运行一切服务时的状况不同,我们并没有一个单一的 Python 应用监听着某个端口,我们只有两个 Pod,如果需要,我们可以有更多的 Pod。
这就是为什么需要 “服务” 为一组提供相同功能的 Pod 提供访问入口。这就是说,我们可以利用 SA-Logic 服务作为所有 SA-Logic Pod 的访问入口。
运行如下命令:
kubectl apply -f service-sa-logic.yamlservice "sa-logic" created
更新后的应用程序状态:现在我们有两个 Pod 在运行(包含 Python 应用程序),并且 SA-Logic 服务提供了访问入口,该访问入口将在 SA-WebApp 的 Pod 中使用。
图 23:更新后的应用程序状态
现在需要部署 SA-WebApp Pod,我们需要用到部署资源。
SA-WebApp 部署
我们已经学过了部署,尽管这个部署会用到更多的特性。打开 sa-web-app-deployment.yaml 文件,会发现以下的新内容:
- image: rinormaloku/sentiment-analysis-web-app imagePullPolicy: Always name: sa-web-app env: - name: SA_LOGIC_API_URLvalue: "http://sa-logic" ports: - containerPort: 8080
我们感兴趣的第一件事就是 env 属性。我们猜测它定义了环境变量 SA_LOGIC_API_URl,值为在 Pod 内的值为 http://sa-logic。但为什么要初始化成 http://sa-logic,sa-logic 究竟是什么?
我们先来介绍下 kube-dns。
KUBE-DNS
Kubernetes 有个特殊的 Pod 叫做 kube-dns。默认情况下,所有 Pod 都用它作为 DNS 服务器。kube-dns 的一个重要属性就是它为每个建立的访问都创建一条 DNS 记录。
这就是说当我们创建 sa-logic 服务时,它会获得一个 IP 地址。它的名字会加入到 kube-dns 中(和它的 IP 地址一起)。这样所有 Pod 都能够把 sa-logic 翻译成 SA-Logic 服务的 IP 地址。
好,现在可以继续了:
SA WebApp 部署(续)
运行以下命令:
kubectl apply -f sa-web-app-deployment.yaml --recorddeployment "sa-web-app" created
完了。剩下的工作就是通过 LoadBalancer 服务将 SA-WebApp Pod 暴露到外部。LoadBalancer 服务提供了 SA-WebApp Pod 的访问入口,这样 React 应用程序就能发送 HTTP 请求了。
SA-WebApp 服务
打开 service-sa-web-app-lb.yaml 文件,可以看到内容还是挺熟悉的。
所以我们可以运行如下命令:
kubectl apply -f service-sa-web-app-lb.yamlservice "sa-web-app-lb" created
这样架构就完成了。但还有一点不完美的地方。在部署 SA-Frontend Pod 之后,容器映像指向了 http://localhost:8080/sentiment 处的 SA-WebApp。但现在我们需要将其更新为 SA-WebApp LoadBalancer 的 IP 地址(其作用是 SA-WebApp Pod 的访问入口)。
修补该不完美是个快速复习一切的绝佳机会(如果能不参照以下的指南独立完成更好)。下面我们开始:
执行下列命令获取 SA-WebApp LoadBalancer 的 IP:minikube service list|-------------|----------------------|-----------------------------|| NAMESPACE | NAME | URL ||-------------|----------------------|-----------------------------|| default | kubernetes | No node port || default | sa-frontend-lb | http://192.168.99.100:30708 || default | sa-logic | No node port || default | sa-web-app-lb | http://192.168.99.100:31691 || kube-system | kube-dns | No node port || kube-system | kubernetes-dashboard | http://192.168.99.100:30000 ||-------------|----------------------|-----------------------------|
在 sa-frontend/src/App.js 中使用 SA-WebApp LoadBalancer 的 IP,如下:analyzeSentence () { fetch (''http://192.168.99.100:31691/sentiment'', { /* shortened for brevity */}) .then (response => response.json ()) .then (data =>this.setState (data)); }
构建静态文件 npm build (需要先切换到 sa-front-end 目录);
构建容器映像:
docker build -f Dockerfile -t $DOCKER_USER_ID/sentiment-analysis-frontend:minikube .
将映像推送到 Docker hub:docker push $DOCKER_USER_ID/sentiment-analysis-frontend:minikube
编辑 sa-frontend-deployment.yaml 并使用新的映像;执行 kubectl apply -f sa-frontend-deployment.yaml 命令。刷新浏览器(如果你关闭了浏览器,则执行 minikube service sa-frontend-lb)。敲个句子试试看!
全文总结
Kubernetes 对团队、项目都很有好处,它能简化部署,提供伸缩性、灵活性,可以让我们使用任何底层基础设施。以后我们叫它 Supernetes 吧!
本文中覆盖的内容:
构建 / 打包 / 运行 ReactJS、Java 和 Python 应用程序;Docker 容器,如何利用 Dockerfile 定义并构建容器;容器注册目录,我们采用 Docker Hub 作为容器的代码库;介绍了 Kubernetes 的最重要的内容;Pod;服务;部署;新概念,如零停机时间部署;创建可伸缩的应用;流程上,我们将整个微服务应用程序转成了 Kubernetes 集群。
(三)Kubernetes 快速入门
Kubernetes的核心对象
API Server
提供了RESTful
风格的编程接口,其管理的资源是Kubernetes API
中的端点,用于存储某种API
对象的集合,例如,内置Pod
资源是包含了所有Pod
对象的集合。资源对象是用于表现集群状态的实体,常用于描述应于哪个节点进行容器化应用、需要为其配置什么资源以及应用程序的管理策略等,例如,重启、升级及容错机制。另外,一个对象也是一种“意向记录“——一旦创建,Kubernetes
就需要一直确保对象始终存在。Pod
、Deployment
和Service
等都是最常用的核心对象。
Pod资源对象
Pod
资源对象是一种集合了一到多个应用容器、存储资源、专用IP
及支撑容器运行的其他选项的逻辑组件,如图所示。Pod
代表着Kubernetes
的部署单元及原子运行单元,即一个应用程序的单一运行实例,它通常由共享资源且关系紧密的一个或多个应用容器组成。
Kubernetes
的网络模型要求其各Pod
对象的IP
地址位于同一网络平面内(同一IP
网段),各Pod
之间可使用其IP
地址直接进行通信,无论它们运行于集群内的哪个工作节点上,这些Pod
对象都像运行于同一局域网中的多个主机。不过,
Pod
对象中的各进程均运行于彼此隔离的容器中,并于容器间共享两种关键资源:网络和存储卷。
网络:每个
Pod
对象都会被分配一个集群内专用的IP
地址,也称为Pod IP
,同一Pod
内部的所有容器共享Pod
对象的Network
和UTS
名称空间,其中包括主机名、IP
地址和端口等。因此,这些容器间的通信可以基于本地回环接口lo
进行,而与Pod
外的其他组件的通信则需要使用Service
资源对象的ClusterIP
及相应的端口完成。存储卷:用户可以为
Pod
对象配置一组“存储卷”资源,这些资源可以共享给其内部的所有容器使用,从而完成容器间数据的共享。存储卷还可以确保在容器终止后重启,甚至是被删除后也能确保数据不会丢失,从而保证了生命周期内的Pod
对象数据的持久化存储。
一个
Pod
对象代表某个应用程序的一个特定实例,如果需要扩展应用程序,则意味着为此应用程序同时创建多个Pod
实例,每个实例均代表应用程序的一个运行的“副本”(replica
)。这些副本化的Pod
对象的创建和管理通常由另一组称为“控制器”(Controller
)的对象实现,例如,Deployment
控制器对象。创建
Pod
时,还可以使用Pod Preset
对象为Pod
注入特定的信息,如ConfigMap
、Secret
、存储卷、挂载卷和环境变量等。有了Pod Preset
对象,Pod
模板的创建者就无须为每个模板显示提供所有信息,因此,也就无须事先了解需要配置的每个应用的细节即可完成模板定义。基于期望的目标状态和各节点的资源可用性,
Master
会将Pod
对象调度至某选定的工作节点运行,工作节点于指向的镜像仓库(image register
)下载镜像,并于本地的容器运行时环境中启动容器。Master
会将整个集群的状态保存于etcd
中,并通过API Server
共享给集群的各组件及客户端。
Controller
Kubernetes
集群的设计中,Pod
是有生命周期的对象。通过手动创建或由Controller
(控制器)直接创建的Pod
对象会被“调度器”(Scheduler
)调度至集群中的某工作节点运行,待到容器应用进程运行结束之后正常终止,随后就会被删除。另外,节点资源耗尽或故障也会导致Pod
对象被回收。但
Pod
对象本身并不具有“自愈”功能,若是因为工作节点甚至是调度器自身导致了运行失败,那么它将会被删除;同样,资源耗尽或节点故障导致的回收操作也会删除相关的Pod
对象。在设计上,Kubernetes
使用”控制器“实现对一次性的(用后即弃)Pod
对象的管理操作,例如,要确保部署的应用程序的Pod副本数量严格反映用户期望的数目,以及基于Pod
模板来创建Pod
对象等,从而实现Pod
对象的扩缩容、滚动更新和自愈能力等。例如,某节点发生故障时,相关的控制器会将此节点上运行的Pod
对象重新调度到其他节点进行重建。控制器本身也是一种资源类型,它有着多种实现,其中与工作负载相关的实现如
Replication Controller
、Deployment
、StatefulSet
、DaemonSet
和Jobs
等,也可统称它们为Pod
控制器。
Pod
控制器的定义通常由期望的副本数量、Pod
模板和标签选择器(Label Selector
)组成。Pod
控制器会根据标签选择器对Pod
对象的标签进行匹配检查,所有满足选择条件的Pod
对象都将受控于当前控制器并计入其副本总数,并确保此数目能够精确反映期望的副本数。
Service
尽管
Pod
对象可以拥有IP
地址,但此地址无法确保在Pod
对象重启或被重建后保持不变,这会为集群中的Pod
应用间依赖关系的维护带来麻烦:前端Pod
应用(依赖方)无法基于固定地址持续跟踪后端Pod
应用(被依赖方)。于是,Service
资源被用于在被访问的Pod
对象中添加一个有这固定IP
地址的中间层,客户端向此地址发起访问请求后由相关的Service
资源调度并代理至后端的Pod
对象。换言之,
Service
是“微服务”的一种实现,事实上它是一种抽象:通过规则定义出由多个Pod
对象组合而成的逻辑集合,并附带访问这组Pod
对象的策略。Service
对象挑选、关联Pod
对象的方式同Pod
控制器一样,都是要基于Label Selector
进行定义,其示意图如下
Service IP
是一种虚拟IP
,也称为Cluster IP
,它专用于集群内通信,通常使用专用的地址段,如“10.96.0.0/12”
网络,各Service
对象的IP
地址在此范围内由系统动态分配。集群内的
Pod
对象可直接请求此类的Cluster IP
,例如,图中来自Pod client
的访问请求即可以Service
的Cluster IP
作为目标地址,但集群网络属于私有网络地址,它们仅在集群内部可达。将集群外部的访问流量引入集群内部的常用方法是通过节点网络进行,实现方法是通过工作节点的IP
地址和某端口(NodePort
)接入请求并将其代理至相应的Service
对象的Cluster IP
上的服务端口,而后由Service
对象将请求代理至后端的Pod
对象的Pod IP
及应用程序监听的端口。因此,图中的External Clients
这种来自集群外部的客户端无法直接请求此Service
提供的服务,而是需要事先经由某一个工作节点(如NodeY
)的IP
地址进行,这类请求需要两次转发才能到达目标Pod
对象,因此在通信效率上必然存在负面影响。事实上,
NodePort
会部署于集群中的每一个节点,这就意味着,集群外部的客户端通过任何一个工作节点的IP
地址来访问定义好的NodePort
都可以到达相应的Service
对象。此种场景下,如果存在集群外部的一个负载均衡器,即可将用户请求负载均衡至集群中的部分或者所有节点。这是一种称为“LoadBalancer”
类型的Service
,它通常是由Cloud Provider
自动创建并提供的软件负载均衡器,不过,也可以是有管理员手工配置的诸如F5
一类的硬件设备。简单来说,
Service
主要有三种常用类型:第一种是仅用于集群内部通信的ClusterIP
类型;第二种是接入集群外部请求的NodePort
类型,它工作与每个节点的主机IP
之上;第三种是LoadBalancer
类型,它可以把外部请求负载均衡至多个Node
的主机IP
的NodePort
之上。此三种类型中,每一种都以其前一种为基础才能实现,而且第三种类型中的LoadBalancer
需要协同集群外部的组件才能实现,并且此外部组件并不接受Kubernetes
的管理。
命令式容器应用编排
部署应用Pod
在
Kubernetes
集群上自主运行的Pod
对象在非计划内终止后,其生命周期即告结束,用户需要再次手动创建类似的Pod
对象才能确保其容器中的依然可得。对于Pod
数量众多的场景,尤其是对微服务业务来说,用户必将疲于应付此类需求。Kubernetes
的工作负载(workload
)类型的控制器能够自动确保由其管控的Pod
对象按用户期望的方式运行,因此,Pod的创建和管理大多会通过这种类型的控制器来进行,包括Deployment
、ReplicasSet
、ReplicationController
等。
1)创建Deployment控制器对象
kubectl run
命令可用于命令行直接创建Deploymen
t控制器,并以--image
选项指定的镜像运行Pod
中的容器,--dry-run
选项可以用于命令的测试,但并不真正执行资源对象的创建过程。
# 创建一个名字叫做nginx的deployment控制器,并指定pod镜像使用nginx:1.12版本,并暴露容器内的80端口,并指定副本数量为1个,并先通过--dry-run测试命令是否错误。
[root@k8s-master ~]# kubectl run nginx --image=nginx:1.12 --port=80 --replicas=1 --dry-run=true
[root@k8s-master ~]# kubectl run nginx --image=nginx:1.12 --port=80 --replicas=1
deployment.apps/nginx created
[root@k8s-master ~]# kubectl get pods #查看所有pod对象
NAME READY STATUS RESTARTS AGE
nginx-685cc95cd4-9z4f4 1/1 Running 0 89s
###参数说明:
--image 指定需要使用到的镜像。
--port 指定容器需要暴露的端口。
--replicas 指定目标控制器对象要自动创建Pod对象的副本数量。
2)打印资源对象的相关信息
kubectl get
命令可用来获取各种资源对象的相关信息,它既能显示对象类型特有格式的简要信息,也能按照指定格式为YAML
或JSON
的详细信息,或者使用Go
模板自定义要显示的属性及信息等。
[root@k8s-master ~]# kubectl get deployment #查看所有deployment控制器对象
NAME READY UP-TO-DATE AVAILABLE AGE
nginx 1/1 1 1 66s
###字段说明:
NAME 资源对象名称
READY 期望由当前控制器管理的Pod对象副本数及当前已有的Pod对象副本数
UP-TO-DATE 更新到最新版本定义的Pod对象的副本数量,在控制器的滚动更新模式下,表示已经完成版本更新的Pod对象的副本数量
AVAILABLE 当前处于可用状态的Pod对象的副本数量,即可正常提供服务的副本数。
AGE Pod的存在时长
说明:Deployment资源对象通过ReplicaSet控制器实例完成对Pod对象的控制,而非直接控制。另外,通过控制器创建的Pod对象都会被自动附加一个标签。格式为“run=<Controller_Name>”。
[root@k8s-master ~]# kubectl get deployment -o wide #查看deployment控制器对象的详细信息
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
nginx 1/1 1 1 69m nginx nginx:1.12 run=nginx
[root@k8s-master ~]# kubectl get pods #查看pod资源
NAME READY STATUS RESTARTS AGE
nginx-685cc95cd4-9z4f4 1/1 Running 0 72m
[root@k8s-master ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-685cc95cd4-9z4f4 1/1 Running 0 73m 10.244.1.12 k8s-node1 <none> <none>
###字段说明:
NAME pode资源对象名称
READY pod中容器进程初始化完成并能够正常提供服务时即为就绪状态,此字段用于记录处于就绪状态的容器数量
STATUS pod的当前状态,其值有Pending、Running、Succeeded、Failed和Unknown等其中之一
RESTARTS Pod重启的次数
IP pod的IP地址,通常由网络插件自动分配
NODE pod被分配的节点。
3)访问Pod对象
这里部署的是
pod
是运行的为nginx
程序,所以我们可以访问是否ok
,在kubernetes
集群中的任意一个节点上都可以直接访问Pod
的IP
地址。
[root@k8s-master ~]# kubectl get pods -o wide #查看pod详细信息
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-685cc95cd4-9z4f4 1/1 Running 0 88m 10.244.1.12 k8s-node1 <none> <none>
[root@k8s-master ~]# curl 10.244.1.12 #kubernetes集群的master节点上访问
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
[root@k8s-node2 ~]# curl 10.244.1.12 #kubernetes集群的node节点上访问
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
上面访问是基于一个pod
的情况下,但是,当这个pod
由于某种原因意外挂掉了,或者所在的节点挂掉了,那么deployment
控制器会立即创建一个新的pod
,这时候再去访问这个IP
就访问不到了,而我们不可能每次去到节点上看到IP
再进行访问。测试如下:
[root@k8s-master ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-685cc95cd4-9z4f4 1/1 Running 0 99m 10.244.1.12 k8s-node1 <none> <none>
[root@k8s-master ~]# kubectl delete pods nginx-685cc95cd4-9z4f4 #删除上面的pod
pod "nginx-685cc95cd4-9z4f4" deleted
[root@k8s-master ~]# kubectl get pods -o wide #可以看出,当上面pod刚删除,接着deployment控制器又马上创建了一个新的pod,且这次分配在k8s-node2节点上了。
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-685cc95cd4-z5z9p 1/1 Running 0 89s 10.244.2.14 k8s-node2 <none> <none>
[root@k8s-master ~]# curl 10.244.1.12 #访问之前的pod,可以看到已经不能访问
curl: (7) Failed connect to 10.244.1.12:80; 没有到主机的路由
[root@k8s-master ~]#
[root@k8s-master ~]# curl 10.244.2.14 #访问新的pod,可以正常访问
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
部署Service对象
简单来说,一个
Service
对象可视作通过其标签选择器过滤出的一组Pod
对象,并能够为此组Pod
对象监听的套接字提供端口代理及调度服务。就好比上面做的测试,如果没有Service
,那么每次都得去访问pod
对象自己的地址等。且那还只是创建了一个pod
对象,如果是多个。那么该如何是好?故使用Service
解决此问题。
1)创建Service对象(将Service端口代理至Pod端口示例)
"kubectl expose"
命令可用于创建Service
对象以将应用程序“暴露”(expose
)于网络中。
#方法一
[root@k8s-master ~]# kubectl expose deployment nginx --name=nginx-svc --port=80 --target-port=80 --protocol=TCP #为deployment的nginx创建service,取名叫nginx-svc,并通过service的80端口转发至容器的80端口上。
service/nginx-svc exposed
#方法二
[root@k8s-master ~]# kubectl expose deployment/nginx --name=nginx-svc --port=80 --target-port=80 --protocol=TCP
service/nginx-svc exposed
###参数说明:
--name 指定service对象的名称
--port 指定service对象的端口
--target-port 指定pod对象容器的端口
--protocol 指定协议
[root@k8s-master ~]# kubectl get svc #查看service对象。或者kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 25h
nginx-svc ClusterIP 10.109.54.136 <none> 80/TCP 41s
这时候可以在kubernetes
集群上所有节点上直接访问nginx-svc
的cluster-ip
及可访问到名为deployment
控制器下nginx
的pod
。并且,集群中的别的新建的pod
都可以直接访问这个IP
或者这个service
名称即可访问到名为deployment
控制器下nginx
的pod
。示例:
# master节点上通过ServiceIP进行访问
[root@k8s-master ~]# curl 10.109.54.136
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
#新建一个客户端pod进行访问,这里这个客户端使用busybox镜像,且pod副本数量为1个,-it表示进入终端模式。--restart=Never,表示从不重启。
[root@k8s-master ~]# kubectl run client --image=busybox --replicas=1 -it --restart=Never
If you don''t see a command prompt, try pressing enter.
/ # wget -O - -q 10.109.54.136 #访问上面创建的(service)nginx-svc的IP
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
......
/ #
/ # wget -O - -q nginx-svc #访问上面创建的(service)名称nginx-svc
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
2)创建Service对象(将创建的Pod对象使用“NodePort”类型的服务暴露到集群外部)
[root@k8s-master ~]# kubectl run mynginx --image=nginx:1.12 --port=80 --replicas=2 #创建一个deployments控制器并使用nginx镜像作为容器运行的应用。
[root@k8s-master ~]# kubectl get pods #查看创建的pod
NAME READY STATUS RESTARTS AGE
client 1/1 Running 0 15h
mynginx-68676f64-28fm7 1/1 Running 0 24s
mynginx-68676f64-9q8dj 1/1 Running 0 24s
nginx-685cc95cd4-z5z9p 1/1 Running 0 16h
[root@k8s-master ~]#
[root@k8s-master ~]# kubectl expose deployments/mynginx --type="NodePort" --port=80 --name=mynginx-svc #创建一个service对象,并将mynginx创建的pod对象使用NodePort类型暴露到集群外部。
service/mynginx-svc exposed
[root@k8s-master ~]#
[root@k8s-master ~]# kubectl get svc #查看service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 41h
mynginx-svc NodePort 10.111.89.58 <none> 80:30884/TCP 10s
nginx-svc ClusterIP 10.109.54.136 <none> 80/TCP 15h
###字段说明:
PORT(S) 这里的mynginx-svc对象可以看出,集群中各工作节点会捕获发往本地的目标端口为30884的流量,并将其代理至当前service对象的80端口。于是集群外部的用户可以使用当前集群中任一节点的此端口来请求Service对象上的服务。
[root@k8s-master ~]#
[root@k8s-master ~]# netstat -nlutp |grep 30884 #查看master节点上是否有监听上面的30884端口
tcp6 0 0 :::30884 :::* LISTEN 7340/kube-proxy
[root@k8s-node1 ~]#
[root@k8s-node1 ~]# netstat -nlutp |grep 30884 #查看node节点是否有监听上面的30884端口
tcp6 0 0 :::30884 :::* LISTEN 2537/kube-proxy
客户端访问kubernetes
集群的30884
端口
3)Service资源对象的描述
“kuberctl describe services”
命令用于打印Service
对象的详细信息,它通常包括Service
对象的Cluster IP
,关联Pod
对象使用的标签选择器及关联到的Pod
资源的端点等。示例
[root@k8s-master ~]# kubectl describe service mynginx-svc
Name: mynginx-svc
Namespace: default
Labels: run=mynginx
Annotations: <none>
Selector: run=mynginx
Type: NodePort
IP: 10.111.89.58
Port: <unset> 80/TCP
TargetPort: 80/TCP
NodePort: <unset> 30884/TCP
Endpoints: 10.244.1.14:80,10.244.2.15:80
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>
###字段说明:
Selector 当前Service对象使用的标签选择器,用于选择关联的Pod对象
Type 即Service的类型,其值可以是ClusterIP、NodePort和LoadBalancer等其中之一
IP 当前Service对象的ClusterIP
Port 暴露的端口,即当前Service用于接收并响应的端口
TargetPort 容器中的用于暴露的目标端口,由Service Port路由请求至此端口
NodePort 当前Service的NodePort,它是否存在有效值与Type字段中的类型相关
Endpoints 后端端点,即被当前Service的Selector挑中的所有Pod的IP及其端口
Session Affinity 是否启用会话粘性
External Traffic Policy 外部流量的调度策略
扩容和缩容
所谓的“伸缩(
Scaling
)”就是指改变特定控制器上Pod
副本数量的操作,“扩容(scaling up
)”即为增加副本数量,而“缩容(scaling down
)"则指缩减副本数量。不过,不论是扩容还是缩容,其数量都需要由用户明确给出。
Service
对象内建的负载均衡机制可在其后端副本数量不止一个时自动进行流量分发,它还会自动监控关联到的Pod
的健康状态,以确保将请求流量分发至可用的后端Pod
对象。若某Deployment
控制器管理包含多个Pod
实例,则必要时用户还可以为其使用“滚动更新”机制将其容器镜像升级到新的版本或变更那些支持动态修改的Pod
属性。使用
kubect run
命令创建Deployment
对象时,“--replicas=”
选项能够指定由该对象创建或管理的Pod
对象副本的数量,且其数量支持运行时进行修改,并立即生效。“kubectl scale”
命令就是专用于变动控制器应用规模的命令,它支持对Deployment
资源对象的扩容和缩容操作。
上面示例中创建的Deployment
对象nginx
仅创建了一个Pod
对象,其所能够承载的访问请求数量即受限于这单个Pod
对象的服务容量。请求流量上升到接近或超出其容量之前,可以通过kubernetes
的“扩容机制”来扩招Pod
的副本数量,从而提升其服务容量。
扩容示例
[root@k8s-master ~]# kubectl get pods -l run=nginx #查看标签run=nginx的pod
NAME READY STATUS RESTARTS AGE
nginx-685cc95cd4-z5z9p 1/1 Running 0 17h
[root@k8s-master ~]#
[root@k8s-master ~]# kubectl scale deployments/nginx --replicas=3 #将其扩容到3个
deployment.extensions/nginx scaled
[root@k8s-master ~]#
[root@k8s-master ~]# kubectl get pods -l run=nginx #再次查看
NAME READY STATUS RESTARTS AGE
nginx-685cc95cd4-f2cwb 1/1 Running 0 5s
nginx-685cc95cd4-pz9dk 1/1 Running 0 5s
nginx-685cc95cd4-z5z9p 1/1 Running 0 17h
[root@k8s-master ~]#
[root@k8s-master ~]# kubectl describe deployments/nginx #查看Deployment对象nginx详细信息
Name: nginx
Namespace: default
CreationTimestamp: Thu, 29 Aug 2019 15:29:31 +0800
Labels: run=nginx
Annotations: deployment.kubernetes.io/revision: 1
Selector: run=nginx
Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType: RollingUpdate
...
#由nginx自动创建的pod资源全部拥有同一个标签选择器“run=nginx”,因此,前面创建的Service资源对象nginx-svc的后端端点也已经通过标签选择器自动扩展到了这3个Pod对象相关的端点
[root@k8s-master ~]# kubectl describe service/nginx-svc
Name: nginx-svc
Namespace: default
Labels: run=nginx
Annotations: <none>
Selector: run=nginx
Type: ClusterIP
IP: 10.109.54.136
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 10.244.1.15:80,10.244.2.14:80,10.244.2.16:80
Session Affinity: None
Events: <none>
缩容示例
缩容的方式和扩容相似,只不过是将
Pod
副本的数量调至比原来小的数字即可。例如将nginx
的pod
副本缩减至2个
[root@k8s-master ~]# kubectl scale deployments/nginx --replicas=2
deployment.extensions/nginx scaled
[root@k8s-master ~]#
[root@k8s-master ~]# kubectl get pods -l run=nginx
NAME READY STATUS RESTARTS AGE
nginx-685cc95cd4-pz9dk 1/1 Running 0 10m
nginx-685cc95cd4-z5z9p 1/1 Running 0 17h
删除对象
有一些不再有价值的活动对象可使用
“kubectl delete”
命令予以删除,需要删除Service
对象nginx-svc
时,即可使用下面命令完成:
[root@k8s-master ~]# kubectl get services #查看当前所有的service对象
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 43h
mynginx-svc NodePort 10.111.89.58 <none> 80:30884/TCP 96m
nginx-svc ClusterIP 10.109.54.136 <none> 80/TCP 17h
[root@k8s-master ~]# kubectl delete service nginx-svc #删除service对象nginx-svc
有时候要清空某一类型下的所有对象,只需要将上面的命令对象的名称缓存
“--all”
选项便能实现。例如,删除默认名称空间中所有的Deployment
控制器的命令如下:
[root@k8s-master ~]# kubectl delete deployment --all
deployment.extensions "mynginx" deleted
注意:受控于控制器的Pod
对象在删除后会被重建,删除此类对象需要直接删除其控制器对象。不过,删除控制器时若不想删除其Pod
对象,可在删除命令上使用“--cascade=false“
选项。
虽然直接命令式管理的相关功能强大且适合用于操纵
Kubernetes
资源对象,但其明显的缺点是缺乏操作行为以及待运行对象的可信源。另外,直接命令式管理资源对象存在较大的局限性,它们在设置资源对象属性方面提供的配置能力相当有限,而且还有不少资源并不支持命令操作进行创建,例如,用户无法创建带有多个容器的Pod
对象,也无法为Pod
对象创建存储卷。因此,管理资源对象更有效的方式是基于保存有对象配置信息的配置清单来进行。
Kubernetes Python API快速入门
Kubernetes Python API 快速入门
Kubernetes提供了多种语言的客户端SDK, 其中Python API可以使用python语言来操纵集群,实现管理的自动化,非常方便、功能强大。
- 官方网站,https://github.com/kubernetes-client/python
- 注意:这里介绍的方法可以在kubernetes里面的JupyterHub中运行,pod里没有~/.kube目录,直接使用官网教程的load_kubeconfig方法会失败,这里改用从文件中载入配置参数,可以从网上操作集群。
1、安装
pip install git+https://github.com/kubernetes-client/python.git
或者:
pip install kubernetes
2、初始化
首先引入SDK支持库。然后将 ~/.kube 的config文件的内容复制到本地目录,保存为文件kubeconfig.yaml,然后运行下面的python代码:
from kubernetes import client, config
config.kube_config.load_kube_config(config_file="kubeconfig.yaml")
获得API的CoreV1Api版本对象:
v1 = client.CoreV1Api()
3、列出 namespaces
for ns in v1.list_namespace().items:
print(ns.metadata.name)
结果如下:
blockchain
default
ingress
istio-system
jupyter
ks-dev
kube-public
kube-system
kubeflow-dev
kubeflow013
monitor
rook-ceph-system
4、列出所有的services
print("Listing All services with their info:\n")
ret = v1.list_service_for_all_namespaces(watch=False)
for i in ret.items:
print("%s \t%s \t%s \t%s \t%s \n" % (i.kind, i.metadata.namespace, i.metadata.name, i.spec.cluster_ip, i.spec.ports ))
5、列出所有的pods
print("Listing pods with their IPs:")
ret = v1.list_pod_for_all_namespaces(watch=False)
for i in ret.items:
print("%s\t%s\t%s" % (i.status.pod_ip, i.metadata.namespace, i.metadata.name))
结果如下:
Listing pods with their IPs:
10.244.0.155 default busybox-577868d55b-47pkx
10.244.0.164 default busybox-deployment-6c975f66c6-ndlt2
10.244.0.154 default nfs-server-nfs-server-provisioner-0
10.244.0.117 default nginx-65899c769f-tgthn
10.244.0.145 istio-system istio-citadel-7bdc7775c7-p4ww8
10.244.0.125 istio-system istio-cleanup-old-ca-dkvcx
10.244.0.144 istio-system istio-egressgateway-795fc9b47-plrjf
10.244.0.148 istio-system istio-ingress-84659cf44c-ztgl7
10.244.0.143 istio-system istio-ingressgateway-7d89dbf85f-mgm6h
10.244.0.126 istio-system istio-mixer-post-install-rfgrh
10.244.0.137 istio-system istio-pilot-66f4dd866c-qcntx
10.244.0.146 istio-system istio-policy-76c8896799-88t7b
10.244.0.139 istio-system istio-sidecar-injector-645c89bc64-d8mxc
10.244.0.159 istio-system istio-statsd-prom-bridge-949999c4c-rcpgt
10.244.0.138 istio-system istio-telemetry-6554768879-vqw86
10.244.0.158 istio-system prometheus-86cb6dd77c-dgp7c
10.244.0.141 jupyter hook-image-puller-1530505782-9lp9b
10.244.0.162 jupyter hub-7b46b56bb8-9l7qh
10.244.0.167 jupyter jupyter-supermap
10.244.0.129 jupyter proxy-757b9676bf-wngcd
192.168.199.249 kube-system etcd-supermap
10.244.0.140 kube-system flux-helm-operator-68f9f586f4-f8p2v
192.168.199.249 kube-system kube-apiserver-supermap
192.168.199.249 kube-system kube-controller-manager-supermap
10.244.0.156 kube-system kube-dns-58dd58c6c4-6hx59
192.168.199.249 kube-system kube-flannel-ds-sg9p6
192.168.199.249 kube-system kube-proxy-79l6g
192.168.199.249 kube-system kube-scheduler-supermap
10.244.0.119 kube-system kubernetes-dashboard-7d5dcdb6d9-xknlr
10.244.0.136 kube-system nginx-ingress-controller-67b9bf4c56-64lpc
10.244.0.134 kube-system nginx-ingress-default-backend-d676cbb5f-8q6t8
10.244.0.147 kube-system nvidia-device-plugin-daemonset-gzhvn
10.244.0.128 kube-system tiller-deploy-f44fbbb48-ff6qq
10.244.0.127 kubeflow-dev ambassador-d74c99b6f-28xnf
10.244.0.115 kubeflow-dev ambassador-d74c99b6f-92mkv
10.244.0.132 kubeflow-dev ambassador-d74c99b6f-mvb79
10.244.0.124 kubeflow-dev spartakus-volunteer-7976c7dd5c-rdd6q
10.244.0.130 kubeflow-dev tf-hub-0
10.244.0.135 kubeflow-dev tf-job-dashboard-7b57c549c8-h2sv2
10.244.0.122 kubeflow-dev tf-job-operator-594d8c7ddd-b75jw
10.244.0.116 kubeflow013 ambassador-5bfc88cc87-4njpb
10.244.0.123 kubeflow013 ambassador-5bfc88cc87-4s7jf
10.244.0.161 kubeflow013 ambassador-5bfc88cc87-x7bvz
10.244.0.118 kubeflow013 spartakus-volunteer-7976c7dd5c-btwtw
10.244.0.126 kubeflow013 tf-hub-0
10.244.0.121 kubeflow013 tf-job-dashboard-7b57c549c8-zwq92
10.244.0.125 kubeflow013 tf-job-operator-594d8c7ddd-ddmqn
10.244.0.120 monitor grafana-8698b89767-hd7sv
10.244.0.163 monitor prometheus-alertmanager-6df98765f4-gkhrh
10.244.0.131 monitor prometheus-kube-state-metrics-6584885ccf-2tlh4
192.168.199.249 monitor prometheus-node-exporter-tcqlx
10.244.0.160 monitor prometheus-pushgateway-5495f55cdf-qbf4v
10.244.0.165 monitor prometheus-server-5959898967-snztn
192.168.199.249 rook-ceph-system rook-ceph-agent-s5tjx
10.244.0.142 rook-ceph-system rook-ceph-mgr0-77d9fb65c-skljh
10.244.0.151 rook-ceph-system rook-ceph-mon3-sgqs8
10.244.0.157 rook-ceph-system rook-ceph-mon5-4rftd
10.244.0.153 rook-ceph-system rook-ceph-mon6-vx9ch
10.244.0.149 rook-ceph-system rook-ceph-operator-6c7687c646-l6r2r
10.244.0.133 rook-ceph-system rook-ceph-osd-frf6h
10.244.0.152 rook-ceph-system rook-discover-ptfwp
Kubernetes 学习 4 kubernetes 应用快速入门
一、相关命令
1、kubectl
通过连接 api server 进行各 k8s 对象资源的增删改查,如 pod,service,controller (控制器),我们常用的 pod 控制器 replicaset,deployment,statefulet,daemonset,job,cronjob 等,甚至 node 都是对象。
[root@k8smaster ~]# kubectl --help
kubectl controls the Kubernetes cluster manager.
Find more information at: https://kubernetes.io/docs/reference/kubectl/overview/
Basic Commands (Beginner): #新手用的命令
create #增 Create a resource from a file or from stdin.
expose Take a replication controller, service, deployment or pod and expose it as a new Kubernetes Service
run Run a particular image on the cluster
set Set specific features on objects
Basic Commands (Intermediate): #中级的基础命令
explain Documentation of resources
get #查 Display one or many resources
edit #改 Edit a resource on the server
delete #删 Delete resources by filenames, stdin, resources and names, or by resources and label selector
Deploy Commands: #部署命令
rollout #滚动,回滚 Manage the rollout of a resource
scale #改变应用程序的规模 Set a new size for a Deployment, ReplicaSet, Replication Controller, or Job
autoscale #自动改变,就是创建HPA的 Auto-scale a Deployment, ReplicaSet, or ReplicationController
Cluster Management Commands: #集群管理相关命令
certificate #证书 Modify certificate resources.
cluster-info #集群信息 Display cluster info
top #查看资源使用率 Display Resource (CPU/Memory/Storage) usage.
cordon #标记一个节点不可被调用 Mark node as unschedulable
uncordon #标记一个节点可被调用 Mark node as schedulable
drain #排干模式 Drain node in preparation for maintenance
taint #增加污点,给节点增加污点以后,能容忍该污点的pod才能被调度到该节点,默认master会有很多污点,所以创建的pod默认是不会在master上创建,这样确保了master只运行各系统组件 Update the taints on one or more nodes
Troubleshooting and Debugging Commands: #修复和调试命令
describe #描述一个资源的详细信息 Show details of a specific resource or group of resources
logs #查看日志 Print the logs for a container in a pod
attach #和docker 中的attach相似 Attach to a running container
exec #和docker exec 相似 Execute a command in a container
port-forward #端口转发 Forward one or more local ports to a pod
proxy #代理 Run a proxy to the Kubernetes API server
cp #跨容器复制文件 Copy files and directories to and from containers.
auth #测试认证 Inspect authorization
Advanced Commands: #高级命令
apply #创建,修改 Apply a configuration to a resource by filename or stdin
patch #打补丁 Update field(s) of a resource using strategic merge patch
replace #替换 Replace a resource by filename or stdin
wait #等待 Experimental: Wait for one condition on one or many resources
convert #转换 Convert config files between different API versions
Settings Commands: #设置命令
label #打标签 Update the labels on a resource
annotate #给资源加一个注解 Update the annotations on a resource
completion #用来做命令补全 Output shell completion code for the specified shell (bash or zsh)
Other Commands: #其它命令
alpha Commands for features in alpha
api-resources Print the supported API resources on the server
api-versions Print the supported API versions on the server, in the form of "group/version"
config Modify kubeconfig files
plugin Runs a command-line plugin
version Print the client and server version information
Usage:
kubectl [flags] [options]
Use "kubectl <command> --help" for more information about a given command.
Use "kubectl options" for a list of global command-line options (applies to all commands).
2、查看 kubectl 版本信息或集群信息
[root@k8smaster ~]# kubectl version
Client Version: version.Info{Major:"1", Minor:"11", GitVersion:"v1.11.1", GitCommit:"b1b29978270dc22fecc592ac55d903350454310a", GitTreeState:"clean", BuildDate:"2018-07-17T18:53:20Z", GoVer
sion:"go1.10.3", Compiler:"gc", Platform:"linux/amd64"}Server Version: version.Info{Major:"1", Minor:"11", GitVersion:"v1.11.1", GitCommit:"b1b29978270dc22fecc592ac55d903350454310a", GitTreeState:"clean", BuildDate:"2018-07-17T18:43:26Z", GoVer
sion:"go1.10.3", Compiler:"gc", Platform:"linux/amd64"}
[root@k8smaster ~]# kubectl cluster-info
Kubernetes master is running at https://192.168.10.10:6443
KubeDNS is running at https://192.168.10.10:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use ''kubectl cluster-info dump''.
3、kubectl run 命令
[root@k8smaster ~]# kubectl run --help
Create and run a particular image, possibly replicated.
Creates a deployment or job to manage the created container(s).#基于这两种中的某一种创建容器(也就是pod)
Examples:
# Start a single instance of nginx.
kubectl run nginx --image=nginx #基于nginx镜像启动pod
# Start a single instance of hazelcast and let the container expose port 5701 .
kubectl run hazelcast --image=hazelcast --port=5701
# Start a single instance of hazelcast and set environment variables "DNS_DOMAIN=cluster" and "POD_NAMESPACE=default"
in the container.
kubectl run hazelcast --image=hazelcast --env="DNS_DOMAIN=cluster" --env="POD_NAMESPACE=default"
# Start a single instance of hazelcast and set labels "app=hazelcast" and "env=prod" in the container.
kubectl run hazelcast --image=nginx --labels="app=hazelcast,env=prod"
# Start a replicated instance of nginx.
kubectl run nginx --image=nginx --replicas=5 #启动5个pod
# Dry run. Print the corresponding API objects without creating them.
kubectl run nginx --image=nginx --dry-run #单跑模式
# Start a single instance of nginx, but overload the spec of the deployment with a partial set of values parsed from
JSON.
kubectl run nginx --image=nginx --overrides=''{ "apiVersion": "v1", "spec": { ... } }''
# Start a pod of busybox and keep it in the foreground, don''t restart it if it exits.
kubectl run -i -t busybox --image=busybox --restart=Never #默认容器结束了会自动补上去,加了此命令后就不会再自动补上去
# Start the nginx container using the default command, but use custom arguments (arg1 .. argN) for that command.
kubectl run nginx --image=nginx -- <arg1> <arg2> ... <argN>
# Start the nginx container using a different command and custom arguments.
kubectl run nginx --image=nginx --command -- <cmd> <arg1> ... <argN> #加上自定义的命令
# Start the perl container to compute π to 2000 places and print it out.
kubectl run pi --image=perl --restart=OnFailure -- perl -Mbignum=bpi -wle ''print bpi(2000)''
# Start the cron job to compute π to 2000 places and print it out every 5 minutes.
kubectl run pi --schedule="0/5 * * * ?" --image=perl --restart=OnFailure -- perl -Mbignum=bpi -wle ''print bpi(2000)'' #创建一个定时job
使用 kubectl run 创建一个单跑模式的 nginx 容器
[root@k8smaster ~]# kubectl run nginx-deploy --image=nginx:1.14-alpine --port=80 --replicas=1 --dry-run=true
deployment.apps/nginx-deploy created (dry run) #deployment控制器下所控制的应用程序,叫做nginx-deploy
使用 kubectl run 创建一个 nginx 容器
[root@k8smaster ~]# kubectl run nginx-deploy --image=nginx:1.14-alpine --port=80 --replicas=1
deployment.apps/nginx-deploy created
[root@k8smaster ~]# kubectl get deployment
NAME DESIRED(期望) CURRENT(当前) UP-TO-DATE AVAILABLE(可用) AGE
nginx-deploy 1 1 1 0 23s
过一会儿查看显示已经可用
[root@k8smaster ~]# kubectl get deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx-deploy 1 1 1 1 2m
查看创建的 pod
[root@k8smaster ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deploy-5b595999-vw5vt 1/1 Running 0 3m
[root@k8smaster ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
nginx-deploy-5b595999-vw5vt 1/1 Running 0 4m 10.244.2.2 k8snode2
到节点 2 中查看网桥可用发现启动的相应 pod 是连接在 cni0 网桥上的
[root@k8snode2 ~]# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:0c:29:b3:80:ea brd ff:ff:ff:ff:ff:ff
inet 192.168.10.12/24 brd 192.168.10.255 scope global ens33
valid_lft forever preferred_lft forever
inet6 fe80::df7a:6e6c:357:ba25/64 scope link
valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN
link/ether 02:42:85:22:4d:73 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
4: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN
link/ether 92:d1:5f:6c:71:7b brd ff:ff:ff:ff:ff:ff
inet 10.244.2.0/32 scope global flannel.1
valid_lft forever preferred_lft forever
inet6 fe80::90d1:5fff:fe6c:717b/64 scope link
valid_lft forever preferred_lft forever
5: cni0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP qlen 1000
link/ether 0a:58:0a:f4:02:01 brd ff:ff:ff:ff:ff:ff
inet 10.244.2.1/24 scope global cni0
valid_lft forever preferred_lft forever
inet6 fe80::6429:a3ff:fe46:ac7e/64 scope link
valid_lft forever preferred_lft forever
6: vethadaa4f42@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master cni0 state UP
link/ether 3e:4d:5f:db:62:17 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet6 fe80::3c4d:5fff:fedb:6217/64 scope link
valid_lft forever preferred_lft forever
[root@k8snode2 ~]# docker exec -it 706159bf29fc /bin/sh
/ # ifconfig
eth0 Link encap:Ethernet HWaddr 0A:58:0A:F4:02:02
inet addr:10.244.2.2 Bcast:0.0.0.0 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1450 Metric:1
RX packets:15 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:1206 (1.1 KiB) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
/ #
[root@k8snode2 ~]# curl 10.244.2.2
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
[root@k8snode2 ~]#
4、kubelet delete :使用此命令删除刚刚创建的 nginx 容器,会发现删除后控制器会再次启动一个 pod
[root@k8smaster ~]# kubectl delete pods nginx-deploy-5b595999-vw5vt
pod "nginx-deploy-5b595999-vw5vt" deleted
[root@k8smaster ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
nginx-deploy-5b595999-kbj6j 0/1 ContainerCreating 0 17s <none> k8snode1
[root@k8smaster ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
nginx-deploy-5b595999-kbj6j 1/1 Running 0 2m 10.244.1.2 k8snode1
5、kubelet expose (暴露): 此时会发现 pod 的 ip 已经变了,因此我们需要创建一个固定的 service 来提供固定的访问接口。我们使用 kubelet expose 命令来进行创建。(service 默认只服务于集群的内部 pod 客户端)
[root@k8smaster ~]# kubectl expose deployment(控制器) nginx-deploy(控制器名字) --name=nginx --port=80(service 端口) --target-port=80(pod端口) --protocol=TCP
service/nginx exposed
查看和测试创建后的 service
[root@k8smaster ~]# kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 20h
nginx ClusterIP 10.103.127.92 <none> 80/TCP 17m
[root@k8smaster ~]# kubectl describe service nginx
Name: nginx
Namespace: default
Labels: run=nginx-deploy
Annotations: <none>
Selector: run=nginx-deploy
Type: ClusterIP
IP: 10.103.127.92
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 10.244.1.2:80
Session Affinity: None
Events: <none>
[root@k8smaster ~]# curl 10.103.127.92
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
[root@k8smaster ~]#
删除 pod 然后等自动重建后继续访问原来的 service 发现依然可以访问
[root@k8smaster ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
client 0/1 Error 0 14m 10.244.2.3 k8snode2
nginx-deploy-5b595999-jdbtn 1/1 Running 0 31s 10.244.1.3 k8snode1
[root@k8smaster ~]# kubectl delete pods nginx-deploy-5b595999-jdbtn
pod "nginx-deploy-5b595999-jdbtn" deleted
[root@k8smaster ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
client 0/1 Error 0 14m 10.244.2.3 k8snode2
nginx-deploy-5b595999-d9lv5 1/1 Running 0 27s 10.244.2.4 k8snode2
[root@k8smaster ~]# kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 21h
nginx ClusterIP 10.103.127.92 <none> 80/TCP 42m
[root@k8smaster ~]# curl 10.103.127.92
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
6、关于集群 dns, 所有启动的 pod 的 nameserver 地址都是指向集群中 系统名称空间 中的 dns 的 service 的
[root@k8smaster ~]# kubectl get svc --all-namespaces
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 21h
default nginx ClusterIP 10.103.127.92 <none> 80/TCP 29m
kube-system kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP 21h
[root@k8smaster ~]# kubectl describe svc kube-dns -n kube-system
Name: kube-dns
Namespace: kube-system
Labels: k8s-app=kube-dns
kubernetes.io/cluster-service=true
kubernetes.io/name=KubeDNS
Annotations: prometheus.io/port=9153
prometheus.io/scrape=true
Selector: k8s-app=kube-dns
Type: ClusterIP
IP: 10.96.0.10
Port: dns 53/UDP
TargetPort: 53/UDP
Endpoints: 10.244.0.2:53,10.244.0.3:53
Port: dns-tcp 53/TCP
TargetPort: 53/TCP
Endpoints: 10.244.0.2:53,10.244.0.3:53
Session Affinity: None
Events: <none>
[root@k8smaster ~]# kubectl run client --image=busybox --replicas=1 --replicas=1 -it --restart=Never
If you don''t see a command prompt, try pressing enter.
/ # cat /etc/resolv.conf
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
7、get pod 时查看 label (service 与 pod 之间是通过 label 关联的)
[root@k8smaster ~]# kubectl get pods --show-labels -o wide
NAME READY STATUS RESTARTS AGE IP NODE LABELS
nginx-deploy-5b595999-d9lv5 1/1 Running 0 15m 10.244.2.4 k8snode2 pod-template-hash=16151555,run=nginx-deploy
8、kubectl edit #可以编辑运行的 service,不过当前版本应该只可以查看不支持编辑
[root@k8smaster ~]# kubectl edit svc nginx
Edit cancelled, no changes made.
9、svc 还有负载均衡的功能
[root@k8smaster ~]# kubectl run myapp --image=ikubernetes/myapp:v1 --replicas=2
deployment.apps/myapp created
[root@k8smaster ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-848b5b879b-5hg7h 1/1 Running 0 2m
myapp-848b5b879b-ptqjd 1/1 Running 0 2m
nginx-deploy-5b595999-d9lv5 1/1 Running 0 56m
[root@k8smaster ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
myapp-848b5b879b-5hg7h 1/1 Running 0 3m 10.244.2.5 k8snode2
myapp-848b5b879b-ptqjd 1/1 Running 0 3m 10.244.1.4 k8snode1
nginx-deploy-5b595999-d9lv5 1/1 Running 0 57m 10.244.2.4 k8snode2
^C[root@k8smaster ~]# kubectl get deployment -o wide -w #持续监控
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
myapp 2 2 2 2 4m myapp ikubernetes/myapp:v1 run=myapp
nginx-deploy 1 1 1 1 4h nginx-deploy nginx:1.14-alpine run=nginx-deploy
创建 svc 并查看转发情况
[root@k8smaster ~]# kubectl expose deployment myapp --name=myapp --port=80
service/myapp exposed
[root@k8smaster ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 22h
myapp ClusterIP 10.106.171.207 <none> 80/TCP 12s
nginx ClusterIP 10.103.127.92 <none> 80/TCP 1h
[root@k8smaster ~]# kubectl describe svc myapp
Name: myapp
Namespace: default
Labels: run=myapp
Annotations: <none>
Selector: run=myapp
Type: ClusterIP
IP: 10.106.171.207
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 10.244.1.4:80,10.244.2.5:80
Session Affinity: None
Events: <none>
[root@k8smaster ~]# curl 10.106.171.207/hostname.html
myapp-848b5b879b-ptqjd
[root@k8smaster ~]# curl 10.106.171.207/hostname.html
myapp-848b5b879b-ptqjd
[root@k8smaster ~]# curl 10.106.171.207/hostname.html
myapp-848b5b879b-ptqjd
[root@k8smaster ~]# curl 10.106.171.207/hostname.html
myapp-848b5b879b-ptqjd
[root@k8smaster ~]# curl 10.106.171.207/hostname.html
myapp-848b5b879b-ptqjd
[root@k8smaster ~]# curl 10.106.171.207/hostname.html
myapp-848b5b879b-ptqjd
[root@k8smaster ~]# curl 10.106.171.207/hostname.html
myapp-848b5b879b-5hg7h
[root@k8smaster ~]# curl 10.106.171.207/hostname.html
myapp-848b5b879b-5hg7h
[root@k8smaster ~]# curl 10.106.171.207/hostname.html
myapp-848b5b879b-5hg7h
[root@k8smaster ~]# curl 10.106.171.207/hostname.html
myapp-848b5b879b-5hg7h
[root@k8smaster ~]# curl 10.106.171.207/hostname.html
10、kubectl scale # 动态改变副本数
[root@k8smaster ~]# kubectl scale --replicas=5 deployment myapp
deployment.extensions/myapp scaled
[root@k8smaster ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-848b5b879b-5hg7h 1/1 Running 0 22m
myapp-848b5b879b-6fvr5 1/1 Running 0 30s
myapp-848b5b879b-dpwpj 1/1 Running 0 30s
myapp-848b5b879b-f77xt 1/1 Running 0 30s
myapp-848b5b879b-ptqjd 1/1 Running 0 22m
nginx-deploy-5b595999-d9lv5 1/1 Running 0 1h
[root@k8smaster ~]# while true; do curl 10.106.171.207/hostname.html;sleep 1; done
myapp-848b5b879b-ptqjd
myapp-848b5b879b-5hg7h
myapp-848b5b879b-dpwpj
myapp-848b5b879b-6fvr5
myapp-848b5b879b-dpwpj
myapp-848b5b879b-f77xt
myapp-848b5b879b-dpwpj
myapp-848b5b879b-5hg7h
myapp-848b5b879b-dpwpj
myapp-848b5b879b-f77xt
myapp-848b5b879b-dpwpj
^C
[root@k8smaster ~]# kubectl scale --replicas=3 deployment myapp
deployment.extensions/myapp scaled
[root@k8smaster ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-848b5b879b-5hg7h 1/1 Running 0 25m
myapp-848b5b879b-dpwpj 1/1 Running 0 3m
myapp-848b5b879b-ptqjd 1/1 Running 0 25m
nginx-deploy-5b595999-d9lv5 1/1 Running 0 1h
[root@k8smaster ~]# while true; do curl 10.106.171.207/hostname.html;sleep 1; done
myapp-848b5b879b-ptqjd
myapp-848b5b879b-dpwpj
myapp-848b5b879b-ptqjd
myapp-848b5b879b-5hg7h
myapp-848b5b879b-ptqjd
^C
11、kubelet set image 滚动升级更新
先查看各 pod 以及其镜像,然后滚动更新后发现 pod 名称和镜像都发生了改变
[root@k8smaster ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-848b5b879b-5hg7h 1/1 Running 0 30m
myapp-848b5b879b-dpwpj 1/1 Running 0 8m
myapp-848b5b879b-ptqjd 1/1 Running 0 30m
nginx-deploy-5b595999-d9lv5 1/1 Running 0 1h
[root@k8smaster ~]# kubectl describe myapp-848b5b879b-5hg7h
error: the server doesn''t have a resource type "myapp-848b5b879b-5hg7h"
[root@k8smaster ~]# kubectl describe pod myapp-848b5b879b-5hg7h
Name: myapp-848b5b879b-5hg7h
Namespace: default
Priority: 0
PriorityClassName: <none>
Node: k8snode2/192.168.10.12
Start Time: Wed, 08 May 2019 22:41:52 +0800
Labels: pod-template-hash=4046164356
run=myapp
Annotations: <none>
Status: Running
IP: 10.244.2.5
Controlled By: ReplicaSet/myapp-848b5b879b
Containers:
myapp:
Container ID: docker://54587de57edd701951f1e0492504a17be62c9fa18002f5bfc58b252ed536b029
Image: ikubernetes/myapp:v1
Image ID: docker-pullable://ikubernetes/myapp@sha256:9c3dc30b5219788b2b8a4b065f548b922a34479577befb54b03330999d30d513
Port: <none>
Host Port: <none>
State: Running
Started: Wed, 08 May 2019 22:42:45 +0800
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-jvtl7 (ro)
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
default-token-jvtl7:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-jvtl7
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Pulling 18h kubelet, k8snode2 pulling image "ikubernetes/myapp:v1"
Normal Pulled 18h kubelet, k8snode2 Successfully pulled image "ikubernetes/myapp:v1"
Normal Created 18h kubelet, k8snode2 Created container
Normal Started 18h kubelet, k8snode2 Started container
Normal Scheduled 30m default-scheduler Successfully assigned default/myapp-848b5b879b-5hg7h to k8snode2
[root@k8smaster ~]# kubectl set image deployment myapp myapp=ikubernetes/myapp:v2
deployment.extensions/myapp image updated
[root@k8smaster ~]# kubectl rollout status deployment myapp #查看滚动更新状态
deployment "myapp" successfully rolled out
[root@k8smaster ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-74c94dcb8c-ccqzs 1/1 Running 0 2m
myapp-74c94dcb8c-jmj4p 1/1 Running 0 2m
myapp-74c94dcb8c-lc2n6 1/1 Running 0 2m
nginx-deploy-5b595999-d9lv5 1/1 Running 0 1h
另启动一个 shell 访问镜像,可以看到动态更新效果
[root@k8smaster ~]# while true; do curl 10.106.171.207;sleep 1; done
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
12、kubectl rollout #版本回退(回滚)
[root@k8smaster ~]# curl 10.106.171.207
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
[root@k8smaster ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-74c94dcb8c-8l4n7 1/1 Running 0 11s
myapp-74c94dcb8c-dzlfx 1/1 Running 0 14s
myapp-74c94dcb8c-tsd2s 1/1 Running 0 12s
nginx-deploy-5b595999-d9lv5 1/1 Running 0 1h
[root@k8smaster ~]# kubectl rollout undo deployment myapp #不加镜像版本默认回退到上一个版本
deployment.extensions/myapp
[root@k8smaster ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-74c94dcb8c-8l4n7 0/1 Terminating 0 22s
myapp-74c94dcb8c-dzlfx 1/1 Terminating 0 25s
myapp-74c94dcb8c-tsd2s 0/1 Terminating 0 23s
myapp-848b5b879b-5k4s4 1/1 Running 0 5s
myapp-848b5b879b-bzblz 1/1 Running 0 3s
myapp-848b5b879b-hzbf5 1/1 Running 0 2s
nginx-deploy-5b595999-d9lv5 1/1 Running 0 1h
[root@k8smaster ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-848b5b879b-5k4s4 1/1 Running 0 13s
myapp-848b5b879b-bzblz 1/1 Running 0 11s
myapp-848b5b879b-hzbf5 1/1 Running 0 10s
nginx-deploy-5b595999-d9lv5 1/1 Running 0 1h
[root@k8smaster ~]# curl 10.106.171.207
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
还可以自动扩缩容,不过需要和资源监控配合。
13、可以通过 iptables -vnL 查看 iptables 规则,可以看到 service 是出现在其中的。
14、通过修改 svc 的 type 属性为 NodePort 可以在外部访问到对应的 pod 服务
[root@k8smaster ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 23h
myapp ClusterIP 10.106.171.207 <none> 80/TCP 50m
nginx ClusterIP 10.103.127.92 <none> 80/TCP 2h
[root@k8smaster ~]# kubectl edit svc myapp
service/myapp edited
#打开后内容如下
# Please edit the object below. Lines beginning with a ''#'' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: v1
kind: Service
metadata:
creationTimestamp: 2019-05-09T08:28:47Z
labels:
run: myapp
name: myapp
namespace: default
resourceVersion: "49560"
selfLink: /api/v1/namespaces/default/services/myapp
uid: 776ef2c3-7234-11e9-be24-000c29d142be
spec:
clusterIP: 10.106.171.207
externalTrafficPolicy: Cluster
ports:
- nodePort: 30935
port: 80
protocol: TCP
targetPort: 80
selector:
run: myapp
sessionAffinity: None
type: NodePort #此处由ClusterIP改为NodePort
status:
loadBalancer: {}
[root@k8smaster ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 23h
myapp NodePort 10.106.171.207 <none> 80:30935/TCP 51m
nginx ClusterIP 10.103.127.92 <none> 80/TCP 2h
[root@k8smaster ~]# curl 192.168.10.10:30935
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Kubernetes 学习 5 kubernetes 资源清单定义入门
一、kubernetes 是有一个 restful 风格的 API,把各种操作对象都一律当做资源来管理。并且可通过标准的 HTTP 请求的方法 GET,PUT,DELETE,POST,等方法来完成操作,不过是通过相应的命令反馈在 kubectl 之上,如 kubectl run,get,edit,...。
二、k8s 常用的资源实例化后我们称之为对象。k8s 相关的核心资源如下。
1、workload (工作负载型资源对象):Pod,ReplicaSet,Deployment,StatefulSet,DaemonSet,Job,Cronjob...
2、Service,Ingress 服务发现和负载均衡有关 ....
3、Volume 配置与存储。 现在的 k8s 版本还支持基于 CSI,容器存储接口来支持各种各样的存储卷。我们还有另外两种特殊类型的存储卷。
a、ConfigMap :用来当配置中心使用的资源
b、Secret:和 ConfigMap 功能相同但是用来保存敏感数据。
c、DownwardAPI:把外部环境中的信息输出给容器
4、集群级的资源
a、Namespace,Node,Role (名称空间级的资源),ClusterRole,RoleBinding,ClusterRoleBinding
5、元数据型资源
a、HPA
b、PodTemplate 用于 pod 控制器创建 pod 时使用的模板。
c、LimitRange 定义资源限制
6、包括但不仅限于上述资源
三、yaml 详解
1、将 pod 信息以 yaml 格式输出
[root@k8smaster ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-848b5b879b-5k4s4 1/1 Running 0 22h
myapp-848b5b879b-bzblz 1/1 Running 0 22h
myapp-848b5b879b-hzbf5 1/1 Running 0 22h
nginx-deploy-5b595999-d9lv5 1/1 Running 0 1d
[root@k8smaster ~]# kubectl get pod myapp-848b5b879b-5k4s4 -o yaml #以yaml格式输出
apiVersion: v1 #定义对象属于k8s哪一个对应的api群组的名称和版本,给定api版本时由两个部分组成,group/version,group如果省略,表示core定义(核心组,最根本的资源)
kind: Pod #定义资源类别。用来指明这是每一种资源用来实例化成一个具体的资源对象时使用。
metadata: #元数据,内部嵌套很多二级字段和三级字段来定义
creationTimestamp: 2019-05-09T09:10:00Z
generateName: myapp-848b5b879b-
labels:
pod-template-hash: "4046164356"
run: myapp
name: myapp-848b5b879b-5k4s4
namespace: default
ownerReferences:
- apiVersion: apps/v1
blockOwnerDeletion: true
controller: true
kind: ReplicaSet
name: myapp-848b5b879b
uid: 8f3f5833-7232-11e9-be24-000c29d142be
resourceVersion: "48605"
selfLink: /api/v1/namespaces/default/pods/myapp-848b5b879b-5k4s4
uid: 3977b5e7-723a-11e9-be24-000c29d142be
spec: #specifications,规格。定义接下来需要创建的资源对象应该具有什么样的特性,应该满足什么样的规范。确保控制器能够被满足。
containers:
- image: ikubernetes/myapp:v1
imagePullPolicy: IfNotPresent
name: myapp
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
name: default-token-jvtl7
readOnly: true
dnsPolicy: ClusterFirst
nodeName: k8snode2
priority: 0
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
serviceAccount: default
serviceAccountName: default
terminationGracePeriodSeconds: 30
tolerations: #容忍度,能容忍哪些污点
- effect: NoExecute
key: node.kubernetes.io/not-ready
operator: Exists
tolerationSeconds: 300
- effect: NoExecute
key: node.kubernetes.io/unreachable
operator: Exists
tolerationSeconds: 300
volumes:
- name: default-token-jvtl7
secret:
defaultMode: 420
secretName: default-token-jvtl7
status: #显示当前资源的当前的状态,只读,由系统维护,而spec由用户定义。如果当前状态和目标状态不一样,k8s就是为了确保每一个资源定义完以后其当前状态无限向目标状态靠近。从而能满足用户期望。
conditions:
- lastProbeTime: null
lastTransitionTime: 2019-05-08T15:36:44Z
status: "True"
type: Initialized
- lastProbeTime: null
lastTransitionTime: 2019-05-08T15:36:46Z
status: "True"
type: Ready
- lastProbeTime: null
lastTransitionTime: null
status: "True"
type: ContainersReady
- lastProbeTime: null
lastTransitionTime: 2019-05-09T09:10:00Z
status: "True"
type: PodScheduled
containerStatuses:
- containerID: docker://0eccbcf513dc608277089bfe2a7b92e1639b1d63ec5d76212a65b30fffa78774
image: ikubernetes/myapp:v1
imageID: docker-pullable://ikubernetes/myapp@sha256:9c3dc30b5219788b2b8a4b065f548b922a34479577befb54b03330999d30d513
lastState: {}
name: myapp
ready: true
restartCount: 0
state:
running:
startedAt: 2019-05-08T15:36:45Z
hostIP: 192.168.10.12
phase: Running
podIP: 10.244.2.14
qosClass: BestEffort
startTime: 2019-05-08T15:36:44Z
2、创建资源的方法
a、apiserver 在定义资源时仅接收 json 格式的资源定义,因此,像我们以前使用的 run 来创建 deployment 时,run 命令会自动将给定的命令转成 json 格式。
b、yaml 格式提供配置清单,apiserver 可自动将其转为 json,而后再提交;
3、大部分资源的配置清单都由五个组成:
a、apiVersion(group/version):用来指明我们要创建的资源属于哪个资源群组 及版本,k8s 把整个 api-server 所支持的 api 有多少种分组来进行管理。分了组后,某一组中的改变我们只需要改变一个组就行了,其它组不受影响可以继续使用,另外,还有一个功能,可以让一个组加版本号以后同一个群组不同版本还能够并存。pod 是最核心资源,所以其属于核心群组 v1,控制器 deployment 等属于应用程序管理的核心资源,属于 apps/v1。我们集群一般会有三个版本,阿尔法(内测版),贝塔(公测版),stable(稳定版)。
[root@k8smaster ~]# kubectl api-versions
admissionregistration.k8s.io/v1beta1
apiextensions.k8s.io/v1beta1
apiregistration.k8s.io/v1
apiregistration.k8s.io/v1beta1
apps/v1
apps/v1beta1
apps/v1beta2
authentication.k8s.io/v1
authentication.k8s.io/v1beta1
authorization.k8s.io/v1
authorization.k8s.io/v1beta1
autoscaling/v1
autoscaling/v2beta1
batch/v1
batch/v1beta1
certificates.k8s.io/v1beta1
events.k8s.io/v1beta1
extensions/v1beta1
networking.k8s.io/v1
policy/v1beta1
rbac.authorization.k8s.io/v1
rbac.authorization.k8s.io/v1beta1
scheduling.k8s.io/v1beta1
storage.k8s.io/v1
storage.k8s.io/v1beta1
v1
b、kind:资源类别
c、metadata:元数据,主要提供以下几个字段
1)、name,在同一类别中资源 name 是唯一的。实例化出来的这个资源类别下的实例的名称。
2)、namespace
3)、labels,每一种类型的资源都可以有标签,标签就是键值数据
4)、annotations,注释
5)、ownerReferences
6)、resourceVersion
7)、uid,唯一标识,由系统自动生成。
8)、selfLink,自引用,就是在我们 api 中这个资源的格式,比如
selfLink: /api/v1/namespaces/default/pods/myapp-848b5b879b-5k4s4 #在api下v1版本下namespaces为default中名称为
myapp-848b5b879b-5k4s4的pod资源类型
因此每个资源的引用PATH为固定格式 /api/GROUP/VERSION/namespaces/NAMESPACE/TYPE/NAME
...
d、spec:spec 可能会嵌套很多其它的二级或三级字段,不同的资源类型其 spec 中可嵌套的字段不尽相同。其定义用户的期望状态(disired state),资源被创建后状态有可能会不符合条件,因此当前状态会向期望状态靠近。由于有很多字段,因此 k8s 有内建的格式定义可用 explain 查看。
[root@k8smaster ~]# kubectl explain(解释,注解) pod
KIND: Pod
VERSION: v1
DESCRIPTION:
Pod is a collection of containers that can run on a host. This resource is
created by clients and scheduled onto hosts.
FIELDS:
apiVersion <string>#字符串
APIVersion defines the versioned schema of this representation of an
object. Servers should convert recognized schemas to the latest internal
value, and may reject unrecognized values. More info:
https://git.k8s.io/community/contributors/devel/api-conventions.md#resources
kind <string>
Kind is a string value representing the REST resource this object
represents. Servers may infer this from the endpoint the client submits
requests to. Cannot be updated. In CamelCase. More info:
https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds
metadata <Object>#对象,需要嵌套很多二级字段
Standard object''s metadata. More info:
https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata
spec <Object>
Specification of the desired behavior of the pod. More info:
https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status
status <Object>
Most recently observed status of the pod. This data may not be up to date.
Populated by the system. Read-only. More info:
https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status
还可以做二级字段探究
[root@k8smaster ~]# kubectl explain pods.metadata
KIND: Pod
VERSION: v1
RESOURCE: metadata <Object>
DESCRIPTION:
Standard object''s metadata. More info:
https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata
ObjectMeta is metadata that all persisted resources must have, which
includes all objects users must create.
FIELDS:
annotations <map[string]string>
Annotations is an unstructured key value map stored with a resource that
may be set by external tools to store and retrieve arbitrary metadata. They
are not queryable and should be preserved when modifying objects. More
info: http://kubernetes.io/docs/user-guide/annotations
clusterName <string>
The name of the cluster which the object belongs to. This is used to
distinguish resources with same name and namespace in different clusters.
This field is not set anywhere right now and apiserver is going to ignore
it if set in create or update request.
...
e、status:当前状态(current state),本字段由 kubernetes 集群维护,用户不能定义它也不能删除它。
四、定义 yaml 文件
[root@k8smaster manifests]# pwd
/root/manifests
[root@k8smaster manifests]# ls
pod-demo.yaml
[root@k8smaster manifests]# cat pod-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-demo
namespace: default
labels: #也可以在此处写上{app:myapp,tier:frontend}代替下面两行
app: myapp
tier: frontend
spec:
containers: #是一个列表,具体定义方式如下
- name: myapp
image: ikubernetes/myapp:v1
- name: busybox
image: busybox:latest
command: #也可以写成中括号形式,比如可以在此处写上["/bin/sh","-c","sleep 3600"]
- "/bin/sh"
- "-c"
- "echo ${date} >> /usr/share/nginx/html/index.html;sleep 5"
[root@k8smaster manifests]# kubectl create -f pod-demo.yaml
Error from server (AlreadyExists): error when creating "pod-demo.yaml": pods "pod-demo" already exists
[root@k8smaster manifests]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
myapp-848b5b879b-5k4s4 1/1 Running 0 3d 10.244.2.14 k8snode2
myapp-848b5b879b-bzblz 1/1 Running 0 3d 10.244.1.21 k8snode1
myapp-848b5b879b-hzbf5 1/1 Running 0 3d 10.244.1.22 k8snode1
nginx-deploy-5b595999-d9lv5 1/1 Running 0 3d 10.244.2.4 k8snode2
pod-demo 1/2 CrashLoopBackOff 7 17m 10.244.2.15 k8snode2
[root@k8smaster manifests]# kubectl describe pod pod-demo
Name: pod-demo
Namespace: default
Priority: 0
PriorityClassName: <none>
Node: k8snode2/192.168.10.12
Start Time: Thu, 09 May 2019 12:26:59 +0800
Labels: app=myapp
tier=frontend
Annotations: kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"labels":{"app":"myapp","tier":"frontend"},"name":"pod-demo
","namespace":"default"},"spec"...Status: Running
IP: 10.244.2.15
Containers:
myapp:
Container ID: docker://b8e4c51d55ac57796b6f55499d119881ef522bcf43e673440bdf6bfe3cd81aa5
Image: ikubernetes/myapp:v1
Image ID: docker-pullable://ikubernetes/myapp@sha256:9c3dc30b5219788b2b8a4b065f548b922a34479577befb54b03330999d30d513
Port: <none>
Host Port: <none>
State: Running
Started: Thu, 09 May 2019 12:27:00 +0800
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-jvtl7 (ro)
busybox:
Container ID: docker://1d3d2c9ab4768c1d9a9dda875c772e9a3a5a489408ad965b09af4d28ee5d5092
Image: busybox:latest
Image ID: docker-pullable://busybox@sha256:4b6ad3a68d34da29bf7c8ccb5d355ba8b4babcad1f99798204e7abb43e54ee3d
Port: <none>
Host Port: <none>
Command:
/bin/sh
-c
echo ${date} >> /usr/share/nginx/html/index.html;sleep 5
State: Waiting
Reason: CrashLoopBackOff
Last State: Terminated
Reason: Completed
Exit Code: 0
Started: Thu, 09 May 2019 12:44:14 +0800
Finished: Thu, 09 May 2019 12:44:19 +0800
Ready: False
Restart Count: 8
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-jvtl7 (ro)
Conditions:
Type Status
Initialized True
Ready False
ContainersReady False
PodScheduled True
Volumes:
default-token-jvtl7:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-jvtl7
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Pulled 4d kubelet, k8snode2 Container image "ikubernetes/myapp:v1" already present on machine
Normal Created 4d kubelet, k8snode2 Created container
Normal Started 4d kubelet, k8snode2 Started container
Normal Pulling 4d (x4 over 4d) kubelet, k8snode2 pulling image "busybox:latest"
Normal Pulled 4d (x4 over 4d) kubelet, k8snode2 Successfully pulled image "busybox:latest"
Normal Created 4d (x4 over 4d) kubelet, k8snode2 Created container
Normal Started 4d (x4 over 4d) kubelet, k8snode2 Started container
Warning BackOff 4d (x63 over 4d) kubelet, k8snode2 Back-off restarting failed container
Normal Scheduled 17m default-scheduler Successfully assigned default/pod-demo to k8snode2
查看日志
[root@k8smaster manifests]# curl 10.244.2.15
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
[root@k8smaster manifests]# kubectl logs pod-demo myapp
10.244.0.0 - - [09/May/2019:04:49:18 +0000] "GET / HTTP/1.1" 200 65 "-" "curl/7.29.0" "-"
[root@k8smaster manifests]# kubectl logs pod-demo busybox
/bin/sh: can''t create /usr/share/nginx/html/index.html: nonexistent directory
改变容器 busybox 的启动命令后启动成功
[root@k8smaster manifests]# cat pod-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-demo
namespace: default
labels: #也可以在此处写上{app:myapp,tier:frontend}代替下面两行
app: myapp
tier: frontend
spec:
containers: #是一个列表,具体定义方式如下
- name: myapp
image: ikubernetes/myapp:v1
- name: busybox
image: busybox:latest
command: #也可以写成中括号形式,比如可以在此处写上["/bin/sh","-c","sleep 3600"]
- "/bin/sh"
- "-c"
- "sleep 3600"
[root@k8smaster manifests]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-848b5b879b-5k4s4 1/1 Running 0 3d
myapp-848b5b879b-bzblz 1/1 Running 0 3d
myapp-848b5b879b-hzbf5 1/1 Running 0 3d
nginx-deploy-5b595999-d9lv5 1/1 Running 0 3d
pod-demo 2/2 Running 0 1m
进入到容器中
[root@k8smaster manifests]# kubectl exec -it pod-demo -c busybox /bin/sh
/ # ls
bin dev etc home proc root sys tmp usr var
/ #
五、使用 kubectl 管理资源有三种用法
1、命令式用法
2、配置清单式用法 (命令式资源清单)
3、使用另外命令(声明式资源清单),确保资源尽可能的向我们声明的状态改变并随时应用。
今天关于Kubernetes 快速入门和kubernetes快速入门 pdf的讲解已经结束,谢谢您的阅读,如果想了解更多关于(三)Kubernetes 快速入门、Kubernetes Python API快速入门、Kubernetes 学习 4 kubernetes 应用快速入门、Kubernetes 学习 5 kubernetes 资源清单定义入门的相关知识,请在本站搜索。
本文标签: