一分钟教你快速部署Kubernetes应用
Kubernetes是最近DevOps世界里最让人激动的技术了。在过去的几年里它吸引了很多人。它瞬间成名的原因是强大的容器技术。
Docker公司推出了伟大的容器产品,让容器成为了技术领域独一无二的焦点。Docker成功推动了容器的广泛使用,然而容器技术的迅猛发展反过来却让其变得有点过时了。不过正是因为Docker,Linux容器的使用才会如此流行,这推动了容器编排引擎的发展。
进入Kubernetes时代——Kubernetes由Google开发,Google的基础架构世界领先,运行多年,支撑着其数十亿的容器的运行,Kubernetes则是凝聚了Google这些年实际经验的结晶。Kubernetes轰动一时,从今年开始,Docker公司支持Kubernetes作为额外的编排引擎选项,和Docker Swarm并列。
从今以后,Kubernetes也将是Docker社区和Docker企业版的一部分。听上去很不错吧?各自领域的最佳方案终归打包在了一起。
概述
Kubernetes,k8s,或称为kube,是一个开源平台,可以将容器的运维操作自动化。它消除了绝大部分已有的手工流程,包括部署,扩展以及容器化应用程序的管理。
使用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的核心理念之一。用户可以自由定义Pod内的容器执行状态。如果因为某种故障该容器停止了运行,Kubernetes会基于预期状态重新创建Pod。
Kubernetes严格确保集群里运行的所有容器总是在预期状态下。这是由Kubernetes Master实现的,它是Kubernetes控制平面(Control Plane)的一部分。用户可以使用kubectl直接和集群交互,通过Kubernetes API设置或者修改预期状态。
Kubernetes对象
根据Kubernetes文档里所述:Kubernetes对象是“意图记录”——一旦用户创建了对象,Kubernetes系统会持续工作保证这个对象的存在。用户通过创建对象来告诉Kubernetes系统自己希望集群里的工作负载是什么样子;这就是集群的预期状态。任意时刻系统里的实体状态是由Kubernetes对象来表示的。Kubernetes对象也是容器接口之上的另一层抽象层。用户可以直接和Kubernetes对象交互,而不用和容器直接交互。基本的Kubernetes对象如下:
- Pod是节点上的最小的部署单元。它是一组必须一起运行的容器。一般来说,但不是必须的,Pod通常包含一个容器。
- Service用来定义一组逻辑上存在关系的Pod以及访问它们的相关策略。
- Volume是Pod里所有容器都能访问的目录。
- Namespace是由物理集群支撑的虚拟集群。
Kubernetes提供了一些控制器(Controller)。这些控制器基于Kubernetes的基础对象构建并提供额外的特性。Kubernetes控制器包括:
- ReplicaSet确保在给定时间运行着特定数量的Pod副本
- Deployment用来将当前状态变更到预期状态
- StatefulSet用来控制部署顺序以及卷的访问等等。
- DaemonSet用来在集群的所有节点或者特定节点运行Pod的拷贝。
- Job用来执行一些任务并且在成功完成工作之后或者在给定时间之后退出。
Kubernetes控制平面
Kubernetes控制平面的工作就是确保集群的当前状态和用户的预期状态一致。要实现这一目标,Kubernetes会自动执行一系列任务——比如,启动或者重启容器,扩展某个给定应用的副本数量,等等。
Kubernetes文档定义如下:Kubernetes控制平面的各个部分,比如Kubernetes Master以及kubelet进程,管控Kubernetes和用户集群的通信。控制平面维护系统里所有Kubernetes对象的记录,并且持续运行控制回路来管理对象的状态。在任意时间,控制平面的控制回路会响应集群的变化,并且让系统里所有对象的实际状态匹配上用户定义的预期状态。Kubernetes控制平面负责维护集群内的预期状态。它记录对象状态并且持续运行控制回路去检查对象的当前状态是否和预期状态匹配。你可以把它看作是管理国家的政府。
Kubernetes Master
作为Kubernetes控制平面的一部分,Kubernetes master的工作是持续维护集群的预期状态。kubectl命令是通过Kubernetes API和集群的Kubernetes master通信的接口。可以看作负责维护法律和秩序的警察机构。
Kubernetes文档定义:“master”指的是管理集群状态的一组进程。通常这些进程都运行在集群里的单个节点上,并且该节点也称为master节点。master也可以被复制用于实现高可用和冗余。Kubernetes Master控制并且协调集群里的所有节点,包括运行在集群里一个或者多个master节点上的三个进程:
- kube-apiserver:整个集群的单点管理点。API server实现了RESTful的接口,用于和工具以及库函数的通信。kubectl命令直接和API server交互。
- kube-controller-manager:通过管理不同类型的控制器来规范集群的状态。
- kube-scheduler:在集群里的可用节点上调度工作负载。
Kubernetes节点
Kubernetes节点是集群里运行工作负载的工作机器(物理的VM或者物理服务器等)。这些节点由Kubernetes master控制,并且通过持续监控来维护应用程序的预期状态。之前它们被称为minion。和master类似,集群里的每个Kubernetes节点运行两个进程:
- kubelet是节点和Kubernetes Master之间的通信接口。
- kube-proxy是网络路由,它将每个节点上通过Kubernetes API定义的服务暴露出去。它还能够执行简单的TCP和UDP的流转发。
投票应用
这里开始尝试在Kubernetes上实际运行一个应用程序。不过首先需要在本地安装并运行Kubernetes。
安装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服务器
$ 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
# 列出所有命名空间里的所有Pod
$ kubectl get pods --all-namespaces
# 列出命名空间里的所有Pod,并提供详细信息
$ kubectl get pods -o wide
# 列出特定的复制控制器
$ kubectl get rc <rc-name>
# 列出带有标签env=production的所有pod
$ 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很酷,很可能就是容器编排的未来。这个技术很赞,值得对容器感兴趣的人花时间学习。Kubernetes是非常强大的容器编排引擎,它设计用于自动化部署,扩展和操作容器,可以用来增强云容器化战略。
好的一面是Kubernetes可以和任何云产品集成,可以是公有云,私有云,混合云或者多云。云供应商,比如AWS和Google,提供了Kubernetes服务,比如Elastic Container Service for Kubernetes(EKS)和Google Kubernetes Engine(GKE)。不好的一面是Kubernetes比Docker自己的容器编排引擎Docker Swarm要复杂的多。