容器技术是微服务技术的核心技术之一,并随着微服务的流行而迅速成为主流。Docker是容器技术的先驱和奠基者,它出现之后迅速占领市场,几乎成了容器的代名词。但它在开始的时候并没有很好地解决容器的集群问题。Kubernetes抓住了这个机遇,以容器编排者(Container Orchestration)的身份出现,对容器集群进行管理和调度,现在已经打败了Docker成为了容器技术事实上的标准。当然K8s内部还是需要Docker的,但它的功能范围被大大压缩了,只是负责底层的容器引擎和镜像(Docker Image)管理,成为了容器体系中不可缺少, 但没有存在感的一部分。而绝大部分的对外接口都是由k8s来负责。

K8s核心对象:

相对于简单易学的Docker来说,k8s系统庞杂而且概念众多,同一个功能有很多不同方法来完成,让你无所适从,学习起来要困难的多。对于普通码农来讲不需要建立完整的生产环境,只需要搭建一个本地开发环境,这时你只需要了解k8s的核心概念就够了,这样可以大大缩短学习时间。k8s的一切都是对象(Object),它的核心概念一共只有4个,Pod,部署(Deployment),服务(Service)和节点(Node)。另外再加上一个容器镜像(Docker Image),这个是Docker引擎的核心。掌握了这五个核心概念,就对容器技术有了基本了解,打下了扎实的基础。

Windows安装环境:

Windows10的Windows 10企业版, 专业版, 和教育版是可以支持直接安装K8s的,但电脑是要支持Hyper-V的, 详见这里。由于我的Windows是家庭版,只能先安装虚拟机(VirtualBox),再在虚拟机上安装k8s。我用的k8s是Minikube,是k8s的简化版。另外还安装了Vagrant(它是管理虚拟机的一个软件)作为界面来管理VirtualBox。

容器镜像(Docker Image):

任何程序都在容器中运行,k8s支持多种容器,其中Docker是最流行的。容器镜像(Docker Image)是一个以文件形式存在的运行环境,它的里面是分层的,每一层都在上一层的基础上不断叠加新的功能。容器镜像是由Dockerfile创建的。Dockerfile是一个文件,里面包含一组已经定义好的Docker命令(与Linux命令比较相似)。当运行Dockerfile时,里面的命令被依次执行,最后生成需要的容器镜像。你再调用Docker命令(Docker run)运行容器镜像来生成Docker容器,完成之后,应用程序就已经在容器里部署好了。这种方式能够保证每次得到的环境都是一样的。容器比虚拟机强的地方在于,它占用系统资源更少,生成时间更短。创建一个容器的耗时一般是秒级的,而虚拟机是分钟级的。容器镜像的创建效率取决于它的大小,一般来讲容器镜像越小,它的生成时间越短。

下面就是一个“nginx”的Dockerfile示例。

FROM alpine:3.2
EXPOSE 80 443
RUN apk add --update nginx && \
rm -rf /var/cache/apk/* && \
mkdir -p /tmp/nginx/client-body
COPY ./nginx.conf /etc/nginx/nginx.conf
VOLUME ["/etc/nginx/sites-enabled", "/etc/nginx/certs", "/etc/nginx/conf.d"]
CMD ["nginx", "-g", "daemon off;"]

任何Dockerfile的第一句总是“FROM 。。。”,就是要创建一个Linux的运行环境。一般有以下几种:

  • FROM ubuntu:18.04: 按照Linux的具体版本来创建镜像,这样的Linux运行环境是比较完整的,镜像的大小是百兆级别的。
  • FROM alpine:latest : alpine是一个 精简了的Linux运行环境,它的大小是十兆级别的。
  • FROM scratch : scratch是最小Linux运行环境,创建非常快,但它的问题是你不能通过shell登录到容器内部,因此我一般不用它。

当用Vagrant管理虚拟机时,可以先用Vagrant命令启动虚拟机,然后敲入vagrant ssh,进入虚拟机,系统显示:

PS E:\app2\kub> vagrant ssh
Last login: Sat Sep 28 06:56:11 2019 from 10.0.2.2

然后键入“docker run --name docker-nginx -p 8001:80 nginx”运行Nginx镜像。"docker-nginx"是容器的名字,“--name”是名字的参数选项。“-p”表示端口映射,把虚拟机的“8001”端口映射到容器的“80”端口(Nginx的缺省端口)。“nginx”是镜像的名字,如果本地没有找到“Nginx”镜像,系统会自动从Docker镜像库里下载Nginx镜像到本地,然后再运行,这个镜像有比较完整的Linux系统,因此文件比较大(100M),但也可以凑活着用。命令运行之后,显示:

vagrant@ubuntu-xenial:~$ docker run --name docker-nginx -p 8001:80 nginx

这时Nginx已经运行,但还没有任何请求,控制台没有输出。如果名字为“docker-nginx”的容器以前已经被运行,那么你需要删除原来的,再运行上面命令。可以先敲入“docker ps -a”找到所有运行过的容器,再敲入“docker rm 1ec2e3d63537”进行删除,其中“ 1ec2e3d63537”是容器ID.

切换到另一个虚拟机窗口,敲入curl localhost:8001,显示:

vagrant@ubuntu-xenial:/usr/bin$ curl localhost:8001
...
<h1>Welcome to nginx!</h1>
...

这时就出现了Nginx的首页,表示Docker容器中的Nginx已经正常运行。

换回原容器显示窗口,这时有了请求,控制台输出Nginx日志。

vagrant@ubuntu-xenial:~$ docker run --name docker-nginx -p 8001:80 nginx
172.17.0.1 - - [28/Sep/2019:07:02:25 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.47.0" "-"

这时已验证Docker镜像是好的,敲入“CTRL-C”退出。

Pod:

Pod是k8是的最基本概念,你可以把它看成是对容器(container)的一个封装,用来管理容器。一个Pod里可以管理有一个或多个容器,但一般是一个。Pod里的所有容器都共享Pod的资源和网络。当一个Pod不能满足用户需求时,你可以把Pod作为复制的最小单元来复制出一个同样的Pod来处理用户请求。Pod支持多种容器,不过一般是用Docker。你可以用单独的Pod配置文件创建Pod, 也可以把Pod的配置信息放在其他的对象(例如Deployment)的配置文件里面,并与其他对象一起创建,后者更为常见。每一个Pod都有一个唯一的IP地址,Pod一旦生成就可以通过IP地址进行访问。但一般不这么做,而是通过服务(Service)去间接地去访问。下面就是Pod的配置文件。它的解释放在后面的Deployment里面。

kind: Pod
apiVersion: v1
metadata:
labels:
app: nginx-app
spec:
containers:
- name: nginx-container
image: nginx:latest
restartPolicy: Never

Pod模板(Pod Templates)

Pod模板是嵌入在其他K8s对象(Object)中的Pod的配置说明,例如Replication Controllers, Jobs, 和DaemonSets. 这时,Pod不是单独创建的,而是由其它对象来创建,其中最常用的是Deployment。

部署(Deployment):

Deployment是比Pod更高一层的对象,它的主要作用是管理Pod集群,它里面可以有一个或多个Pod, 每一个Pod在功能上都是等同的。一般在Deployment里配置多个Pod以实现负载均衡和容错。在配置Deployment时,你需要指定Pod拷贝的个数,Deployment会自动管理它里面的Pod。当某个Pod宕机时,Deployment能自动复制一个新的Pod并替换宕机的Pod,

下面就是Deployment的配置文件(nginx-deployment.yaml)。在正方形灰框内(从template开始)的是嵌入在Deployment里的Pod的设置,灰框上面的是部署(Deployment)的设置。当你运行这个配置文件时,它会创建一个Deployment,同时也会创建嵌入在里面的Pod。这就是为什么我们一般不需要单独的Pod的配置文件,因为已经把它嵌入在了Deployment里了。

键入“kubectl create -f nginx-deployment.yaml”来运行这个部署,显示:

vagrant@ubuntu-xenial:~/dockerimages/kubernetes/nginx$ kubectl create -f nginx-deployment.yaml
deployment.apps/nginx-deployment created

这时部署已经成功,现在就可以访问它了。每个Pod都有自己的k8s集群内部IP地址,我们这时只能在K8s内部用IP地址进行访问。键入下面命令查看Pod地址,里面有两个“Nginx”Pod,因为Deployment里面是两个Pod的集群。

vagrant@ubuntu-xenial:~/nginx$ kubectl get pods -o=custom-columns=NAME:.metadata.name,IP:.status.podIP
NAME IP
hello-minikube-856979d68c-74c65 172.17.0.3
nginx-deployment-77fff558d7-bhbbt 172.17.0.10
nginx-deployment-77fff558d7-v6zqw 172.17.0.9

打开另一个窗口,连入虚拟机,然后键入以下命令“kubectl exec -ti hello-minikube-856979d68c-74c65 -- /bin/sh”登录到k8s集群内部,就能访问Nginx了。这里“hello-minikube-856979d68c-74c65”是"Minikube"Pod的名字。“172.17.0.10”是其中一个Pod的内部IP地址。

vagrant@ubuntu-xenial:~$ kubectl exec -ti hello-minikube-856979d68c-74c65 -- /bin/sh
# curl 172.17.0.10

服务(Service):

Service是最上层的k8s的对象,可以看成我们平常说的微服务。对服务来讲最重要的就是服务注册和发现。在k8s中,Service就是用来实现这个功能的。下面就是Service的配置文件(nginx-service.yaml)。一般来说调用服务需要知道三个东西,IP地址,协议和端口,例如"http://10.0.2.1:80". 但我们不想用IP,而是用名字来寻址,这就需要DNS。DNS在k8s集群内部实现了基于服务名的寻址。下面是Service的配置文件。Service通过“selector”来与Pod进行绑定,这里它把请求转发给标签“app”是“nginx-app”的Pod。“nodePort”给服务创建了一个外部可以访问的端口,这样在虚拟机上就可以直接访问服务,而不必登录到k8s集群里。

运行以下命令“kubectl create -f nginx-service.yaml”创建服务。

vagrant@ubuntu-xenial:~/$ kubectl create -f nginx-service.yaml
service/nginx-service created

服务创建完成之后,调用以下命令显示当前的所有服务, 现在就有了“nginx-service”服务。“80”是服务的内部端口,“30163”是服务的外部端口。

vagrant@ubuntu-xenial:~/$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 35d
nginx-service NodePort 10.109.7.249 <none> 80:30163/TCP 18s

因为已经通过“NodePort”对外开放了端口,现在不必登录到k8s内部,在虚拟机上就可以访问服务了. 你可以键入“localhost”

curl localhost:30163

Service 和Deployment的区别:

Deployment是用来管理集群的,与Pod绑定,但你不能直接访问Deployment。服务(Service)是为了方便用名字(而不是IP地址)访问。但这也只是在集群内部。你可以登录k8s集群内部,然后键入下面命令访问服务,但在虚拟机上(k8s外面)就不行, 这时只能用IP地址。因为DNS只是在k8s内部才起作用。

# curl nginx-service

节点(Node):

Node刚开始接触时容易和Pod搞混,但它相当于虚拟机或物理机,而Pod相当于容器。所有的的Pod或容器都是部署在Node上面。Minikube只支持单Node,但你可以在它里面部署多个Pod。下面是Node示意图。

图片来源

k8s核心概念之间的关系:

对象间关系:

下面是k8s的一个简单结构图:

图片来源

图中每个菱形是一个Node,中间的Node是Master Node,其余三个是Worker Node。Master Node负责管理Worker Node。 Worker Node是真正干活的Node。Master Node里有各种控制器,Deployment就是由控制器来管理的,它在中间的管理Node里,他里面有两个部署,A和B,分别对应服务A和服务B。“服务A”部署在最下面的Node里,它里面只有一个Pod。“服务B”部署在上面的两个Node里,左边的Node只有一个Pod,右边的Node有两个Pod,这是一个有三个Pod的集群。当一个部署里有多个Pod时,一般是把它们部署在不同的Node上,这样即使一个Node宕机,Deployment仍然可用。

对象绑定:

下图是介绍对象之间如何绑定的关系图。

图片来源

每个对象都有多个标签(Label),“app”就是一个用来标识Pod对象的标签。图里有两个Pod,它们的“app”标签的值分别为“A”和“B”,其中Pod “B”是集群,而Pod “A”不是。服务(Service)和部署(Deployment)都通过标签选择器(Label Selector)来绑定与之匹配的Pod。

附录:

你最好是已经安装了k8s和Docker环境,那就可以依次运行本文中的示例。如果你没有环境,新建一个也不难。如果你不愿意创建环境, k8s的官网有一个练习环境,可以直接用来运行命令,详见这里

索引:

  1. Kubernetes
  2. Docker
  3. Windows
  4. Minikube
  5. Kubernetes Basics

通过实例快速掌握k8s(Kubernetes)核心概念的更多相关文章

  1. Kubernetes 核心概念

    什么是Kubernetes? Kubernetes(k8s)是自动化容器操作的开源平台,这些操作包括部署,调度和节点集群间扩展.如果你曾经用过Docker容器技术部署容器,那么可以将Docker看成K ...

  2. 十分钟带你理解Kubernetes核心概念

    什么是Kubernetes? Kubernetes(k8s)是自动化容器操作的开源平台,这些操作包括部署,调度和节点集群间扩展.如果你曾经用过Docker容器技术部署容器,那么可以将Docker看成K ...

  3. Kubernetes核心概念简介

    本文将会简单介绍Kubernetes的核心概念.因为这些定义可以在Kubernetes的文档中找到,所以文章也会避免用大段的枯燥的文字介绍.相反,我们会使用一些图表(其中一些是动画)和示例来解释这些概 ...

  4. 后端技术杂谈11:十分钟理解Kubernetes核心概念

    本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 本文转自 https://github.com/h2pl/Java-Tutorial 喜欢的 ...

  5. 01 . 容器编排简介及Kubernetes核心概念

    Kubernetes简介 Kubernetes是谷歌严格保密十几年的秘密武器-Borg的一个开源版本,是Docker分布式系统解决方案.2014年由Google公司启动. Kubernetes提供了面 ...

  6. [转]十分钟带你理解Kubernetes核心概念

    本文将会简单介绍 Kubernetes的核心概念.因为这些定义可以在Kubernetes的文档中找到,所以文章也会避免用大段的枯燥的文字介绍.相反,我们会使用一些图表(其中一些是动画)和示例来解释这些 ...

  7. 第3 章 : Kubernetes 核心概念

    Kubernetes 核心概念 本文整理自 CNCF 和阿里巴巴联合举办的云原生技术公开课的课时 3:Kubernetes 核心概念.本次课程中,阿里巴巴资深技术专家.CNCF 9个 TCO 之一 李 ...

  8. K8s - Kubernetes重要概念介绍(Cluster、Master、Node、Pod、Controller、Service、Namespace)

    K8s - Kubernetes重要概念介绍(Cluster.Master.Node.Pod.Controller.Service.Namespace)       Kubernetes 是目前发展最 ...

  9. k8s kubernetes 核心笔记 镜像仓库 项目k8s改造(含最新k8s v1.16.2版本)

    k8s kubernetes 核心笔记 镜像仓库 项目k8s改造 2019/10/24 Chenxin 一 基本资料 一 参考: https://kubernetes.io/ 官网 https://k ...

随机推荐

  1. WTM重磅更新,LayuiAdmin and more

    从善如登,从恶如崩.对于一个开发人员来说,那就是做一个好的系统不容易,想搞砸一个系统很简单,删库跑路会还不会么. 对于我们开源框架的作者来说,做一个好的框架就像登山(也许是登天),我们一步一步往上走, ...

  2. Keras(三)backend 兼容 Regressor 回归 Classifier 分类 原理及实例

    backend 兼容 backend,即基于什么来做运算 Keras 可以基于两个Backend,一个是 Theano,一个是 Tensorflow 查看当前backend import keras ...

  3. odoo 恢复数据库前端报错

    Could not get content for…… jQuery is not defined 原因:数据库缓存 解决方法: select id, create_date, store_fname ...

  4. bzoj 2002 弹飞绵羊 lct裸题

    上一次用分块过了, 今天换了一种lct(link-cut tree)的写法. 学lct之前要先学过splay. lct 简单的来说就是 一颗树, 然后每次起作用的都是其中的某一条链. 所以每次如果需要 ...

  5. codeforces 233 D. Table(思维+dp )

    题目链接:http://codeforces.com/contest/233/problem/D 题意:问在n*m的矩阵中满足在每一个n*n的矩阵里画k个点,一共有几种画法. 题解:其实这题挺简单的但 ...

  6. Codeforces Round #385 (Div. 2) C - Hongcow Builds A Nation

    题目链接:http://codeforces.com/contest/745/problem/C 题意:给出n个点m条边,还有k个不能连通的点,问最多能添加几条边. 要知道如果有n个点最多的边是n*( ...

  7. Erlang模块file翻译

    模块摘要     文件接口模块   描述     模块file提供了文件系统的接口.     在具有线程支持的操作系统上,可以让文件操作以其自己的线程执行,从而允许其他Erlang进程与文件操作并行地 ...

  8. Java并发编程(一):进程和线程之由来

    转自:http://www.cnblogs.com/dolphin0520/p/3910667.html 在前面,已经介绍了Java的基础知识,现在我们来讨论一点稍微难一点的问题:Java并发编程.当 ...

  9. MapReduce案例运行及分词

    首先查询进程,发现hadoop并没有启动 如何配置hadoop,参考我的另外一篇博文<Hadoop环境准备> 接下来,启动hadoop start-all.sh 或者 start-dfs. ...

  10. Microsoft Office 365的安装

    一.安装准备 本教程中需要用到的工具包括:最新版的Office离线包,虚拟光驱软件,离线Kms激活工具, 下载地址:百度网盘 链接: https://pan.baidu.com/s/1sQk7zE40 ...