经过实例快速掌握k8s(Kubernetes)核心概念

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

K8s核心对象:

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

Windows安装环境:

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

容器镜像(Docker Image):

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

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的运行环境。通常有如下几种:docker

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

当用Vagrant管理虚拟机时,能够先用Vagrant命令启动虚拟机,而后敲入vagrant ssh,进入虚拟机,系统显示:shell

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),但也能够凑活着用。命令运行以后,显示:ubuntu

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

这时Nginx已经运行,但尚未任何请求,控制台没有输出。若是名字为“docker-nginx”的容器之前已经被运行,那么你须要删除原来的,再运行上面命令。能够先敲入“docker ps -a”找到全部运行过的容器,再敲入“docker rm 1ec2e3d63537”进行删除,其中“ 1ec2e3d63537”是容器ID.windows

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

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里了。

file

键入“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集群里。 file

运行如下命令“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示意图。

file

图片来源

k8s核心概念之间的关系:

对象间关系:

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

file

图片来源

图中每一个菱形是一个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仍然可用。

对象绑定:

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

file

图片来源

每一个对象都有多个标签(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
相关文章
相关标签/搜索