Docker公司推出了伟大的容器产品,让容器成为了技术领域独一无二的焦点。Docker成功推动了容器的广泛使用,然而容器技术的迅猛发展反过来却让其变得有点过时了。不过正是因为Docker,Linux容器的使用才会如此流行,这推动了容器编排引擎的发展。
进入Kubernetes时代——Kubernetes由Google开发,Google的基础架构世界领先,运行多年,支撑着其数十亿的容器的运行,Kubernetes则是凝聚了Google这些年实际经验的结晶。Kubernetes轰动一时,从今年开始,Docker公司支持Kubernetes作为额外的编排引擎选项,和Docker Swarm并列。
从今以后,Kubernetes也将是Docker社区和Docker企业版的一部分。听上去很不错吧?各自领域的最佳方案终归打包在了一起。
概述
使用Kubernetes,用户可以将运行容器的主机组放到集群里。Kubernetes帮助用户管理这些集群。这些集群可以跨越公有云,私有云和混合云——谁知道呢,说不定某一天跨越星球大战的宇宙。
Kubernetes由Google的工程师团队开发以及设计。Google很久以来一直就是容器技术的贡献者。Kubernetes不仅是Google容器技术的活招牌,而且也在背后支撑着Google的云服务产品。
Google每周部署超过20亿个容器。这些都是由称为Borg的内部平台支撑的。Borg是Kubernetes的先驱。Google使用Borg多年积累下来的经验教训成为了Kubernetes的理念来源。
Kubernetes简化了部署以及管理容器化应用程序相关的所有事情。Kubernetes将升级,回滚以及已部署服务的健康监控等等工作都自动化了。这让用户可以在事情真的变得很糟糕之前避免有问题版本的升级。
另外,Kubernetes可以基于使用情况动态地对服务进行扩容缩容,确保用户只会在需要的时候运行所需要的实例。和容器一样,Kubernetes允许用户管理集群,做版本控制和复制。
这仅仅是很简要的概览,还有更多关于Kubernetes的知识。
Kubernetes是如何工作的?
和Docker的编排方案Docker Swarm相比,Kubernetes是很复杂的系统。要理解Kubernetes是如何工作的,我们需要先理解其底层的理念和原则。
预期状态(Desired State)
Kubernetes严格确保集群里运行的所有容器总是在预期状态下。这是由Kubernetes Master实现的,它是Kubernetes控制平面(Control Plane)的一部分。用户可以使用kubectl直接和集群交互,通过Kubernetes API设置或者修改预期状态。
Kubernetes对象
Pod是节点上的最小的部署单元。它是一组必须一起运行的容器。一般来说,但不是必须的,Pod通常包含一个容器。
Service用来定义一组逻辑上存在关系的Pod以及访问它们的相关策略。
Volume是Pod里所有容器都能访问的目录。
Namespace是由物理集群支撑的虚拟集群。
Kubernetes提供了一些控制器(Controller)。这些控制器基于Kubernetes的基础对象构建并提供额外的特性。Kubernetes控制器包括:
ReplicaSet确保在给定时间运行着特定数量的Pod副本
Deployment用来将当前状态变更到预期状态
StatefulSet用来控制部署顺序以及卷的访问等等。
DaemonSet用来在集群的所有节点或者特定节点运行Pod的拷贝。
Job用来执行一些任务并且在成功完成工作之后或者在给定时间之后退出。
Kubernetes控制平面
Kubernetes文档定义如下:Kubernetes控制平面的各个部分,比如Kubernetes Master以及kubelet进程,管控Kubernetes和用户集群的通信。控制平面维护系统里所有Kubernetes对象的记录,并且持续运行控制回路来管理对象的状态。在任意时间,控制平面的控制回路会响应集群的变化,并且让系统里所有对象的实际状态匹配上用户定义的预期状态。Kubernetes控制平面负责维护集群内的预期状态。它记录对象状态并且持续运行控制回路去检查对象的当前状态是否和预期状态匹配。你可以把它看作是管理国家的政府。
Kubernetes Master
Kubernetes文档定义:“master”指的是管理集群状态的一组进程。通常这些进程都运行在集群里的单个节点上,并且该节点也称为master节点。master也可以被复制用于实现高可用和冗余。 Kubernetes Master控制并且协调集群里的所有节点,包括运行在集群里一个或者多个master节点上的三个进程:
kube-apiserver:整个集群的单点管理点。API server实现了RESTful的接口,用于和工具以及库函数的通信。kubectl命令直接和API server交互。
kube-controller-manager:通过管理不同类型的控制器来规范集群的状态。
kube-scheduler:在集群里的可用节点上调度工作负载。
Kubernetes节点
kubelet是节点和Kubernetes Master之间的通信接口。
kube-proxy是网络路由,它将每个节点上通过Kubernetes API定义的服务暴露出去。它还能够执行简单的TCP和UDP的流转发。
投票应用
安装Kubernetes
现在,Kubernetes在Docker社区版17.12+里开箱即用。如果你没有安装社区版,可以在https://www.docker.com/community-edition下载。
安装MiniKube
在本地运行Kubernetes,需要安装MiniKube。它会创建一个本地的VM并且运行一个单节点集群。不要在这上面运行生产集群。它最好仅用来做开发和测试。
单节点集群
要运行一个单节点集群,我们仅仅需要运行minikube start命令。然后,一个VM,一个集群和Kubernetes就运行起来了。
$ minikube start
Starting local Kubernetes v1.10.0 cluster...
Starting VM...
Getting VM IP address...
Moving files into cluster...
Setting up certs...
Connecting to cluster...
Setting up kubeconfig...
Starting cluster components...
Kubectl is now configured to use the cluster.
Loading cached images from config file.
运行kubectl version来验证环境搭建成功,同时检查Kubernetes的版本。
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"9", GitVersion:"v1.9.1", GitCommit:"3a1c9449a956b6026f075fa3134ff92f7d55f812", GitTreeState:"clean", BuildDate:"2018-01-04T20:00:41Z", GoVersion:"go1.9.2", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"10", GitVersion:"v1.10.0", GitCommit:"fc32d2f3698e36b93322a3465f63a14e9f0eaead", GitTreeState:"clean", BuildDate:"2018-03-26T16:44:10Z", GoVersion:"go1.9.3", Compiler:"gc", Platform:"linux/amd64"}
投票应用
这是一个基于微服务架构的简单应用,包括5个简单的服务。
Voting-App:应用前端,用Python编写,用户使用它来投票
Redis:内存内数据库,作为实时存储使用
Worker:.Net服务,从Redis里获得投票并存储到Postgres数据库里
DB:PostgreSql数据库,用作数据库。
Result-App:应用前端,用Node.js编写,展示投票结果。
Git clone并且cd到投票应用程序的代码库里。
“k8s-specifications”文件夹里包含该投票应用服务的Kubernetes yaml定义。每个服务有两个yaml文件:一个服务文件和一个部署文件。服务文件定义pod的逻辑组及其策略。下面是投票程序里结果服务的服务文件:
apiVersion: v1
kind: Service
metadata:
name: result
spec:
type: NodePort
ports:
- name: "result-service"
port: 5001
targetPort: 80
nodePort: 31001
selector:
app: result
部署文件用来定义应用程序的预期状态,比如任意时间点应该运行着的副本数量。如下是投票应用的结果部署文件。
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: result
spec:
replicas: 1
template:
metadata:
labels:
app: result
spec:
containers:
- image: dockersamples/examplevotingapp_result:before
name: result
创建服务和部署对象:
$ kubectl create -f k8s-specifications/
deployment "db" created
service "db" created
deployment "redis" created
service "redis" created
deployment "result" created
service "result" created
deployment "vote" created
service "vote" created
deployment "worker" created
已经好了!你的应用已经被成功部署到这个单节点集群里,可以查看运行着的Pod和服务的列表。
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
db-86b99d968f-s5pv7 1/1 Running 0 1m
redis-659469b86b-hrxqs 1/1 Running 0 1m
result-59f4f867b8-cthvc 1/1 Running 0 1m
vote-54f5f76b95-zgwrm 1/1 Running 0 1m
worker-56578c48f8-h7zvs 1/1 Running 0 1m
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
db ClusterIP 10.109.241.59 <none> 5432/TCP 2m
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 23m
redis ClusterIP 10.102.242.148 <none> 6379/TCP 2m
result NodePort 10.106.7.255 <none> 5001:31001/TCP 2m
vote NodePort 10.103.28.96 <none> 5000:31000/TCP 2m
投票应用暴露在
30001端口,结果应用暴露在
31001端口。你可以使用localhost:port来访问应用。还可以使用IP访问,IP可以通过minikube ip命令得到。
Kubernetes命令备忘录
# 启动Minikube服务器
$ minikube start
# 得到Minikube IP
$ minikube ip
版本信息:
$ kubectl version #得到kubectl版本
$ kubectl cluster-info #得到集群信息
创建对象:
$ kubectl create -f ./file.yml
$ kubectl create -f ./file1.yml -f ./file2.yaml
$ kubectl create -f ./dir
$ kubectl create -f http://www.fpaste.org/279276/48569091/raw/
查看并且找到资源:
$ kubectl get services
$ kubectl get pods --all-namespaces
$ kubectl get pods -o wide
$ kubectl get rc <rc-name>
$ kubectl get pods -l env=production
$ kubectl get services --sort-by=.metadata.name
修改以及删除资源:
$ kubectl label pods <pod-name> new-label=awesome
$ kubectl annotate pods <pod-name> icon-url=http://goo.gl/XXBTWq
$ kubectl delete pod pingredis-XXXXX
扩容缩容:
$ kubectl scale --replicas=3 deployment nginx
和运行着的Pod交互:
$ kubectl logs <pod-name>
# 运行tail -f 得到日志输出
$ kubectl logs -f <pod-name>
# 以交互shell运行pod
$ kubectl run -i --tty busybox --image=busybox -- sh
# 连接到运行着的容器里
$ kubectl attach <podname> -i
# 将Pod的端口转发到本地机器
$ kubectl port-forward <podname> <local-and-remote-port>
# 将端口转发到服务
$ kubectl port-forward <servicename> <port>
# 在已有pod里运行命令(仅有1个容器的情况下)
$ kubectl exec <pod-name> -- ls /
# 在已有pod里运行命令(多个容器的情况下)
$ kubectl exec <pod-name> -c <container-name> -- ls /
DNS查找:
$ kubectl exec busybox -- nslookup kubernetes
$ kubectl exec busybox -- nslookup kubernetes.default
$ kubectl exec busybox -- nslookup kubernetes.default.svc.cluster.local
创建并暴露部署:
$ kubectl run nginx --image=nginx:1.9.12
$ kubectl expose deployment nginx --port=80 --type=LoadBalancer
总结
好的一面是Kubernetes可以和任何云产品集成,可以是公有云,私有云,混合云或者多云。云供应商,比如AWS和Google,提供了Kubernetes服务,比如Elastic Container Service for Kubernetes(EKS)和Google Kubernetes Engine(GKE)。不好的一面是Kubernetes比Docker自己的容器编排引擎Docker Swarm要复杂的多。
如果你想系统学习Kubernetes,可以参加我们的培训,3天时间,帮你迅速上手Kubernetes。
Kubernetes项目实战训练将于2018年8月17日在深圳开课,3天时间带你系统掌握Kubernetes 。本次培训包括:Docker介绍、Docker镜像、网络、存储、容器安全;Kubernetes架构、设计理念、常用对象、网络、存储、网络隔离、服务发现与负载均衡;Kubernetes核心组件、Pod、插件、微服务、云原生、Kubernetes Operator、集群灾备、Helm等,点击下方图片查看详情。