Docker,K8S以及12要素
Docker
Docker 对进程进行封装隔离,属于操作系统层面的虚拟化技术。
Docker 在容器的基础上,进行了进一步的封装,从文件系统、网络互联到进程隔离等等,极大的简化了容器的创建和维护。使得 Docker 技术比虚拟机技术更为轻便、快捷。
Docker 和传统虚拟化方式的不同之处:
传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;而容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核,而且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便。
K8S
K8S,就是基于容器的集群管理平台,它的全称,是kubernetes。
在现实的生产环境中 Docker 本身是一个相对底层的容器引擎,在有很多服务器的集群中,不太可能单独去管理任务和资源。所以我们需要 Kubernetes 这样的系统来进行任务的编排和调度。
关于pod
Kubernetes 中部署的最小单位是 pod,而不是 Docker 容器。实时上 Kubernetes 是不依赖于 Docker 的,完全可以使用其他的容器引擎在 Kubernetes 管理的集群中替代 Docker。
Kubernetes 引入 Pod 主要基于下面两个目的:
- 可管理性。
有些容器天生就是需要紧密联系,一起工作。Pod 提供了比容器更高层次的抽象,将它们封装到一个部署单元中。Kubernetes 以 Pod 为最小单位进行调度、扩展、共享资源、管理生命周期。 - 通信和资源共享。
Pod 中的所有容器使用同一个网络 namespace,即相同的 IP 地址和 Port 空间。它们可以直接用 localhost 通信。同样的,这些容器可以共享存储,当 Kubernetes 挂载 volume 到 Pod,本质上是将 volume 挂载到 Pod 中的每一个容器。
在与 Docker 结合使用时,一个 pod 中可以包含一个或多个 Docker 容器。但除了有紧密耦合的情况下,通常一个 pod 中只有一个容器,这样方便不同的服务各自独立地扩展。Pod 中的容器会作为一个整体被 Master 调度到一个 Node 上运行。Pods 有两种使用方式:
- 运行单一容器。
one-container-per-Pod 是 K8s 最常见的模型,这种情况下,只是将单个容器简单封装成 Pod。即便是只有一个容器,K8s 管理的也是 Pod 而不是直接管理容器。 - 运行多个容器。
但问题在于:哪些容器应该放到一个 Pod 中?
答案是:这些容器联系必须非常紧密,而且需要直接共享资源。
关于Controller
Kubernetes 通常不会直接创建 Pod,而是通过 Controller 来管理 Pod 的。Controller 中定义了 Pod 的部署特性,比如有几个副本,在什么样的 Node 上运行等。为了满足不同的业务场景,Kubernetes 提供了多种 Controller,包括 Deployment、ReplicaSet、DaemonSet、StatefuleSet、Job 等。
实战
参考官网提供的一个实践方案。结果是把一个 node.js 的简单的 Hello World 应用,在 Kubernetes 上部署成为一个复制应用,将代码变成一个 Docker 镜像,并且在Google Container Engine上运行它。(Kubernetes 是可以运行在许多不同环境的开源项目,无论是笔记本还是高可用多点集群,公有云还是本地环境,无论是虚拟机还是物理机。范例提到的是google的k8s托管环境。)
步骤:
-
登陆google云平台,创建并配置项目,记下配置的
PROJECT_ID
-
创建nodejs项目并起服务
-
创建一个docker容器镜像
先创建dockerfile
// 让搭建的 Docker 镜像基于 Docker 镜像仓库的 Node.js LTS镜像
// 开放 8080 端口,复制我们的 server.js 文件到镜像并启动 Node 服务
FROM node:4.4
EXPOSE 8080
COPY server.js .
CMD node server.js
然后使用docker构建容器并用project_id标记
docker build -t gcr.io/$PROJECT_ID/hello-node:v1 .
(范例文件夹命名为hello-node)
docker run -d -p 8080:8080 --name hello_tutorial gcr.io/$PROJECT_ID/hello-node:v1
通过docker run本地运行镜像试试可否正常访问。
最后推送镜像到google容器仓库(命令行需要先安装Google Cloud SDK)
gcloud docker push gcr.io/$PROJECT_ID/hello-node:v1
如果一切顺利,应该会在控制台中看到容器镜像
-
创建一个集群
集群由一个 master API server 和一组叫做 node 的虚拟机构成。
先选择地区,再通过gcloud container clusters create hello-world
创建一个集群。另外可以通过Google Cloud Console的New container cluster可视化创建一个集群。
最后通过gcloud container clusters get-credentials hello-world
部署容器式应用到 Kubernetes 集群。 -
创建pod
借助kubectl run
命令来创建一个pod
kubectl run hello-node --image=gcr.io/$PROJECT_ID/hello-node:v1 --port=8080
-
允许外部访问
在我们的开发机上,我们可以使用kubectl expose
以及--type="LoadBalancer"
标识需要从外部 IP 访问来公开 pod。
kubectl expose deployment hello-node --type="LoadBalancer"
此命令中使用deployment这个标识指定了我们将使用底层架构来提供负载均衡。*我们开放的是 deployment,而不是直接公开 pod,这将会让所有由 deployment 管理的 pod 负载均衡(这只有一个 pod,我们一会会复制多个)
- 滚动升级你的网站
与往常一样,修复 bug 或者添加功能的应用,部署到生产环境。
首先编辑修改代码。
再构建镜像docker build -t gcr.io/$PROJECT_ID/hello-node:v2 .
上传gcloud docker push gcr.io/$PROJECT_ID/hello-node:v2
借助kubectl set image
命令用新的镜像更新deployment,它会创建新的pod并删除旧的pod
kubectl set image deployment/hello-node hello-node=gcr.io/$PROJECT_ID/hello-node:v2
当然,我们也可以借助 Kubernetes Web UI 图形化管理,用它来部署容器化应用,以及监视和管理你的群集。
12要素
12-Factor 为构建如下的 SaaS(software as a service 软件即服务) 应用提供了方法论:
- 使用标准化流程自动配置,从而使新的开发者花费最少的学习成本加入这个项目。
- 和操作系统之间尽可能的划清界限,在各个系统中提供最大的可移植性。
- 适合部署在现代的云计算平台,从而在服务器和系统管理方面节省资源。
- 将开发环境和生产环境的差异降至最低,并使用持续交付实施敏捷开发。
- 可以在工具、架构和开发流程不发生明显变化的前提下实现扩展。
这套理论适用于任意语言和后端服务(数据库、消息队列、缓存等)开发的应用程序。
-
基准代码(一份基准代码,多份部署)
每个应用只对应一份基准代码,但可以同时存在多份部署。每份部署相当于运行了一个应用的实例。通常会有一个生产环境,一个或多个预发布环境。此外,每个开发人员都会在自己本地环境运行一个应用实例,这些都相当于一份部署。 -
依赖(显式声明依赖关系)
12-Factor规则下的应用程序不会隐式依赖系统级的类库。 它一定通过依赖清单,确切地声明所有依赖项。此外,在运行过程中通过依赖隔离工具来确保程序不会调用系统中存在但清单中未声明的依赖项。这一做法会统一应用到生产和开发环境。 -
配置(在环境中存储配置)
12-Factor推荐将应用的配置存储于环境变量中( env vars, env )。环境变量可以非常方便地在不同的部署间做修改,却不动一行代码;与配置文件不同,不小心把它们签入代码库的概率微乎其微;与一些传统的解决配置问题的机制(比如 Java 的属性配置文件)相比,环境变量与语言和系统无关。 -
后端服务(把后端服务当作附加资源)
12-Factor 应用不会区别对待本地或第三方服务。 对应用程序而言,两种都是附加资源,通过一个 url 或是其他存储在配置中的服务定位/服务证书来获取数据。12-Factor 应用的任意部署,都应该可以在不进行任何代码改动的情况下,将本地 MySQL 数据库换成第三方服务(例如 Amazon RDS)。类似的,本地 SMTP 服务应该也可以和第三方 SMTP 服务(例如 Postmark )互换。上述 2 个例子中,仅需修改配置中的资源地址。
每个不同的后端服务是一份资源,这些资源和它们附属的部署保持松耦合。
部署可以按需加载或卸载资源。例如,如果应用的数据库服务由于硬件问题出现异常,管理员可以从最近的备份中恢复一个数据库,卸载当前的数据库,然后加载新的数据库 – 整个过程都不需要修改代码。 -
构建,发布,运行(严格分离构建和运行)
12-factor 应用严格区分构建,发布,运行这三个步骤。
- 构建阶段 是指将代码仓库转化为可执行包的过程。构建时会使用指定版本的代码,获取和打包依赖项,编译成二进制文件和资源文件。
- 发布阶段 会将构建的结果和当前部署所需配置相结合,并能够立刻在运行环境中投入使用。
- 运行阶段 (或者说“运行时”)是指针对选定的发布版本,在执行环境中启动一系列应用程序进程。
-
进程(以一个或多个无状态进程运行应用)
12-Factor 应用的进程必须无状态且无共享。 任何需要持久化的数据都要存储在后端服务内,比如数据库。 -
端口绑定(通过端口绑定提供服务)
12-Factor 应用完全自我加载而不依赖于任何网络服务器就可以创建一个面向网络的服务。互联网应用通过端口绑定来提供服务 ,并监听发送至该端口的请求。
端口绑定这种方式也意味着一个应用可以成为另外一个应用的后端服务 ,调用方将服务方提供的相应 URL 当作资源存入配置以备将来调用。 -
并发(通过进程模型进行扩展)
进程和进程类型关系
在 12-factor 应用中,进程是一等公民。12-Factor 应用的进程主要借鉴于unix 守护进程模型。
-
易处理(快速启动和优雅终止可最大化健壮性)
12-Factor 应用的进程易处理(disposable)的,意思是说它们可以瞬间开启或停止。 这有利于快速、弹性的伸缩应用,迅速部署变化的代码或配置,稳健的部署应用。
进程应当追求最小启动时间,一旦接收终止信号就会优雅的终止。进程还应当在面对突然死亡时保持健壮,例如底层硬件故障。 -
开发环境与线上环境等价(尽可能的保持开发,预发布,线上环境相同)
12-Factor 应用的开发人员应该反对在不同环境间使用不同的后端服务,即使适配器已经可以几乎消除使用上的差异。这是因为,不同的后端服务意味着会突然出现的不兼容,从而导致测试、预发布都正常的代码在线上出现问题。这些错误会给持续部署带来阻力。从应用程序的生命周期来看,消除这种阻力需要花费很大的代价。
- 缩小时间差异:开发人员可以几小时,甚至几分钟就部署代码。
- 缩小人员差异:开发人员不只要编写代码,更应该密切参与部署过程以及代码在线上的表现。
- 缩小工具差异:尽量保证开发环境以及线上环境的一致性。
-
日志(把日志当作事件流)
12-factor应用本身从不考虑存储自己的输出流。不应该试图去写或者管理日志文件。相反,每一个运行的进程都会直接的标准输出(stdout)事件流。开发环境中,开发人员可以通过这些数据流,实时在终端看到应用的活动。 -
管理进程(后台管理任务当作一次性进程运行)
进程构成是指用来处理应用的常规业务(比如处理 web 请求)的一组进程。
参考
干货满满!10分钟看懂Docker和K8S
12要素
k8s中文社区pod名词解释
k8s基本概念
借助k8s Web UI进行图形化管理