• KVM 教程


    1. KVM 教程

    在云的时代, 应用会更多地迁移到云端, 基于云的架构设计和开发模式需要一套全新的理念去承载, 于是云原生思想应运而生, 而针对云原生应用开发的最佳实践原则, 12-Factor 脱颖而出, 同时也带来了新的解读。本次分享将结合 Docker 等技术, 介绍在 Cloud Native 时代下, 如何一一实践 12-Factor 原则。

    1. 云原生

    云原生 (Cloud Native) 是由 Pivotal 的 Matt Stine 在 2013 年提出的一个概念, 是他多年的架构和咨询总结出来的一个思想的集合。

    那怎么去理解云原生应用? 我觉得可以从三个角度来说明, 这和云计算平台的三个层次不谋而合, 如下图:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xzAmBlvZ-1669260326344)(https://hjs-1251193177.cos.ap-shanghai.myqcloud.com/cloud/cloud-native-12-factor-apply-1.webp)]

    • IaaS 看做基础云设施, 用来提供各种基础资源 (Infrastructure)
    • PaaS 作为开发平台, 用来提供各种平台服务 (Platform)
    • SaaS 交付应用或服务, 直面用户, 提供应用价值 (Application)

    云原生应用, 正好契合了云、平台和服务, 一层层建构, 所以我通常就把它理解为面向云 (平台) 来设计我们的应用。网易三拾众筹的架构师陈晓辉还为它起了一个小清新的名字——向云而生, 我觉得非常贴切, 再通俗一点讲, 也可以叫做云平台应用。

    2. 12-Factor

    12-Factor, 是由 Heroku 创始人 Adam Wiggins 首次提出并开源, 并由众多经验丰富的开发者共同完善, 这综合了他们关于 SaaS 应用几乎所有的经验和智慧, 是开发此类应用的理想实践标准。

    12-Factor 全称叫 The Twelve-Factor App, 它定义了一个优雅的互联网应用在设计过程中, 需要遵循的一些基本原则, 和 Cloud-Native 有异曲同工之处。其中文翻译不少, 我觉得 “十二要素” 或 “十二原则” 比较贴切。

    那具体有哪十二原则了, 见下图:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hDzf2PRJ-1669260326345)(https://hjs-1251193177.cos.ap-shanghai.myqcloud.com/cloud/cloud-native-12-factor-apply-2.webp)]

    在接下来的应用和实践当中, 我们会一一实践每条原则。

    注: 虽然 12-Factor 的原文书籍都是发布在其官网上, 但因为网络问题和格式问题, 不是很方便阅读, 我将其转化为了 GitBook 格式, 并架设在网易云基础服务 (蜂巢) 平台上, 同时开源在 GitHub 上, 方便大家阅读和下载:

    • 在线阅读地址:

    http://12.bingohuang.com/zh_cn/index.html

    • GitHub 开源地址:

    https://github.com/bingohuang/12factor-gitbook

    • pdf/epub 下载地址:

    https://github.com/bingohuang/12factor-gitbook/download

    • GitBook 地址:

    https://www.gitbook.com/book/bingohuang/12factor/details

    3. 应用与实践

    既然 12-factor 作为 SaaS 开发的最佳实践原则, 当然脱离不了实践, 接下来我们就来设计一款云原生应用, 并依照 12-factor, 一步步验证和升级我们的应用。从中, 我们将讲解每个 Factor 的要点, 以及如何在我们的应用中实践 Factor。

    3.1. 应用准备

    这是一个面向云平台设计的简单 Web 应用, 它将暴露一个 HTTP REST 风格的接口, 可以实现对 user 的增删改查功能, 将用到以下技术栈:

    1. 基于 Node.js, 用 Node.js 写 Web 应用非常方便, 而且是当今最火的编程平台之一。

    下载安装 Node.js (包含 npm): https://nodejs.org/zh-cn/download/

    注: Node 版本只要 v4.4 以上就够用, 当前最新的稳定版是 v6.9.5, 我本地的版本是 v5.12.0

    1. 基于 Sails, 类似 Rails 框架, 用于快速开发 Node.js 应用: http://sailsjs.com/

    安装 Sails 框架最新版:

    npm install sails -g
    
    • 1
    1. 基于 mongo 3.2 : https://docs.mongodb.org/manual/installation/

    2. 基于 Docker, 非常契合 12-Factor 理念, 作为我们打包、发布、运行的工具。

    安装 Docker: https://docs.docker.com/engine/installation/

    1. 以上环境安装好之后, 就开始初始化我们的应用并运行, 应用的名称就叫: 12factor-app。
    $ sails new 12factor-app
      info: Created a new Sails app `12factor-app`!
    $ cd 12factor-app
    $ sails generate api user
      info: Created a new api!
    $ npm start
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    注: 本文源代码放在 GitHub 上, 请参考文后参考链接

    仅需 4 条命令就搞定了应用的框架代码, 并自动生成了基于 user 的 CRUD 接口, 我们已经将应用启动起来, 可以通过以下方式本地调试接口:

    控制台输出正常, 在浏览器中访问下面链接, 即可看到 Sails 应用的首页: http://localhost:1337

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6uyBJudh-1669260326345)(https://hjs-1251193177.cos.ap-shanghai.myqcloud.com/cloud/cloud-native-12-factor-apply-3.webp)]

    接着, 就可以通过本地 curl 命令或者 http 工具来做接口调试, 这里以常规的增删改查为例:

    1. 增加一个新用户
    $ curl -XPOST http://localhost:1337/user?name=bingo
    {
      "name": "bingo",
      "createdAt": "2017-02-13T06:13:53.791Z",
      "updatedAt": "2017-02-13T06:13:53.791Z",
      "id": 58a41d952f53291200b9e065
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    1. 获取用户列表
    $ curl http://localhost:1337/user
    [
      {
        "name": "bingo",
        "createdAt": "2017-02-13T06:13:53.791Z",
        "updatedAt": "2017-02-13T06:13:53.791Z",
        "id": 58a41d952f53291200b9e065
      }
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    1. 修改一个用户
    curl -XPUT http://localhost:1337/user/58a41d952f53291200b9e065?name=bingohuang
    {
      "name": "bingohuang",
      "createdAt": "2017-02-13T06:13:53.791Z",
      "updatedAt": "2017-02-13T06:14:13.460Z",
      "id": 58a41d952f53291200b9e065
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    1. 删除一个用户
    curl -XDELETE http://localhost:1337/user/58a41d952f53291200b9e065
    
    • 1

    我已经将该应用部署到了网易云基础服务 (蜂巢) 在线平台, 如果您对这个应用感兴趣, 直接将 localhost 替换为 59.111.110.95, 一样可以体验 CRUD 操作, 如下所示, 只要把 yourname 换成您的名字即可(建议在 PC 端操作):

    # 注册你自己
    curl -XPOST http://59.111.110.95:1337/user?name=yourname
    # 查看所有注册过的用户
    curl http://59.111.110.95:1337/user
    # 或者 PC 浏览器直接访问 http://59.111.110.95:1337/user
    
    • 1
    • 2
    • 3
    • 4
    • 5

    接下来开始就让我们开始一一实践 12-Factor 中的每条原则吧, 每个原则中我们将分为Factor 解说Factor 实践两块。

    3.1.1. 基准代码

    Factor 解说:

    12-Factor 应用只有一份基准代码(Codebase), 可以多份部署(deploy)。

    意思就是说一个应用只有一份用来跟踪所有修订版本的代码仓库, 基准代码和应用之间总是保持一一对应的关系, 因为:

    • 一旦有多个基准代码, 就不能称为一个应用, 而是一个分布式系统。分布式系统中的每一个组件都是一个应用, 每一个应用可以分别使用 12-Factor 进行开发。
    • 多个应用共享一份基准代码是有悖于 12-Factor 原则的。解决方案是将共享的代码拆分为独立的类库, 然后使用依赖管理(第二个原则) 策略去加载它们。
    • 多份部署相当于是运行了该应用的多个实例, 比如开发环境一个实例, 测试环境、生产环境都有一个实例。
    • 一个代码仓库, 确保了单一的信任源, 从而保证了更少的配置错误和更强的容错和复原能力。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-awO2vVQz-1669260326345)(https://hjs-1251193177.cos.ap-shanghai.myqcloud.com/cloud/cloud-native-12-factor-apply-4.webp)]

    Factor 实践:

    使用 Git 作为应用的版本管理系统, 使用 GitHub 我们的在线仓库。

    在刚刚创建好的应用目录下执行:

    $ echo "# 12factor-app" >> README.md
    $ git init
    $ git add .
    $ git commit -m "first commit"
    $ git remote add origin git@github.com:bingohuang/12factor-app.git
    $ git push -u origin master
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3.1.2. 依赖

    Factor 解说:

    12-Factor 规则下的应用程序不会隐式依赖系统级的类库。

    意思就是说: 通过依赖清单声明所有依赖项, 通过依赖隔离工具确保程序不会调用系统中存在但清单中未声明的依赖项。并统一应用到生产和开发环境。

    云平台根据这些声明管理依赖, 确保云应用所需的库和服务。

    Factor 实践:

    package.json 就是我们的依赖清单, 所有应用程序的依赖都声明在此。

    {
    "name": "12factor-app",
    "private": true,
    "version": "0.0.0",
    "description": "a Sails application",
    "keywords": [],
    "dependencies": {
     "ejs": "2.3.4",
     "grunt": "1.0.1",
     "grunt-contrib-clean": "1.0.0",
     "grunt-contrib-coffee": "1.0.0",
     "grunt-contrib-concat": "1.0.1",
     "grunt-contrib-copy": "1.0.0",
     "grunt-contrib-cssmin": "1.0.1",
     "grunt-contrib-jst": "1.0.0",
     "grunt-contrib-less": "1.3.0",
     "grunt-contrib-uglify": "1.0.1",
     "grunt-contrib-watch": "1.0.0",
     "grunt-sails-linker": "~0.10.1",
     "grunt-sync": "0.5.2",
     "include-all": "^1.0.0",
     "rc": "1.0.1",
     "sails": "~0.12.11",
     "sails-disk": "~0.10.9"
    },
    "scripts": {
     "debug": "node debug app.js",
     "start": "node app.js"
    },
    "main": "app.js",
    "repository": {
     "type": "git",
     "url": "git://github.com/bingo/12factor-app.git"
    },
    "author": "bingo",
    "license": ""
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    接下来我们加入 mongodb 的库依赖(后续会用到), 只需要执行:

    npm install sails-mongo --save
    
    • 1

    同时 package.json 中会有相应的变更

    {
      ...
      "dependencies": {
        ...
        "sails-mongo": "^0.12.2"  // 最新加入的依赖
      }
      ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    应用程序需要用到的依赖库都安装在 node_modules 文件夹下, 该文件夹就是作为应用的依赖隔离, 并且和系统的库是隔离的。

    3.1.3. 配置

    Factor 解说:

    12-Factor 推荐将应用的配置存储于环境变量中, 保证配置排除在代码之外, 有如下好处:

    • 环境变量是一种清楚、容易理解和标准化的配置方法;
    • 环境变量可以非常方便地在不同的部署间做修改, 却不动一行代码;
    • 与配置文件不同, 不小心把它们签入代码库的概率微乎其微;
    • 与一些传统的解决配置问题的机制 (比如 Java 的属性配置文件) 相比, 环境变量与语言和系统无关;
    • 存储在环境变量中的另一个好处是, 方便和 Docker 配合使用。

    一个技巧: 判断一个应用是否正确地将配置排除在代码之外, 一个简单的方法是看该应用可以立刻开源, 而不用担心会暴露任何敏感的信息。

    Factor 实践:

    在应用程序的 config/connections.js 文件中, 我们使用 MONGO_URL 这个环境变量来定义 mongo 的连接方式。

    module.exports.connections = {
     mongo: {
        adapter: 'sails-mongo',
        url: process.env.MONGO_URL
     }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在文件中, 指定 module 所使用的连接。

    module.exports.models = {
     connection: mongo,
     migrate: 'safe'
    };
    
    • 1
    • 2
    • 3
    • 4

    如果你在本地起了一个 mongodb 测试服务, 就可以用这个命令验证应用是否正常配置。

    MONGO_URL=mongodb://localhost:27017/12factor-app npm start
    
    • 1

    3.1.4. 后端服务

    Factor 解说:

    12-Factor 应用不会区别对待本地或第三方服务, 统一把后端服务 (backing services)当作附加资源或者说是远程的资源。

    所谓后端服务是指程序运行所需要的通过网络调用的各种服务, 如数据库 (MySQL), 消息 / 队列系统(RabbitMQ), SMTP 邮件发送服务( Postfix), 以及缓存系统(Memcached) 等。

    除了本地服务之外, 应用程序有可能使用了第三方发布和管理的服务, 如 SMTP(例如 Postmark), 数据收集服务, 数据存储服务 (如 Amazon S3), 以及使用 API 访问的服务(例如 Twitter) 等。

    对应用程序而言, 本地或第三方服务都是附加资源, 通过一个 url 或是其他存储在 配置中的设置来获取数据, 仅需修改配置中的资源地址即可。

    应用也因此具有容错和复原能力, 因为它一方面要求编码时就要考虑资源不可用的情况, 另外一方面也增强微服务方法的好处。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1gI7XJEl-1669260326345)(https://hjs-1251193177.cos.ap-shanghai.myqcloud.com/cloud/cloud-native-12-factor-apply-5.webp)]

    Factor 实践:

    对我们的应用程序来说, 用到的后端服务就是 MongoDB 数据库。我们正是通过 MONGO_URL 来传递 MongoDB 的资源地址, 从而实现了后端服务和应用程序的解耦。

    如果当前这个 MongoDB 实例出问题了, 我们可以通过设置 MONGO_URL 这个环境变量, 很方便的切换一个新的实例。

    3.1.5. 构建, 发布, 运行

    Factor 解说:

    12-Factor 应用严格区分构建, 发布, 运行这三个步骤。

    Cloud Native 应用的构建流程把大部分发布配置挪到开发阶段, 包括实际的代码构建和运行应用所需的生产环境配置。

    举例来说, 直接修改处于运行状态的代码是非常不可取的做法, 因为这些修改很难再同步回构建步骤。

    发布的版本就像一本只能追加的账本, 一旦发布就不可修改, 任何的变动都应该产生一个新的发布版本。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lGxmObIE-1669260326345)(https://hjs-1251193177.cos.ap-shanghai.myqcloud.com/cloud/cloud-native-12-factor-apply-6.webp)]

    Factor 实践:

    针对这条原则, 强烈推荐使用 Docker 及其组件(Compose), 它的核心理念正是: Build, Ship and Run, 将适合在整个构建、发布和运行流程, 我们也将从这三个方面进行讲解。

    1. 构建

    书写构建脚本: Dockerfile

    FROM hub.c.163.com/library/node:5.12.0
    MAINTAINER bingohuang 
    # 拷贝依赖清单
    COPY package.json /tmp/package.json
    # 安装依赖包
    RUN cd /tmp && npm install --registry=https://registry.npm.taobao.org
    # 将依赖包拷贝到应用程序目录下
    RUN mkdir /app && cp -a /tmp/node_modules /app/
    # 更改工作目录
    WORKDIR /app
    # 拷贝应用程序代码
    COPY . /app
    # 设置应用启动端口
    ENV PORT 1337
    # 暴露应用程序端口
    EXPOSE 1337
    # 启动应用
    CMD ["npm","start"]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    Docker 构建

    $ docker build -t 12factor-app:v1.0 .
    
    • 1

    Docker 镜像推送: 可以将其 push 到指定的镜像仓库, 比如网易云基础服务 (蜂巢) 的镜像仓库中。

    $ docker push hub.c.163.com/bingohuang/12factor-app:1.0
    
    • 1
    1. 发布:

    书写发布脚本: docker-compose.yml

    version: '2'
    services:
    mongo:
     image: hub.c.163.com/library/mongo:3.2
     volumes:
       - mongo-data:/data/db
     ports:
       - "27017:27017"
    app:
     image: hub.c.163.com/bingohuang/12factor-app:1.0
     ports:
       - "1337:1337"
     links:
       - mongo
     depends_on:
       - mongo
     environment:
       - MONGO_URL=mongodb://mongo/12factor-app
    volumes:
     mongo-data:
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    以上在构建好的镜像基础上, 定义了一个发布过程, 并将配置 (MONGO_URL) 通过环境变量注入进去。

    MONGO_URL=mongodb://mongo/12factor-app
    
    • 1
    1. 运行:

    可以通过 Docker Compose 在本地运行, 也可以通过云平台来在线编排(网易云基础服务即将支持服务编排功能)。

    docker-compose up -d
    
    • 1

    继而查看日志

    docker-compose logs -f
    
    • 1

    注: 为了方便不熟悉 docker 和 docker-compose 命令的人快速运行程序和本地调试, 我在源代码中还提供了 docker.sh 脚本, 方便构建、发布和运行应用(源码请看后续资料链接)。

    3.1.6. 进程

    Factor 解说:

    12-Factor 应用的进程必须无状态且无共享。

    任何需要持久化的数据都要存储在后端服务内, 比如数据库。Session 中的数据应该保存在诸如 Memcached 或 Redis 这样的带有过期时间的缓存中。

    运行环境中, 应用程序通常是以一个和多个进程 运行的。

    最简单的场景中, 代码是一个独立的脚本, 运行环境是开发人员自己的笔记本电脑, 进程由一条命令行(例如 python my_script.py)。另外一个极端情况是, 复杂的应用可能会使用很多 进程类型 , 也就是零个或多个进程实例。

    这么做是为了保证 Cloud Native 基础设施的速度和效率。

    Factor 实践:

    虽然这是一个简单的 demo 应用, 但查看 docker 容器中的运行进程, 发现也有 4 个进程在运行, 其中 npm 也就是我们的启动进程, node app.js 是实际运行应用的进程。

    $ docker  exec 12-factor ps aux
    USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
    root         1  0.2  2.0 1076204 42024 ?       Ssl  18:22   0:00 npm
    root        17  0.0  0.0   4340   724 ?        S    18:22   0:00 sh -c node app.js
    root        18  0.9  4.5 1253808 93808 ?       Sl   18:22   0:01 node app.js
    root        27  1.1  3.7 962884 77076 ?        Sl   18:22   0:01 grunt
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里, 我们的应用进程是无状态的, 持久化的数据都存储在了后端服务 MongoDB 当中。

    3.1.7. 端口绑定

    Factor 解说:

    12-Factor 应用通过自我加载而不依赖于任何网络服务器就可以创建一个面向网络的服务。

    意思就是说: Web 应用通过端口绑定 (Port binding)来提供服务 , 并监听发送至该端口的请求。Cloud Native 应用的服务接口优先选择 HTTP API 作为通用的集成框架。

    还要指出的是, 端口绑定这种方式也意味着一个应用可以成为另外一个应用的 后端服务 , 调用方将服务方提供的相应 URL 当作资源存入 配置 以备将来调用。

    Factor 实践:

    docker-compose 文件为我们很好的定义了端口绑定。

    ports: “1337:1337” // 应用容器暴露 1337 端口在容器中, 宿主机将其映射到 1337 端口。

    需要注意的是, 如果在一个宿主机中部署多个应用实例, 就不能将一个宿主机端口映射到多个容器端口(端口冲突), 解决方法是在这之上加一个负载均衡, 负载宿主机的不同端口服务所对应的不同容器。

    3.1.8. 并发

    Factor 解说:

    12-factor 应用通过进程模型进行扩展, 把进程看作是一等公民, 并且具备具备的无共享, 水平分区的特性。

    这意味着依赖底层平台就能实现横向扩展, 不需要技术难度高的多线程编码。

    举例来说, HTTP 请求可以交给 web 进程来处理, 而常驻的后台工作则交由 worker 进程负责, 定时任务交由 clock 来处理, 这样扩展每一类的进程就非常方便, 如下图所示:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nOuKkrzv-1669260326346)(https://hjs-1251193177.cos.ap-shanghai.myqcloud.com/cloud/cloud-native-12-factor-apply-7.webp)]

    Factor 实践:

    如第六个原则所描述, 我们的应用拥有多个进程, 最主要的是 Node.js 的 http server 进程, 进程都是无状态并无共享, 所以我们可以非常容易的水平扩展应用。

    3.1.9. 易处理

    Factor 解说:

    12-Factor 应用的进程是易处理 (disposable) 的, 意思是说任何进程都可以快速启动和优雅终止, 这样做的好处是:

    • 这有利于快速、弹性的伸缩应用, 迅速部署变化的代码或配置, 提高健壮性;
    • 进程应当追求最小启动时间, 可以提供了更敏捷的发布以及扩展过程;
    • 进程一旦接收终止信号(SIGTERM) 就会优雅的终止。

    如下图所示, 就是一个优雅的应用启动和终止流程。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BKrzhYj5-1669260326346)(https://hjs-1251193177.cos.ap-shanghai.myqcloud.com/cloud/cloud-native-12-factor-apply-8.webp)]

    Factor 实践:

    Docker 先天的轻量级和隔离性, 就非常适合来做快速启动和优雅终止, Docker 非常适合实践这条原则, 在我们的应用中, 就加入了 Docker 和 Compose 实践。

    针对线上环境, 推荐构建在容器云平台之上(比如网易云基础服务平台), 可以更优雅的处理进程的启动和停止。

    3.1.10. 环境等价

    Factor 解说:

    12-Factor 应用想要做到持续部署就必须缩小本地与线上差异, 包括以下三种差异:

    • 缩小时间差异: 开发人员可以几小时, 甚至几分钟就部署代码;
    • 缩小人员差异: 开发人员不只要编写代码, 更应该密切参与部署过程以及代码在线上的表现;
    • 缩小工具差异: 尽量保证开发环境以及线上环境的一致性。

    12-Factor 应用的开发人员应该反对在不同环境间使用不同的后端服务。

    这是因为, 不同的后端服务意味着会突然出现的不兼容, 从而导致测试、预发布都正常的代码在线上出现问题。

    Factor 实践:

    我们的应用程序中, 使用了 docker-compose 作为我们的发布脚本, 它使得应用既可以在本地运行, 也可以在任何支持 Docker 的云平台上运行, 应用无需变化, 只需修改配置文件, 很好的解除了不同环境的差异化。

    从以往经验来看, 传统应用和 12-Factor 应用会存在如下差异:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HNGucNXx-1669260326346)(https://hjs-1251193177.cos.ap-shanghai.myqcloud.com/cloud/cloud-native-12-factor-apply-9.webp)]

    3.1.11. 日志

    Factor 解说:

    12-factor 应用本身从不考虑存储自己的输出流。相反, 每一个运行的进程都会直接的标准输出 (stdout) 事件流。

    当日志是由云平台而不是应用包含的库处理时, 日志处理机制必须保持简单。

    Factor 实践:

    许多服务都能提供日志集中管理, 比如 ELK、Splunk、Logentries, 而且大多数都能方便的和 Docker 集成在一起。

    这里以 Logentries 为例来为应用集成日志服务, 需要在 docker-compose 文件中加入 log 服务, 如下:

    log:
     command: '-t a80277ea-4233-7785203ae328'
     image: 'logentries/docker-logentries’
     restart: always
     tags:
       - development
     volumes:
       - '/var/run/docker.sock:/var/run/docker.sock'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    一个典型的 Logentries 面板界面如下:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oejEu08m-1669260326346)(https://hjs-1251193177.cos.ap-shanghai.myqcloud.com/cloud/cloud-native-12-factor-apply-10.webp)]

    3.1.12. 管理进程

    Factor 解说:

    开发人员经常希望执行一些管理或维护应用的一次性任务, 例如:

    • 运行数据移植
    • 运行一个控制台也被称为 REPL shell, 来执行一些代码或是针对线上数据库做一些检查。
    • 运行一些提交到代码仓库的一次性脚本。

    12-Factor 应用中, 一次性管理进程应该和正常的常驻进程 (应用进程) 使用同样的环境, 并且使用相同的代码和配置, 基于某个发布版本运行, 随着其他的应用程序一起发布。

    在 Cloud Native 中, 管理任务也是一个进程, 而不是特别的工具; 同样重要的是, 管理任务的进程不应使用秘密的 API 或者内部机制。

    Factor 实践:

    我们可以在 docker-compose 文件中定义管理服务, 和程序一起执行。

    我们可以通过通过 docker exec 命令执行一些管理任务, 比如:

    docker exec -ti ADMIN_CONTAINER_ID bash
    
    • 1

    如果多个容器处在相同的网络下, 可以通过一个容器来管理其它容器。

    4. 总结

    至此, 12-Factor 一一实践完毕, 从中可以看出, 12-Factor 并非相互独立, 而是一个整体, 有的涉及代码和框架 (Node 和 Rails), 有的涉及工具(Docker 和 Compose) 有的涉及架构和平台。在云原生时代, 12-Factor 仍然具有强大的生命力, 每一条原则都是应用开发的珠玑, 而且每一个原则也不是一成不变的, 随着新的理念出现, 原有的 Factor 会得到延伸和发展, 也会出现新的原则, 有兴趣的同学, 不妨读一读《Beyond the 12 Factor App》这本书, 还会有更大的收获。最后, 希望此次分享对你理解云原生应用、实践 12-Factor 有所帮助。

    5. 参考链接

    • 源代码:

    https://github.com/bingohuang/12factor-app

    • 文章地址:

    http://talks.bingohuang.com/2017/cloud-native-12factor.article

    • 12-Factor 在线书籍:

    http://12.bingohuang.com/zh_cn/index.html

    • 12-Factor 书籍开源:

    https://github.com/bingohuang/12factor-gitbook

    一、什么是 KVM

    KVM,Kernel-based Virtual Machine,最初是由以色列的公司 Qumranet 开发的。KVM 在 2007 年 2 月被正式合并到 Linux 2.6.20 核心中,成为内核源代码的一部分。2008 年 9 月 4 日,RedHat 公司收购了 Qumranet,开始在 RHEL 中用 KVM 替换 Xen,第一个包含 KVM 的版本是 RHEL 5.4。从 RHEL 6 开始,KVM 成为默认的虚拟化引擎。KVM 必须在具备 Intel VT 或 AMD-V 功能的 X86 平台上运行。

    KVM 是开源软件,目前由 Red Hat 等厂商开发,对 CentOS/Fedora/RHEL 等 Red Hat 系发行版支持极佳。

    From: https://en.wikipedia.org/wiki/Kernel-based_Virtual_Machine

    Developer(s): Open Virtualization Alliance (OVA)
    Repository: git://git.kernel.org/pub/scm/virt/kvm/kvm.git
    Written in: C
    Operating system: Unix-like
    
    • 1
    • 2
    • 3
    • 4

    使用 KVM 技术更不需要在虚拟化方面支付额外的费用,可以进一步节省企业的 IT 成本。免费并不意味着 KVM 没有技术支持。在 KVM 的开源社区,数量巨大的 KVM 技术支持者都可以提供 KVM 技术支持。另外,如果需要商业级支持,也可以购买红帽公司的服务。

    二、KVM 架构

    KVM 包含一个为处理器提供底层虚拟化、可加载的核心模块 kvm.kokvm-intel.kokvm-amd.ko),使用 QEMU(QEMU-KVM)作为虚拟机上层控制工具。KVM 不需要改变 Linux 或 Windows 系统就能运行。

    KVM 还需要一个经过修改的 QEMU 软件(qemu-kvm),作为虚拟机上层控制和界面。

    KVM 还能够使用 KSM (Kernel Same-page Merging) 技术帮助宿主服务器节约内存。

    KVM 背靠 Linux 这棵大树,和 Linux 系统紧密结合,在 Linux 上的新技术都可以马上应用到 KVM 上。围绕 KVM 的是一个开源的生态链,从底层的 Linux 系统,到中间层的 Libvirt 管理工具,到云管理平台 OpenStack,莫不是如此。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U6ZytaUt-1669260326346)(http://p7tng301o.bkt.clouddn.com/Cloud-kvm-host-architecture.jpg)]

    因为对进程的管理非常麻烦,RedHat发布了一个开源项目Libvirt。Libvirt有API,也有一套命令行工具,可以完成对虚拟机的管理,大多数的管理平台都是通过Libvirt来完成对KVM虚拟机的管理的,比如OpenStack、CloudStack、OpenNebula等。

    2.1 KVM 与 QEMU

    QEMU 是一个开源项目,实际就是一台硬件模拟器,可以模拟许多硬件,包括X86架构处理器、AMD64 架构处理器等等。

    QEMU 可以在其他平台上运行 Linux 的程序,可以存储及还原虚拟机运行状态,还可以虚拟多种设备,包括网卡、多 CPU、IDE 设备、软驱、显卡、声卡、多种并口设备、多种串口设备、多种 USB 设备、PC 喇叭、PS/2 键盘鼠标(默认)和 USB 键盘鼠标、蓝牙设备。

    QEMU 的好处是因为是纯软件模拟,所以可以在支持的平台模拟支持的设备,QEMU 的缺点是因为是纯软件模拟,所有非常慢。QEMU-KVM 的分支版本发布了 3 个正式的版本 1.1、1.2、1.3,随后和 QEMU 的主版本合并,也就是说现在的 QEMU 版本默认支持 KVM,QEMU 和 KVM 已经紧密地结合起来了。

    KVM 的最后一个自己的版本是 KVM 83,随后和内核版本一起发布,和内核版本号保持一致,所以要使用 KVM 的最新版本,就要使用最新的内核。

    QEMU 全称 Quick Emulator。是独立虚拟软件,能独立运行虚拟机(根本不需要 kvm)。kqemu 是该软件的加速软件。kvm 并不需要 qemu 进行虚拟处理,只是需要它的上层管理界面进行虚拟机控制。虚拟机依旧是由 kvm 驱动。所以,大家不要把概念弄错了,盲目的安装qemu 和 kqemu。

    2.2 Libvirt 与 KVM

    Libvirt 是一套开源的虚拟化的管理工具,主要由 3 部分组成:

    • 一套 API 的 lib 库,支持主流的编程语言,包括 C、Python、Ruby 等。
    • Libvirtd 服务。
    • 命令行工具 virsh。

    Libvirt 的设计目标是通过相同的方式管理不同的虚拟化引擎,比如 KVM、Xen、HyperV、VMware ESX 等。但是目前实际上多数场景使用 Libvirt 的是 KVM,而 Xen、HyperV、VMware ESX 都有各自的管理工具。

    Libvirt 可以实现对虚拟机的管理,比如虚拟机的创建、启动、关闭、暂停、恢复、迁移、销毁,以及虚拟机网卡、硬盘、CPU、内存等多种设备的热添加。

    Libvirt 还支持远程的宿主机管理,只要在宿主机上启动 Libvirtd 服务并做好配置,就可以通过 Libvirt 进行虚拟机的配置。通道可以是以下方式:

    • SSH。
    • TCP。
    • 基于 TCP 的 TLS。

    Libvirt 将虚拟机的管理分为以下几个方面:

    • 第一,存储池资源管理,支持 本地文件系统目录、裸设备、lvm、nfs、iscsi 等方式。在虚拟机磁盘格式上支持 qcow2、vmdk、raw 等格式。
    • 第二,网络资源管理,支持 Linux 桥、VLAN、多网卡绑定管理,比较新的版本还支持 Open vSwitch。Libvirt 还支持 nat 和路由方式的网络,Libvirt 可以通过防火墙让虚拟机通过宿主机建立网络通道,和外部的网络进行通信。

    2.3 KVM 与 VBOX 的区别

    VBOX 是由 qemu 改写而成,包含大量 qemu 代码。

    • 可以使用于 “不支持” 虚拟化技术的 CPU。
    • 值得说的一点:VBOX 在图形方面比较好,能进行 2D 3D 加速。
    • 但 CPU 控制不理想(估计是因为图形支持的缘故)。
    • 操作上有独立的图形界面,易于上手。

    KVM 是 Linux 内核包含的东西,使用 qemu 作为上层管理(命令行)。

    • 要求 CPU 必须支持虚拟化。
    • 性能:作为服务器很好,可是图形能力十分的差。即使放电影,图像也是像刷油漆一样,一层一层的。
    • CPU 使用率控制很好。
    • 控制上比较简洁,功能比较丰富:比如使用 “无敌功能” 所有更改指向内存,你的镜像永远保持干净。 “母镜像” 功能让你拥有 n 个独立快照点。还有很多参数。另外,KVM 作为内核级的虚拟机,刚开始发展关注的公司比较多——但是还没有达到商业应用的水平。

    总体而言:在支持虚拟化的情况下,VBOX 和 KVM 的性能差不多,主要是面向对象不同: KVM 适用于服务器, VBOX 适用于桌面应用。

    2.3 与 VBOX 的冲突(不用 VBOX 的 ose 版本,用官方下载的4.X可独立正常使用)

    当你安装了 VBOX 然后又安装 kvm,那么当你再次打开开 VBOX 的时候,vmbox 就会报错。

    Step 1. 查看相关正在运行的 mod

    lsmod | grep kvm

    Step 2. 停止模块运行

    • 如果你的 CPU 是 AMD: sudo rmmod kvm-amd
    • 如果是 Intel: sudo rmmod kvm

    Step 3. 卸载模块

    • 如果你的 CPU 是 AMD: sudo modprobe -r kvm-amd
    • 如果你的 CPU 是 Intel:sudo modprobe -r kvm-intel

    sudo modprobe -r kvm

    Step 4. 完全卸载

    sudo aptitude purge kvm qemu-kvm
    sudo apt-get remove kvm qemu-kvm
    
    • 1
    • 2

    三、虚拟化技术

    虚拟化技术的演变过程可以分为软件模拟、虚拟化层翻译、容器虚拟化三个大的阶段。

    虚拟化层翻译可以分为:

    • 软件捕获翻译,即软件全虚拟化。
    • 改造虚拟机系统内核加虚拟化层翻译,即半虚拟化。
    • 硬件支持的虚拟化层翻译,即硬件支持的全虚拟化。

    四、KVM 运行要求

    • CPU 支持 VT

    首先知道一下 CPU 虚拟化的特征 flags:

    • 半虚拟化为 pae
    • 全虚拟化为 vmx(Intel)、svm(AMD)

    判断当前系统是否 支持/开启 虚拟化 VT 命令如下,如果有打印输出则说明 VT 已开启:

    命令 1: grep

    cat /proc/cpuinfo | grep -E '(vmx|svm)'

    命令 2: egrep

    cat /proc/cpuinfo | egrep '(vmx|svm)'

    备注:grep -Eegrep 一样,表示使用 extended regular expression(扩展正则表达式)语法规范。

    如果打印结果是 pae,那说明开启的是半虚拟化模式,需要将其改成全虚拟化模式。

    还有一条命令:$ lscpu | grep Virtualization

    • 64 位的 Linux
    • Linux kernel >= 2.6.20
  • 相关阅读:
    希望你永远不懂JSON和全局异常处理
    详解如何在数仓中搭建细粒度容灾应用
    什么是仲裁器(Arbiter)?
    VmWare16+Ubuntu安装教程
    FBA海运到美国费用一般包含哪些?
    c++【3】 常量、指针、指针变量、变量指针
    一文搞懂MySQL索引(清晰明了)
    shell脚本将执行结果重定向到指定路径指定文件对应的变量
    Go命令行参数 os和flag
    对象 和 json 互转 四种方式 json-lib、Gson、FastJson、Jackson
  • 原文地址:https://blog.csdn.net/wan212000/article/details/128014930