kubernetes in action - Overview

传统的应用都是“monoliths”,意思就是大应用,即全部逻辑和模块都耦合在一块儿的java

这样明显很挺多问题的,好比只能scale up,升级必须总体升级,扩容node

因此咱们就想把大应用,broken down成小,独立的模块或组件,这样组件能够独立的升级,扩容,组件也能够用不一样的语言实现,组件间经过协议通讯,每一个组件就是一个微服务linux

微服务技术能够说是传统组件技术,如之前的COM,Corba,基于docker的演进,对于用户透明硬件,实现语言,组件间经过Restful或RPC交互docker

 

问题在于,你把一个大应用拆成不少小应用,是否是很难维护和部署?shell

好,你在一台物理机上部署这么多的小应用,而且独立升级,那么他们的依赖若是冲突怎么办?centos

而且每一个组件跑的环境可能也不同,你全部机器都须要把这些环境都装上?想一想就要爆炸bash

因此任何设计都有利弊,monoliths应用有他的问题,但拆成微服务也会引入一堆新的问题,网络

之因此如今微服务那么火,固然当年COM和Corba也是红极一时然后沉寂,是由于docker技术的出现,现有docker和相关框架能够比较好的解决这些问题,好比kubernetes架构

在这些框架的基础下,咱们能够作到持续开发,甚至Devops,Noops并发

这里须要理解Devops,不是把ops团队干掉,而后把ops的工做都交给Dev,而是说在框架的支持下,原来的维护和发布已经变的很是简单,那么Dev也能够更高效的去作,没有必要让ops作,而ops也能够解放出来提供更好的基础框架,这是一种良性循环,不然张口闭口Devops只是一种恶性循环。

 

那么容器技术有啥牛逼的,原来的VM为啥不行?关键点就在“轻量”上

由于微服务是须要把大应用拆分红不少小应用,而这些小应用都是混布在机器上,首先考虑的问题就是隔离,

固然若是都用VM,隔离是没问题,可是太浪费资源了,都用VM可能比原来用一个应用消耗的资源大一个量级

因此,container技术,是一种轻量的VM

最大的差别是,每一个VM都会跑一个独立的OS,kernel,而container会共用host上的OS

那么对于VM而言,由于OS都是独立的,因此他的隔离是很直觉的

那么container既然是共享OS,是用什么技术作到隔离的?

linux container主要是用了下面两种技术作到的容器隔离

首先,Linux namespaces,

Linux会默认用一个namespace,你也能够建立更多的namespace,namespace之间下面这些资源命名是隔离的,也就是说这个namespace看不到其余namespace的pid或userid等其余资源

 Mount (mnt)

 Process ID (pid)

 Network (net)

 Inter-process communication (ipc)

 UTS (host name,domain name)

 User ID (user)

再者,是CGroup,Linux kernel feature that limits the resource usage of a process (or a group of processes).

被限制的进程,使用的资源,cpu,memory,能够限制在规定的范围内

Cgroup其实也不完美,好比对于IO,只能限制IOPS,不管是磁盘仍是网络,很难去限制真正的流量;Cpu也没法针对突发流量,使用率在瞬间超限,而后再被限制,这样很容易影响到其余进程,除非明确绑核;

 

容器技术好久以前就有,可是一直到docker技术出现后,才被你们普遍的关注和接受;缘由在于docker是“Portable”的,经过docker image

Docker was the first container system that made containers easily portable across different machines.
It simplified the process of packaging up not only the application but also all its libraries and other dependencies,
even the whole OS file system, into a simple, portable package that can be used to provision the application to any other machine running Docker

docker image把整个执行环境,包含OS file system都package,这样哪怕docker内和宿主机是不一样的os内核都不要紧,好比一个是centos,一个是debian

docker image自己也是从vm image借鉴过来的,但docker image会更轻量

而且docker image一个很优秀的设计是他是分层的,因此若是不少image都用到一个layer,这个layer只须要被下载一次

A big difference between Docker-based container images and VM images is that
container images are composed of layers, which can be shared and reused across multiple images.

因此要理解,docker技术的核心是package技术,而不是隔离,docker的隔离是经过linux内核features,namespaces和cgroup来保证的,docker自己无论隔离的事

因此通俗的讲,docker就是一个打包和管理包的技术,就相似maven,只是他管理的不是一个java jar包,而是一个image

 

以前说过container和VM的差异,那么如今再具体看下docker container和VM的差异,加深理解

从这个图咱们能够看出,

首先,以前说的区别,VM是须要自带OS kernel的,而且VM是彻底独立的;docker共享宿主机的OS,而且须要一个docker进程来管理

再者,对于VM,若是应用A和B须要同一个执行环境,咱们须要把他们放在一个VM中,但这样他们之间是不隔离的;对于docker,A和B须要跑在独立的容器内,可是还要共享执行环境

那么docker是怎么作的,关键就是docker image是分层的,docker能够基于同一层去启动容器;但这里的layer是read-only的,因此若是一个container改变了环境的话,他会增长一个新的layer,把全部的变动放在这个新的layer中

 

下面来讲k8s,

咱们有了docker,容器能够在各个机器上迁来迁去,那么若是我有不少容器,和主机,怎么管理他们,靠手工的迁移和管理确定是不合适的

那么kubernetes就作这个事的,他能够当作cluster的操做系统,提供相似,service discovery, scaling, load-balancing, self-healing, and even leader election等功能

Kubernetes的架构以下,

首先,kubernetes节点分为,master和worker

master,Control plane,包含API server,用于通讯,client和control plane,或多个control plane之间;Scheduler,顾名思义,负责调度应用到各个worker nodes;ETCD,相似zk,存储配置,并保证一致性;Controller Manager,负责集群级别的管理,监控worker nodes,节点failover等

woker node,首先要个Container Runtime,如docker进程来执行容器;Kubelet,用于和master通讯,并管理改woker上的全部容器;Kube-proxy,相似SLB,作服务访问load balance的

下面经过一个例子来看下,用户是如何经过kubernetes来提交应用的,

1. 用户首先要把应用相关的docker image提交到image registry

2. 而后用户须要写,App descriptor,用于描述应用中各个container是如何组织的
这里有个概念是,pods,能够理解成容器分组,在一个pods中,会被要求在一块儿执行,调度的时候也是按照一个总体调用,而且container之间也是不彻底隔离的
因此在descriptor中,须要将container分红pods,而且给出每一个pods的并发数

3. 接着就把应用提交给master,master会将各个pods调度到woker,经过woker上的kubelet,kubelet会让节点上的docker runtime把容器启动起来

4,docker runtime按照以前的步骤,先去image registry下载,而后启动容器便可

 

下面开始action,Docker篇

1. 启动docker

docker run <image> 

docker run <image>:<tag>

例子,执行busybox image,传入参数 echo “hello world”

 

2. 建立docker image

首先,须要有一个要跑在docker中的程序,这里用个js,

const http = require('http');
const os = require('os');
console.log("Kubia server starting...");
var handler = function(request, response) {
  console.log("Received request from " + request.connection.remoteAddress);
  response.writeHead(200);
  response.end("You've hit " + os.hostname() + "\n");
};
var www = http.createServer(handler);
www.listen(8080);

而后,须要写个Dockerfile,

FROM node:7   #基于的image layer,“node” container image, tag 7

ADD app.js /app.js  #把app.js放到容器的root目录

ENTRYPOINT ["node", "app.js"]  #容器启动的时候执行那个命令,这里是“node app.js”

最终调用,docker build建立image,

docker build -t kubia .

这里再经过这个例子看下,image layer的分层,

能够看到,对于dockerfile中每一行命令,都会产生一个layer

You may think that each Dockerfile creates only a single new layer, but that’s not the case. When building an image, a new layer is created for each individual command

in the Dockerfile.

这个时候,咱们能够查看刚刚建立的image,

如今你能够用docker run,启动这个容器,

docker run --name kubia-container -p 8080:8080 -d kubia

--name,容器名字
-p,Port 8080 on the local machine will be mapped to port 8080 inside the container,docker的端口是隔离的,因此你想从外面访问,须要和宿主机的端口匹配上
-d,daemon,后台程序;

容器启动后,能够经过 http://localhost:8080 来访问

 

3. 查看容器

 docker ps   #查看容器基本信息

 docker inspect kubia-container  #查看容器相关的全部信息

 登入到容器内部,

 docker exec -it kubia-container bash 

-i, which makes sure STDIN is kept open. You need this for entering commands into the shell.

-t, which allocates a pseudo terminal (TTY).

这里需注意,由于容器的进程实际上是跑在宿主机的os上,因此容器内核宿主机上均可以看到这个容器进程,可是PID不同,docker内的PID是隔离的

 

4. 中止和删除容器

docker stop kubia-container  #中止的容器,能够用docker ps -a查看到

docker rm kubia-container   #删除容器

 

5. 上传和注册容器image

通过上面的步骤,容器已经能够在local正常使用,可是若是要跨机器使用,须要把image注册到docker hub上

先要给image加tag,由于docker hub只容许用户上传,以用户docker hub id开头的image

docker tag kubia luksa/kubia #若是dockerhub id是luksa

docker push luksa/kubia  #上传

这样你就能够在其余机器上,这样启动这个image

docker run -p 8080:8080 -d luksa/kubia

 

Kubernetes篇

集群版本kubernetes按照比较麻烦,因此通常是用miniKube,先启动miniKube

minikube start

而后,便可以用kubectl来链接kubernetes,kubectl就是一个client,用于链接kubernetes的APIServer

你能够看集群状况,

也能够看到全部节点的状况,

看某一个节点,

kubectl describe node gke-kubia-85f6-node-0rr

如今开始部署应用到kubernetes,

$ kubectl run kubia --image=luksa/kubia --port=8080 --generator=run/v1

replicationcontroller "kubia" created

这里看到启动应用的时候,建立的是一个replicationcontroller,由于应用部署的时候须要多并发,因此须要rc来管理各个应用的replica

部署完后,咱们怎么看部署的应用,
对于kubernetes,应用的部署的粒度是pod,而不是container

A pod is a group of one or more tightly related containers that will always run together on the same worker node and in the same Linux namespace(s).

pod相似逻辑machine,pod内部的container不是彻底隔离,是共用同一个linux namespaces的

container,pod,work node的关系以下,

那么咱们就能够看看pod的状态,

详细的信息,

 

接着,如何把pod所提供的服务暴露给外部用户?这里就须要建立一个service,把rc暴露出来,由于rc管理的pod是动态的,临时的,若是挂了,会拉起新的,但服务的ip不能老变,因此须要一个service作层proxy

kubectl expose rc kubia --type=LoadBalancer --name kubia-http

service "kubia-http" exposed

查看services的状态,

因此整个应用的组件图以下,

 

kubernetes能够动态扩容的,下面能够看到扩容先后的状况

相关文章
相关标签/搜索